• 【Spring 从0开始】JdbcTemplate 数据库事务管理


    现在有个账户表,里面存着用户金额。

    如果要真正地做好转账的操作,就要用到事务,否则当出现异常后会出现数据不一致等问题。

    try {
      // 第一步 开启事务
      // 第二步 进行业务操作
      // 第三步 没有发生异常,提交事务
    } catch(){
      // 第四步 发生异常,事务回滚
    }
    

    一、spring 中的事务管理

    通常,把事务加在 service 层(业务逻辑层)。

    而在 spring 中管理事务可以有 2 种方式实现:

    • 编程式管理:就像上面伪代码那样,这种使用起来不方便。
    • 声明式管理:通过配置方式实现,推荐使用。其中,可以基于 XML 方式进行配置,也可以基于注解,显然后者更方便。

    在 spring 中进行声明式事务管理,底层使用的是 AOP 原理。

    二、spring 事务管理 API

    spring 提供了一个接口 PlatformTransactionManager ,代表事务管理器。此接口针对不同的框架提供不同的实现类。

    利用idea工具,展开结构,使用 jdbcTemplate 用到的是 DataSourceTransactionManager 。

    三、使用事务管理

    1. 配置文件

    创建事务管理器。

        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--注入数据源-->
            <property name="dataSource" ref="dataSource"></property>
        </bean>
    

    开启事务注解,使用名称空间 tx

        <!--开启事务注释-->
        <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
    

    2. 类上添加事务注解

    注解 @Transactional 可以加在 service 类上,也可以加到方法上:

    • 加到类上,表示类下所有的方法都添加了事务。
    • 加到方法,表示只有该方法添加事务。
    @Service
    @Transactional
    public class UserService {
    
        @Autowired
        private UserDao userDao;
    
        // 转账方法
        public void accountMoney() {
            // 大周 少 100
            userDao.reduceMoney();
    
            // 模拟异常
            int i = 1/0;
    
            // 小毛 加 100
            userDao.addMoney();
        }
    }
    

    接口实现类 UserDaoImpl 。

    @Repository
    public class UserDaoImpl implements UserDao {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public void addMoney() {
            String sql = "update t_account set money=money+? where username=?";
            jdbcTemplate.update(sql, 100, "小毛");
        }
    
        @Override
        public void reduceMoney() {
            String sql = "update t_account set money=money-? where username=?";
            jdbcTemplate.update(sql, 100, "大周");
        }
    }
    

    到测试类里执行一下:

    public class TestTrans {
        @Test
        public void testJdbc() {
    
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("bean1.xml");
    
            UserService userService = context.getBean("userService", UserService.class);
    
            userService.accountMoney();
        }
    }
    

    注意,上面的 service 里我手动添加了异常,所以执行后,事务应该是要回滚操作,2 个人的金额仍然各是 1000 。

    八月 07, 2021 10:39:57 上午 com.alibaba.druid.pool.DruidDataSource info
    信息: {dataSource-1} inited
    
    java.lang.ArithmeticException: / by zero
    

    刷新数据表。

    现在我去掉 service 类中的异常 int i = 1/0;,重新执行测试方法:

    八月 07, 2021 10:47:01 上午 com.alibaba.druid.pool.DruidDataSource info
    信息: {dataSource-1} inited
    
    Process finished with exit code 0
    

    刷新数据表。

    结果正确。

    --不要用肉体的勤奋,去掩盖思考的懒惰--
  • 相关阅读:
    php中的闭包和匿名函数
    php魔术常量
    SQL查询:存在一个表而不在另一个表中的数据
    php发送http请求的几种方式
    php高级工程师面试题
    php中include、require、include_once、require_once的区别
    gitignore规则基础
    Google地图数据算法
    【营销】包子和星座
    【GPS】 数据围栏
  • 原文地址:https://www.cnblogs.com/pingguo-softwaretesting/p/15111349.html
Copyright © 2020-2023  润新知