zoukankan      html  css  js  c++  java
  • Spring 框架基础(05):事务管理机制,和实现方式

    本文源码:GitHub·点这里 || GitEE·点这里

    一、Spring事务管理

    1、基础描述

    Spring事务管理的本质就是封装了数据库对事务支持的操作,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交和回滚。

    Connection conn = DriverManager.getConnection();
    try {  
        // 自动提交设置为false
        conn.setAutoCommit(false);
        // 执行增删改查操作
        // 当操作成功后手动提交
        conn.commit();  
    } catch (Exception e) {
        // 出现异常,回滚所有操作
        conn.rollback();
        e.printStackTrace();
    } finally {
        conn.colse();
    }
    

    2、事务常见概念

    • 事务

    事务是指作为单个逻辑工作单元执行的一系列操作(SQL语句)。这些操作要么全部成功,要么全部不成功。

    • 特性:ACID
    原子性(Atomicity):事务中的多个操作要么都成功要么都失败
    一致性(consistency):事务的执行的前后数据的完整性保持一致
    隔离性(isolation):事务执行的过程中,不应该受到其他事务的干扰
    持久性(durability):事务一旦结束,数据就持久到数据库
    
    • 隔离问题

    脏读:一个事务读到另一个事务没有提交的数据

    不可重复读:一个事务前后多次读取相同数据,数据内容不一致,update场景问题

    虚读(幻读):一个事务前后多次读取,数据总量不一致,insert场景问题

    • 隔离级别

    read uncommitted:

    事务可以读取另一个未提交事务的数据。

    read committed

    事务要等另一个事务提交后才能读取数据,解决脏读。

    repeatable read

    在开始读取数据时,事务开启,不再允许修改操作,解决:脏读、不可重复读。

    serializable

    最高事务隔离级别,事务串行化顺序执行,解决脏读、不可重复读、幻读。但是效率低下,耗数据库性能。

    3、事务管理API描述

    • PlatformTransactionManager

    平台事务管理器,Spring管理事务,必须使用事务管理器进行事务配置时,核心方法:获取事务,提交事务,回滚事务。

    • TransactionDefinition

    该对象封装事务详情(事务定义、事务属性),例如:隔离级别、是否只读、超时时间 等。

    • TransactionStatus

    用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。Spring底层根据状态进行相应操作。

    4、事务案例SQL语句

    CREATE TABLE user_account(
      id INT PRIMARY KEY AUTO_INCREMENT,
      username VARCHAR(50),
      money INT
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;;
    INSERT INTO user_account(username,money) VALUES('jack','5000');
    INSERT INTO user_account(username,money) VALUES('tom','5000');
    SELECT * FROM user_account ;
    

    二、编程式事务管理

    1、核心配置文件

    <!-- 配置事物管理器 -->
    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 创建事物模板 -->
    <bean id="transactionTemplate"
          class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="txManager" />
    </bean>
    <!-- 配置转账接口 -->
    <bean id="userAccountService"
          class="com.spring.mvc.service.impl.UserAccountServiceImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate" />
        <property name="transactionTemplate" ref="transactionTemplate" />
    </bean>
    

    2、演示案例

    @Service
    public class UserAccountServiceImpl extends JdbcDaoSupport implements UserAccountService {
        // 注入事物模板
        private TransactionTemplate transactionTemplate ;
        public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
            this.transactionTemplate = transactionTemplate;
        }
        @Override
        public void remittance(String remitTer, String receiver, int money) {
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                public void doInTransactionWithoutResult(TransactionStatus arg0) {
                    outMoney(remitTer,money);
                    // System.out.println(1/0);
                    innerMoney(receiver,money);
                }
            });
        }
        private void outMoney (String remitTer, int money){
            String outSql = "update user_account set money = money - ? where username = ?";
            this.getJdbcTemplate().update(outSql, money ,remitTer);
        }
        private void innerMoney (String receiver, int money){
            String inSql = "update user_account set money = money + ? where username = ?";
            this.getJdbcTemplate().update(inSql, money,receiver);
        }
    }
    

    三、事务代理工厂

    1、核心配置

    <!-- 配置转账接口 -->
    <bean id="userAccountService01"
          class="com.spring.mvc.service.impl.UserAccountServiceImpl01">
        <property name="jdbcTemplate" ref="jdbcTemplate" />
    </bean>
    <!-- 配置事务代理工厂 -->
    <bean id="proxyAccountService"
          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="proxyInterfaces" value="com.spring.mvc.service.UserAccountService01" />
        <property name="target" ref="userAccountService01" />
        <property name="transactionManager" ref="txManager" />
        <property name="transactionAttributes">
            <props>
                <!-- 默认传播行为、隔离级别 -->
                <prop key="remittance">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop>
                <!-- 异常仍然提交事务
                <prop key="remittance">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.Exception</prop>
                -->
            </props>
        </property>
    </bean>
    

    配置说明:

    • proxyInterfaces 代理接口
    • target 代理目标类
    • transactionManager 事务管理器
    • transactionAttributes 事务属性(事务详情)
    • prop.key 指定方法使用当前事务配置

    事务行为:

    • PROPAGATION 传播行为
    • ISOLATION 隔离级别
    • readOnly 是否只读
    • -Exception 异常回滚
    • +Exception 异常提交

    2、演示案例

    @Service
    public class UserAccountServiceImpl01 extends JdbcDaoSupport implements UserAccountService01 {
        @Override
        public void remittance(String remitTer, String receiver, int money) {
            outMoney(remitTer,money);
            System.out.println(1/0);
            innerMoney(receiver,money);
        }
        private void outMoney (String remitTer, int money){
            String outSql = "update user_account set money = money - ? where username = ?";
            this.getJdbcTemplate().update(outSql, money ,remitTer);
        }
        private void innerMoney (String receiver, int money){
            String inSql = "update user_account set money = money + ? where username = ?";
            this.getJdbcTemplate().update(inSql, money,receiver);
        }
    }
    

    3、测试代码

    public class Tx_Test_02 {
        @Test
        public void test1 (){
            String xmlPath = "spring-jdbc-tx-02.xml";
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
            UserAccountService01 accountService = (UserAccountService01)
                                        context.getBean("proxyAccountService");
            accountService.remittance("jack","tom",1000);
        }
    }
    

    四、XML配置事务

    首先配置事务管理器,然后配置事务属性,最后基于AOP编程配置事务切入点。

    1、核心配置

    <!-- 配置事物管理器 -->
    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 配置转账接口 -->
    <bean id="userAccountService01"
          class="com.spring.mvc.service.impl.UserAccountServiceImpl01">
        <property name="jdbcTemplate" ref="jdbcTemplate" />
    </bean>
    <!-- 配置事物详情 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="remittance"
                       propagation="REQUIRED"
                       isolation="DEFAULT"/>
        </tx:attributes>
    </tx:advice>
    <!-- 事务切入点,基于AOP编程 -->
    <aop:config>
        <aop:advisor
             advice-ref="txAdvice"
             pointcut="execution(* com.spring.mvc.service.UserAccountService01.*(..))"/>
    </aop:config>
    

    五、基于事务注解

    配置事务管理器,并启动事务注解的支持,在目标类或目标方法添加@Transactional核心注解即可。

    1、核心配置

    <!-- 配置事物管理器 -->
    <bean id="txManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <!-- 支持事务注解 -->
    <tx:annotation-driven transaction-manager="txManager" />
    

    2、注解用法

    注解写在接口方法上,或者接口实现的方法上效果一样。

    public interface UserAccountService02 {
        @Transactional(rollbackFor = Exception.class)
        void remittance(String remitTer, String receiver, int money) ;
    }
    

    六、源代码地址

    GitHub·地址
    https://github.com/cicadasmile/spring-mvc-parent
    GitEE·地址
    https://gitee.com/cicadasmile/spring-mvc-parent
    

  • 相关阅读:
    调用匿名函数的骚操作
    angular,vue,react的父子通信
    JavaScript高阶函数的应用
    图解javascript中this指向
    前端开发必备
    MEAN-全栈javascript开发框架
    MongoDB初识
    ES6新特性概览
    为什么是link-visited-hover-active
    CSS布局 — 圣杯布局与双飞翼布局
  • 原文地址:https://www.cnblogs.com/cicada-smile/p/11985733.html
Copyright © 2011-2022 走看看