Spring:事务(tx)

1. 简介

2b734fb75f5c45db9eb1a7aa9a185320.png

spring对jdbc进行封装,简化对数据库的操作

 2. HelloWorld

1. 搭建模块

2.加入依赖

<dependencies>
    <!--spring jdbc  Spring 持久化层支持jar包-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>6.0.2</version>
    </dependency>
    <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
    <!-- 数据源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.15</version>
    </dependency>
</dependencies>

 3.创建jdbc.properties文件

jdbc.user=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/study?characterEncoding=utf8&useSSL=false
jdbc.driver=com.mysql.cj.jdbc.Driver

4.配置spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">
    <context:component-scan base-package="com.itgyl.tx"></context:component-scan>

    <!-- 导入外部属性文件 -->
    <context:property-placeholder location="classpath:jdbc.properties" />

    <!-- 配置数据源 -->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 配置 JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!-- 装配数据源 -->
        <property name="dataSource" ref="druidDataSource"/>
    </bean>

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"></property>
    </bean>

    <!--
        开启事务的注解驱动
        通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务
    -->
    <!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

实现CURD操作

 查

/***
 * queryForObject方法会将查询的单个对象进行返回
 * query方法会将查询的结果存入集合在将集合进行返回
 * 三个参数:
 * 参数一:执行的sql语句
 * 参数二:通过该方法可以将实例化对象创建出来,并将数据库中查询的数据存入该实例化对象中
 * 参数三以及之后的参数(非必要,如有占位符即需要带上):都是查询语句的条件判断参数
 */
@Component
@SpringJUnitConfig(locations = "classpath:beans.xml")
public class JdbcTemplateTest {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    
    @Test
    public void testQuery() {
        
        //查询返回单个对象
        String sql = "select * from t_emp where id = ?";
        Emp emp = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(Emp.class), 3);
        System.out.println(emp);

    }
}
//查询返回单个值
        String sql = "select count(*) from t_emp";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        System.out.println("总数为:" + count);
//查询返回所有数据
        String sql = "select * from t_emp";
        List<Emp> list = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Emp.class));
        for (Emp emp : list) {
            System.out.println(emp);
        }

//添加功能
        String sql = "insert into t_emp (name, age, sex) value (?, ?, ?)";
        int result = jdbcTemplate.update(sql, "东方不败", 19, "未知");

 改

 String sql =" update t_emp set name =  ? where name = ?";
        int result = jdbcTemplate.update(sql, "牛逼", "zhangsan");

String sql = "delete from t_emp where name = ?";
        int result = jdbcTemplate.update(sql, "牛逼");

 3. 事务

事务基本概念

 事务详情跳转链接

声明式事务

既然事务控制的代码有规律可循,代码的结构基本是确定的,所以框架就可以将固定模式的代码抽取出来,进行相关的封装。

封装起来后,我们只需要在配置文件中进行简单的配置即可完成操作。

* 好处1:提高开发效率
* 好处2:消除了冗余的代码
* 好处3:框架会综合考虑相关领域中在实际开发环境下有可能遇到的各种问题,进行了健壮性、性能等各个方面的优化

基于注解的声明式事务

完成简单的图书出售事务

配置tx命名空间

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd">

 开启事务注解驱动

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druidDataSource"></property>
</bean>

<!--
    开启事务的注解驱动
    通过注解@Transactional所标识的方法或标识的类中所有的方法,都会被事务管理器管理事务
-->
<!-- transaction-manager属性的默认值是transactionManager,如果事务管理器bean的id正好就是这个默认值,则可以省略这个属性 -->
<tx:annotation-driven transaction-manager="transactionManager" />

@Transaction注解

/***
 * 注解@Transactional及添加事务功能
 * 在类上面添加该注解则会影响类的所有方法,即所有方法都添加事务的功能
 * 在方法上面添加该注解则单影响该方法,即当前有注解的方法添加事务功能
 *      readOnly即设置只读功能,无法做修改删除插入操作
 *      timeout设置超时功能,当超过指定时机还未执行完毕则自动进行事务回滚
 *      noRollbackFor即设置不回滚操作,当满足里面的条件即使是报错也不回滚
 *      isolation即设置事务的隔离级别
 *      propagation设置事务的传播行为
 */
@Repository
public class BookDaoImp implements BookDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    //@Transactional(readOnly = true)
    //@Transactional(timeout = 3)
    //@Transactional(noRollbackFor = ArithmeticException.class)
    //@Transactional(isolation = Isolation.DEFAULT)
    //@Transactional(propagation = Propagation.REQUIRES_NEW)
    @Transactional
    @Override
    public boolean buyBook(Integer bookId, Integer userId) {
        //完成一个事务

        //TODO 模拟超时场景
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //1.查询库存
        String sqlBookSelect = "select price from t_book where book_id = ?";
        Integer price = jdbcTemplate.queryForObject(sqlBookSelect, Integer.class, bookId);

        //2.用户购买库存减少
        String sqlBook = "update t_book set stock = stock - 1 where book_id = ?";
        int rows = jdbcTemplate.update(sqlBook, userId);

        //3.用户扣款
        String sqlUser = "update t_user set balance = balance - 50 where  user_id = ?";
        int rows2 = jdbcTemplate.update(sqlUser, userId);

        //int j = 1 / 0;
        return rows2 == rows;
    }
}
@Service
public class BookServiceImp implements BookService{
    @Autowired
    private BookDao bookDao;

    //@Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public boolean buyBook(Integer bookId, Integer userId) {
        return bookDao.buyBook(bookId, userId);
    }
}

 

只读

对一个查询操作来说,如果我们把它设置成只读,就能够明确告诉数据库,这个操作不涉及写操作。这样数据库就能够针对查询操作来进行优化。

超时

事务在执行过程中,有可能因为遇到某些问题,导致程序卡住,从而长时间占用数据库资源。而长时间占用资源,大概率是因为程序运行出现了问题(可能是Java程序或MySQL数据库或网络连接等等)。此时这个很可能出问题的程序应该被回滚,撤销它已做的操作,事务结束,把资源让出来,让其他正常程序可以执行。

概括来说就是一句话:超时回滚,释放资源。

 回滚策略

声明式事务默认只针对运行时异常回滚,编译时异常不回滚。

可以通过@Transactional中相关属性设置回滚策略

* rollbackFor属性:需要设置一个Class类型的对象
  
* rollbackForClassName属性:需要设置一个字符串类型的全类名
  
* noRollbackFor属性:需要设置一个Class类型的对象
  
* rollbackFor属性:需要设置一个字符串类型的全类名

 隔离级别

数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

隔离级别一共有四种:

* 读未提交:READ UNCOMMITTED允许Transaction01读取Transaction02未提交的修改。
  
* 读已提交:READ COMMITTED、要求Transaction01只能读取Transaction02已提交的修改。
  
* 可重复读:REPEATABLE READ确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其它事务对这个字段进行更新。
  
* 串行化:SERIALIZABLE确保Transaction01可以多次从一个表中读取到相同的行,在Transaction01执行期间,禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题,但性能十分低下。

传播行为

* REQUIRED:支持当前事务,如果不存在就新建一个(默认)**【没有就新建,有就加入】**
* SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行**【有就加入,没有就不管了】**
* MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常**【有就加入,没有就抛异常】**
* REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起**【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起】**
* NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务**【不支持事务,存在就挂起】**
* NEVER:以非事务方式运行,如果有事务存在,抛出异常**【不支持事务,存在就抛异常】**
* NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。**【有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。没有事务就和REQUIRED一样。】 

 全注解配置事务

//基于全注解管理事务
@Configuration
@ComponentScan("com.itgyl") //开启组件扫描
@EnableTransactionManagement //开启事务管理等同于<tx:annotation-driven transaction-manager="transactionManager" />
public class SpringConfig {

    //设置连接数据库
    @Bean
    public DataSource getDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/study?characterEncoding=utf8&useSSL=false");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    //
    @Bean(name = "jdbcTemplate")
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

基于XML的声明式事务

<aop:config>
    <!-- 配置事务通知和切入点表达式 -->
    <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.atguigu.spring.tx.xml.service.impl.*.*(..))"></aop:advisor>
</aop:config>
<!-- tx:advice标签:配置事务通知 -->
<!-- id属性:给事务通知标签设置唯一标识,便于引用 -->
<!-- transaction-manager属性:关联事务管理器 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- tx:method标签:配置具体的事务方法 -->
        <!-- name属性:指定方法名,可以使用星号代表多个字符 -->
        <tx:method name="get*" read-only="true"/>
        <tx:method name="query*" read-only="true"/>
        <tx:method name="find*" read-only="true"/>

        <!-- read-only属性:设置只读属性 -->
        <!-- rollback-for属性:设置回滚的异常 -->
        <!-- no-rollback-for属性:设置不回滚的异常 -->
        <!-- isolation属性:设置事务的隔离级别 -->
        <!-- timeout属性:设置事务的超时属性 -->
        <!-- propagation属性:设置事务的传播行为 -->
        <tx:method name="save*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
        <tx:method name="update*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
        <tx:method name="delete*" read-only="false" rollback-for="java.lang.Exception" propagation="REQUIRES_NEW"/>
    </tx:attributes>
</tx:advice>

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/656373.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity Dotween 定位点的制作

目录 前言 一、动画预览 二、动画拆分 三、素材准备 四、曲线 OutCirc详解 五、速度分类详解 六、代码 七、组件和设置 八、作者的话 前言 我答应我的粉丝接下来更新Dotween系列&#xff0c;但是我一直没想好&#xff0c;从哪里开始讲。 Dotween的安装我就跳过了&…

一款220V降12V恒压芯片电路原理图WT5114

一款220V降12V恒压芯片电路原理图WT5114&#xff0c;电路图简示如下&#xff1a; 一款220V降12V恒压芯片线路图WT5114 WT5114是一款高性能、高精度、低成本的PWM电源开关&#xff0c;适用于非隔离降压和反激式应用。它集成了专用电流模式PWM控制器&#xff08;采用SOP8封装的高…

埃及媒体分发投放-新闻媒体通稿发布

埃及商业新闻 大舍传媒近日宣布将在埃及商业新闻领域展开新的媒体分发投放。作为埃及最具影响力的商业新闻平台之一&#xff0c;埃及商业新闻将为大舍传媒提供广阔的市场和受众群体。这一合作意味着大舍传媒将有机会通过埃及商业新闻的平台向埃及的商业精英和投资者传递最新的…

ACM Proceedings Template 使用方法

模板导入 打开ACM Primary Article Template官网&#xff0c;可以看到自带overleaf模板&#xff0c;接下来我们使用overleaf来自动导入模板。 选择你需要的ACM Conference or Journals模板&#xff0c;然后Open as Template 栏目说明 接下来依次解释一下左边栏目的作用 …

mail发送调用接口如何与三方服务无缝对接?

mail发送调用接口的性能怎么样&#xff1f;调用邮件接口的技巧&#xff1f; 为了提高效率和自动化水平&#xff0c;企业通常会选择使用mail发送调用接口。然而&#xff0c;仅仅使用这些接口还不够&#xff0c;如何与各种第三方服务无缝对接同样至关重要。AokSend将探讨如何有效…

再创佳绩丨达梦数据库一体机荣获2024数字中国创新大赛·信创赛道总决赛一等奖

5月24日&#xff0c;第七届数字中国建设峰会在福州盛大开幕&#xff0c;峰会内容安排包含开幕式、主论坛、分论坛、数字中国创新大赛、现场体验区及成果发布和专业工作会议等。武汉达梦数据库股份有限公司(以下简称达梦数据)受邀参加并在展、会、赛等多个环节深度参与。达梦全栈…

mac M3芯片 goland 2022.1 断点调试失败(frames are not available)问题,亲测有效

遇到如上问题&#xff0c;解法 步骤1&#xff1a;下载dlv文件 执行 go install github.com/go-delve/delve/cmd/dlvlatest 然后在 $GOPATH/bin里发现多了一个dlv文件 (找不到gopath? 执行 go env 可以看到) 步骤2&#xff1a;配置dlv 将这个dlv文件移到 /Applications/G…

vue中在mounted使用$refs获取不到DOM元素

vue中在mounted使用$refs获取不到DOM元素 前言解决方案1、通过使用$nextTick来获取2、updated中获取 前言 在使用ref的时候&#xff0c;在mounted中通过$ref获取节点是获取不到报undefined this.$refs.xx 为 undefined 解决方案 在mounted钩子中加载回来的数据不会在这个阶段更…

webpack5_相关知识点

webpack是一个现代JavaScript应用程序的静态模块打包器(module bundler) &#xff0c;是前端资源模块化管理和打包工具&#xff0c; 它可以将许多松散耦合的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分离&#xff0c;等到实际需要时…

Python 读取.shp文件并生成图幅编号

代码适用于需要处理和分析地理空间数据的场景&#xff0c;如城市规划、环境监测或自然资源管理&#xff0c;其中它可以帮助用户读取特定区域的Shapefile文件&#xff0c;确定其地理边界&#xff0c;并基于这些边界计算出按照经纬度5度间隔的图幅编号&#xff0c;进而用于地图制…

Hive环境搭建

1 安装Hive 下载文件 # wget -P /opt/ https://mirrors.huaweicloud.com/apache/hive/hive-2.3.8/apache-hive-2.3.8-bin.tar.gz 解压缩 # tar -zxvf /opt/apache-hive-2.3.8-bin.tar.gz -C /opt/ 修改hive文件夹名字 # mv /opt/apache-hive-2.3.8-bin /opt/hive 配置环境变量 …

力扣HOT100 - 138. 随机链表的复制

解题思路&#xff1a; class Solution {public Node copyRandomList(Node head) {if(headnull) return null;Node p head;//第一步&#xff0c;在每个原节点后面创建一个新节点//1->1->2->2->3->3while(p!null) {Node newNode new Node(p.val);newNode.next …

场景文本检测识别学习 day10(MMdetection)

配置文件(config) 由于在大型项目中&#xff0c;一种模型需要分&#xff1a;tiny、small、big等很多种&#xff0c;而它们的区别主要在网络结构&#xff0c;数据的加载&#xff0c;训练策略等&#xff0c;且差别很多都很小&#xff0c;所以如果每个模型都手动从头写一份&#…

文生图模型演进:AE、VAE、VQ-VAE、VQ-GAN、DALL-E 等 8 模型

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 合集&#x…

【强训笔记】day24

NO.1 思路&#xff1a;递归。 代码实现&#xff1a; class Solution { public:bool IsBalanced_Solution(TreeNode* pRoot) {return dfs(pRoot)!-1;}int dfs(TreeNode* root){if(rootnullptr) return 0;int leftdfs(root->left);if(left-1) return -1;int rightdfs(root-…

如何使用甘特图来做任务管理?zz-plan甘特图的实践指南

在项目管理和任务调度中&#xff0c;甘特图是一种非常实用的工具&#xff0c;它可以帮助团队成员清晰地规划、执行和跟踪项目进度。然而&#xff0c;如何有效利用甘特图进行任务管理&#xff0c;对于许多团队来说仍然是一个挑战。本文将结合 zz-plan https://zz-plan.com/ 甘特…

jmeter服务器性能监控分析工具ServerAgent教程

ServerAgent介绍&#xff1a;支持监控CPU&#xff0c;memory&#xff0c;磁盘&#xff0c;网络等&#xff0c;和JMeter集成&#xff0c;在JMeter的图形界面中&#xff0c;可以实时看到监控的数据&#xff0c;但是&#xff0c;它只能监控硬件资源使用情况。 不能监控应用服务 S…

天若OCR 识别 (本地文字识别转换工具)

前言 天若OCR文字识别本地版是一款在天若OCR文字识别工具v5.0免费开源版的基础上采用Chinese-lite框架和Paddle-ocr框架本地化识别接口编译而成,无需联网也无需申请密钥&#xff0c;纯本地运算&#xff0c;识别准确度和速度很快&#xff0c;操作和天若OCR免费版一样&#xff0…

解决:error: failed to push some refs to ‘https://gitee.com/***/***.git‘(高效快速)

解决方案&#xff1a; git pull --rebase origin master 具体原因&#xff1a; 主要原因是gitee(github)中的README.md文件不在本地代码目录中 要执行git pull --rebase origin master命令将README.md拉到本地 然后就可以执行git push啦 写在最后&#xff1a; 要是问题得到…

实验四 网络的路径与连通性

文章目录 4.1 网络的路径与连通性第1关&#xff1a;路径与初始距离矩阵的构建第2关&#xff1a;由网络邻接矩阵求初始距离矩阵方法第3关&#xff1a;网络中任意两点的最短路径求解 4.2 网络连通性第1关&#xff1a;网络节点间的可达性判断第2关&#xff1a;邻接矩阵转换可达矩阵…