• 5、声明式事务


    5.1、JdbcTemplate

    Spring中提供了对JDBC功能的封装。

    1、使用配置

    导入依赖:

    <dependencies>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-contextartifactId>
            <version>5.3.1version>
        dependency>
        
        
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-ormartifactId>
            <version>5.3.1version>
        dependency>
        
        <dependency>
            <groupId>org.springframeworkgroupId>
            <artifactId>spring-testartifactId>
            <version>5.3.1version>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.16version>
        dependency>
        
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>druidartifactId>
            <version>1.0.31version>
        dependency>
    dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    创建jdbc.properties文件

    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
    jdbc.username=root
    jdbc.password=123456
    
    • 1
    • 2
    • 3
    • 4

    配置spring核心文件

    <context:property-placeholder location="jdbc.properties">context:property-placeholder>
    
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}">property>
        <property name="url" value="${jdbc.url}">property>
        <property name="username" value="${jdbc.username}">property>
        <property name="password" value="${jdbc.password}">property>
    bean>
    
    
    <bean class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource">property>
    bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    测试:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:spring-jdbctemplate.xml")
    public class TestJdbcTemplate {
        @Autowired
        public JdbcTemplate jdbcTemplate;
    
        @Test
        public void JdbcTemplateTest() {
    
            String sql = "insert into t_user values(null,'王五',28,'男')";
            int update = jdbcTemplate.update(sql);
            System.out.println(update);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    jdbcTemplate具备增删改查功能的实现,除了查询功能其他都是调用update函数,利用重写实现不同需求的更新数据功能。

    5.2、声明式事务注解实现

    利用注解实现声明式事务比较简单,只需要在spring核心配置文件中配置两个标签,然后就可以使用注解进行标识事务了。

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource">property>
    bean>
    
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    配置完成之后在要实现事务功能的方法或者类上面加@Transactional注解即可。(若在类上面加代表所有方法均实现事务)一般加在Service层。

    @Service
    public class bookServiceImpl implements bookService {
        
        @Autowired
        public bookDao bookdao;
    
        public bookDao getBookdao() {
            return bookdao;
        }
    
        @Transactional
        public void buybook(Integer uid, Integer bid) {
            //要么都执行成功,要么都失败。
            Integer price = bookdao.queryprice(bid);
            bookdao.bookaccount(bid);
            bookdao.buy(uid,price);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    5.3、@Transactional的属性

    1、readOnly——只读

    @Transactional(readOnly = true)
    public void buybook(Integer uid, Integer bid) {
        /**
         * 设置事务只读属性则无法对数据库中的数据进行修改
         * 只能执行查询操作。
         */
        Integer price = bookdao.queryprice(bid);//查询书籍的价格,可以执行
        bookdao.bookaccount(bid);//修改书籍的数量,不能执行
        bookdao.buy(uid,price);//修改用户的余额,不能执行
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2、timeout——超时

    @Transactional(timeout = 3)
    public void buybook(Integer uid, Integer bid) {
        /**
             * 超时属性,防止事务因为异常卡死而占用资源不释放。
             * 当业务超时未完成,将会抛出异常TransactionTimedOutException
             */
        try {
            TimeUnit.SECONDS.sleep(5);
            Integer price = bookdao.queryprice(bid);
            bookdao.bookaccount(bid);
            bookdao.buy(uid,price);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3、回滚策略

    回滚策略有四个属性可以选择设置,具体来说分两类就是遇到什么异常回滚,遇到什么异常不会滚。

    rollbackFor = TransactionTimedOutException.class	//遇到TransactionTimedOutException异常回滚
    rollbackForClassName ="TransactionTimedOutException"//遇到TransactionTimedOutException异常回滚
        
    noRollbackFor =TransactionTimedOutException.class	//遇到TransactionTimedOutException异常不回滚
    noRollbackForClassName ="TransactionTimedOutException"//遇到TransactionTimedOutException异常不回滚
    
    • 1
    • 2
    • 3
    • 4
    • 5
    @Transactional(noRollbackFor =TransactionTimedOutException.class )
    public void buybook(Integer uid, Integer bid) {
        try {
            TimeUnit.SECONDS.sleep(5);
            Integer price = bookdao.queryprice(bid);
            bookdao.bookaccount(bid);
            bookdao.buy(uid,price);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4、隔离级别

    @Transactional(isolation = Isolation.DEFAULT)//使用数据库默认的隔离级别
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)//读未提交
    @Transactional(isolation = Isolation.READ_COMMITTED)//读已提交
    @Transactional(isolation = Isolation.REPEATABLE_READ)//可重复读
    @Transactional(isolation = Isolation.SERIALIZABLE)//串行化
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5、传播行为

    传播行为可以理解为:事务之中还有事务的情况下,如果出错是全部回滚还是部分回滚。

    比如买一本书是事务,将买多本书的操作封装在一个大事务中,如果第一本书成功购买(对于买一本书的事务已经提交了),第二本出错,那第一本买的书还要回滚吗?

    @Transactional(propagation = Propagation.REQUIRED),是默认情况,一旦出错全部回滚。

    @Transactional(propagation = Propagation.REQUIRES_NEW),一旦出错,将出错部分回滚。

    5.4、基于xml实现声明事务

    利用xml实现事务声明需要引入aspectj依赖:

    <dependency>
    <groupId>org.springframeworkgroupId>
    <artifactId>spring-aspectsartifactId>
    <version>5.3.1version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在spring核心配置文件配置事务声明,要将之前注解实现的以下配置删除

    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    • 1

    xml实现:

    	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource">property>
    bean>
    
    <aop:config>
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lu.Spring.service.*.*(..))">aop:advisor>
    aop:config>
    
    
    
    
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            
            
            <tx:method name="get*" read-only="true"/>
            <tx:method name="query*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
            
            
            
            
            
            
            <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
  • 相关阅读:
    Kettle入门教程
    Android Shimmer 布局微光(闪光,闪烁)效果
    由SoftRefLRUPolicyMSPerMB=0引起的频繁Full GC问题排查实战
    ​Python实战案例:航班票价预测这样做,效果真好啊
    LQ0150 回文日期【枚举】
    ​打造企业自己代码规范IDEA插件(上)
    【全民Python】PIP模块的安装,Pyinstaller模块安装,导出exe文件
    Oracle数据库系统安全管理(一)
    adb详细教程(一)-下载安装与环境变量配置
    JavaScript教程第四篇(作者原创)
  • 原文地址:https://blog.csdn.net/weixin_48312484/article/details/126381624