• 【Spring进阶系列丨最终篇】一文详解Spring中的事务控制


    0、说明

    本篇文章是【Spring进阶系列】专栏的最后一篇文章,至此,我们对Spring的学习就告一段落,接下来我会持续更新【Spring+SpringMVC+MyBatis整合】专栏,欢迎免费订阅!

    在这里插入图片描述

    一、Spring事务控制

    在这里插入图片描述

    • 事务需要放在业务层(service)
    • Spring的事务是基于AOP的
    • Spring的事务控制有两种:编程式事务【了解】和声明式事务【重点】
    • 声明式事务分为:基于xml配置和基于注解配置

    1、事务的环境准备

    1.1、导入依赖

    <dependencies>
    
            
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-contextartifactId>
                <version>5.2.1.RELEASEversion>
            dependency>
    
            
            <dependency>
                <groupId>org.aspectjgroupId>
                <artifactId>aspectjweaverartifactId>
                <version>1.9.4version>
            dependency>
    
            
            <dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-txartifactId>
                <version>5.2.1.RELEASEversion>
            dependency>
    
            
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <version>5.1.48version>
            dependency>
      	
      		
      		<dependency>
                <groupId>org.springframeworkgroupId>
                <artifactId>spring-jdbcartifactId>
                <version>5.2.1.RELEASEversion>
            dependency>
    
            
            <dependency>
                <groupId>junitgroupId>
                <artifactId>junitartifactId>
                <version>4.12version>
                <scope>testscope>
            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
    • 43
    • 44
    • 45

    1.2、添加AOP的约束

    <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:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/tx
            https://www.springframework.org/schema/tx/spring-tx.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.3、数据库准备

    create database bank;
    
    use bank;
    
    create table t_account(
    	id int primary key auto_increment,
      	name varchar(30),
      	balance int
    );
    
    insert into t_account(name,balance) values('段康家',2000);
    insert into t_account(name,balance) values('彭依凝',2000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    1.4、定义Bean

    // 定义实体
    public class Account {
        
        private Integer id;
        
        private String name;
        
        private Integer balance;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    // 业务接口
    public interface AccountService {
    
        public void transfer(Integer srcId,Integer destId,Integer money);
    
    }
    public class AccountServiceImpl implements AccountService {
    
        @Override
        public void transfer(Integer srcId, Integer destId, Integer money) {
            // 源账号
            Account srcAccount = accountDao.selectById(srcId);
            Integer srcBalance = srcAccount.getBalance();
            srcAccount.setBalance(srcBalance - money);
            
            accountDao.updateById(srcAccount);
            
            // 目标账号
            Account destAccount = accountDao.selectById(destId);
            Integer destBalance = destAccount.getBalance();
            destAccount.setBalance(destBalance + money);
            
            accountDao.updateById(destAccount);
        }
    }
    
    • 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
    // dao接口
    public interface AccountDao {
        
        public Account selectById(Integer id);
        
        public void updateById(Account account);
        
    }
    // dao实现类
    public class AccountDaoImpl implements AccountDao {
        @Override
        public Account selectById(Integer id) {
    
            String sql = "select id,name,balance from t_account where id = ?";
    
            List<Account> accounts = getJdbcTemplate().query(sql,new BeanPropertyRowMapper<Account>(Account.class),id);
    
            return accounts.get(0);
        }
    
        @Override
        public void updateById(Account account) {
    
            String sql = "update t_account set balance = ? where id = ?";
    
            getJdbcTemplate().update(sql,account.getBalance(),account.getId());
        }
    }
    
    • 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

    1.5、主配置文件定义

    <beans> 
    	
        <bean id="accountDao" class="cn.bdqn.dao.impl.AccountDaoImpl">
            <property name="dataSource" ref=""/>
        bean>
    
        
        <bean id="accountService" class="cn.bdqn.service.impl.AccountServiceImpl">
            <property name="accountDao" ref="accountDao">property>
        bean>
    
        
        <bean id="dataSource" 																class="org.springframework.jdbc.datasource.DriverManagerDataSource">
            <property name="driverClassName" value="com.mysql.jdbc.Driver">property>
            <property name="url" value="jdbc:mysql:///bank">property>
            <property name="username" value="root">property>
            <property name="password" value="root">property>
        bean>
    
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    1.6、测试

    @Test
    public void testTransfer() throws Exception{
    
            ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
            AccountService accountService = (AccountService) ac.getBean("accountService");
            accountService.transfer(1,2,100);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、基于xml的声明式事务

    2.1、配置事务管理器

    
    <bean id="transactionManager" 																																		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
    bean>
    
    • 1
    • 2
    • 3
    • 4

    2.2、配置事务的通知

     
    <tx:advice id="txAdvice" transaction-manager="transactionManager"/>
    
    • 1
    • 2

    2.3、配置AOP

    ​ 重点是配置切入点表达式及事务通知和切入点表达式的关系

    
    <aop:config>
            <aop:pointcut id="pt" expression="execution(* cn.bdqn.service.impl.*.*(..))"/>
            <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    aop:config>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.4、配置事务的属性

    ​ 注意:事务的属性在tx:advice标签的内部。

    isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。

    propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。

    read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。

    timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。

    rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。

    no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。

    
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
       
       <tx:attributes>
            <tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED" 
                       read-only="false"/>
       tx:attributes>
    tx:advice>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3、基于注解的声明式事务

    3.1、配置事务管理器

    
    <bean id="transactionManager" 																																				class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
    bean>
    
    • 1
    • 2
    • 3
    • 4

    3.2、在业务类添加注解

    @Service("accountService")
    public class AccountServiceImpl implements AccountService {
    
        @Autowired
        private AccountDao accountDao;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.3、配置JdbcTemplate模板

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    bean>
    
    • 1
    • 2
    • 3

    3.4、在Dao类添加注解

    @Repository("accountDao")
    public class AccountDaoImpl implements AccountDao {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.5、配置类中扫描包

    <context:component-scan base-package="cn.bdqn"/>
    
    • 1

    3.6、开启spring对注解事务的支持

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

    3.7、在业务层@Transactional注解

    @Service("accountService")
    @Transactional
    public class AccountServiceImpl implements AccountService {
    
        @Autowired
        private AccountDao accountDao;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.8、测试

    @Test
    public void testTransfer() throws Exception{
    
            ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
            AccountService accountService = (AccountService) ac.getBean("accountService");
            accountService.transfer(1,2,100);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

  • 相关阅读:
    cesium 设置默认视图
    线程安全与共享资源
    Guava缓存及Guava线程池
    第29章_瑞萨MCU零基础入门系列教程之改进型环形缓冲区
    Git仓库迁移实操(附批量迁移脚本)
    详解xacro语法并优化封装urdf
    发布文章到wordpress
    [附源码]计算机毕业设计基于springboot的文成考研培训管理系统
    万字长文Python面试题
    230. 二叉搜索树中第K小的元素 java解决
  • 原文地址:https://blog.csdn.net/m0_63947499/article/details/137752098