zoukankan      html  css  js  c++  java
  • Spring 框架的事务管理

    1. Spring 框架的事务管理相关的类和API

    • PlateformTransactionManager 接口: 平台事务管理器(真正管理事务的类);
    • TransactionDefinition 接口: 事务定义信息(事务的隔离级别,传播行为,超时,只读等);
    • TransactionStatus 接口: 事务的状态;
    • 平台事务管理器真正管理事务对象,根据事务定义信息(TransactionDefinition)进行事务管理,在管理事务
      中产生的一些状态记录到TransactionStatus中;

    1.1 PlateformTransactionManager 接口中实现类和常用的方法

    1. 接口的实现类
      • 如果使用 Spring 框架的JDBC模板或者MyBatis框架,需要选择DataSourceTransactionManager实现类;
      • 如果使用的是 Hibernate 框架,需要选择HibernateTransactionManager实现类;
    2. 该接口的常用方法
      • void commit(TransactionStatus status)
      • TransactionStatus getTransaction(TransactionDefinition definition)
      • void rollback(TransactionStatus status)

    1.2 TransactionDefinition

    1. 事务隔离级别的常量

      • static int ISOLATION_DEFAULT: 采用数据库的默认隔离级别;
      • static int ISOLATION_READ_UNCOMMITTED
      • static int ISOLATION_READ_COMMITTED
      • static int ISOLATION_REPEATABLE_READ
      • static int ISOLATION_SERIALIZABLE
    2. 事务的传播行为常量(一般使用默认值)

      • 事务的传播行为:解决的是业务层之间的方法调用!
      • 保证 A,B 在同一个事务中:
        • PROPAGATION_REQUIRED(默认值): A中有事务,使用A中的事务;如果没有,B会开启一个新的事务,
          将A包含进来(保证A,B在同一个事务中);
        • PROPAGATION_SUPPORTS: A中有事务,使用A中的事务;如果A中没有事务,那么B也不使用事务;
        • PROPAGATION_MANDATORY: A中有事务,使用A中的事务; 如果A中没有事务,抛出异常;
      • 保证 A,B 没有在同一个事务中:
        • PROPAGATION_REQUIRES_NEW: A中有事务,将A中的事务挂起,B创建一个新的事务,
          (保证A,B不在同一个事务中);
        • PROPAGATION_NOT_SUPPORTED: A中有事务,将A中的事务挂起;
        • PROPAGATION_NEVER: A中有事务,抛出异常;
      • PROPAGATION_NESTED: 嵌套事务,当 A 执行之后,就会在这个位置设置一个保存点,如果B没有问题,
        执行通过;如果B出现异常,根据需求回滚(可以回滚到保存点或最初始的状态);

    2. 搭建事务管理转账案例的环境

    2.1 导入 jar 包

    • Spring 框架的基本开发包(6个);
    • Spring 的传统AOP的开发包
      • spring-aop-4.3.10.RELEASE
      • org.aopalliance-1.10.0 (在 Spring 依赖包中)
    • aspectJ 的开发包
      • org.aspectj.weave-1.6.8.RELEASE.jar (在 Spring 依赖包中)
      • spring-aspects-4.3.10.RELEASE.jar
    • JDBC 模板所需 jar 包
      • mysql-connector-java.jar: MySql 驱动包;
      • Spring-jdbc.jar;
      • Spring-tx.jar: Spring 事务包;
    • c3p0 的 jar 包: com.mchange.v2.c3p0-0.9.1.2.jar

    2.2 创建对应的包结构和类

    • com.itheima.demo
      • AccountService
      • AccountServiceImpl
      • AccountDao
      • AccountDaoImpl
    // AccountDao.java
        public class AccountDao {
            // 扣钱
            public void outMoney(String out, double money);
    
            // 加钱
            public void inMoney(String in, double money);
        }
    
    // AccountService.java
        public class AccountService{
            public void pay(String out,String in, double money);
        }
    
    // AccountDaoImpl.java
        // 第一种方式, 使用 jdbc 模板类
        public class AccountDaoImpl implements AccountDao{
            // 使用 jdbc 模板操作数据库
            // 在配置文件中注入 jdbcTemplate 对象
            private JdbcTemplate jdbcTemplate;
            public void setJdbcTemplate(JdbcTemplate jdbcTemplate){
                this.jdbcTemplate = jdbcTemplate;
            }
    
            // 扣钱
            public void outMoney(String out, double money){
                jdbcTemplate.update(sql,args);
            }
    
            // 加钱
            public void inMoney(String out, double money){
                jdbcTemplate.update(sql,args);
            }
        }
    
        // 第二种方式, 继承 JdbcDaoSupport类, 该类中包含 jdbcTemplate,并且提供了 set方法
        //           applicationContext.xml 中仍需要注入 jdbcTemplate 对象
    
        public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
    
            // 扣钱
            public void outMoney(String out, double money){
                this.getJdbcTemplate().update(sql,args);
            }
    
            // 加钱
            public void inMoney(String in, double money){
                this.getJdbcTemplate().update(sql,args);
            }
        }
    
        // 第三种方式: applicationContext.xml 中无需注入 jdtcTemplate 对象
        //           只需要注入连接池对象,
        // JdbcDaoSupport 类内部,在 jdbcTemplate 对象为 null 时, 根据连接池创建 jdbcTemplate 对象
    
        public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
    
            // 扣钱
            public void outMoney(String out, double money){
                this.getJdbcTemplate().update("UPDATE t_account SET"
                                    +"money = money - ? WHERE name = ?",money,out);
            }
    
            // 加钱
            public void inMoney(String in, double money){
                this.getJdbcTemplate().update("UPDATE t_account SET"
                                    +"money = money - ? WHERE name = ?",money,in);
            }
        }
    
    
    // AccountServiceImpl.java
        public class AccountServiceImpl implements AccountService{
    
            private AccountDao accountDao;
            public void setAccountDao(AccountDao accountDao){
                this.accountDao = accountDao;
            }
    
            // 实现转账功能
            public void pay(String out, String in, double money){
                accountDao.outMoney(out,money);
                accountDao.inMoney(in,money);
            }
        }
    
    
    // 测试类
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration("classpath:applicationContext.xml")
        public class Demo{
    
            @Resource(name="accountService")
            private AccountServiceImpl accountService;
    
            @Test
            public void fun(){
                // 测试支付方法
                accountService.pay("张三","李四",100);
            }
        }
    

    2.3 applicationContext.xml

    <!-- 管理c3p0 连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb1"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>
    
    <!-- 管理JDBC的模板类 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" value="dataSource"/>
    </bean>
    
    <!-- 配置业务层和持久层 -->
    <bean id="accountService" class="com.itheima.demo.AccountServiceImpl">
        <property name="accountDao" value="accountDao"/>
    </bean>
    
    <!-- 第一种和第二种方式, 需要注入 jdbcTemplate 对象 -->
    <bean id="accountDao" class="com.itheima.demo.AccountDaoImpl">
        <property name="jdbcTemplate" value="jdbcTemplate"/>
    </bean>
    
    <!-- 第三种方式, 只需要注入连接池 -->
    <bean id="accountDao" class="com.itheima.demo.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    

    2.4 Spring 框架事务管理的分类

    1. Spring 的编程式事务管理(不推荐使用)
      • 通过手动编写代码的方式完成事务的管理;
    2. Spring 的声明式事务管理(底层采用AOP的技术)
      • 通过一段配置的方式完成事务的管理;
    2.4.1 编程式的事务管理
    1. 手动编程的方式来管理事务,需要使用 TransactonTemplate模板类;
    // 具体步骤
    // 1. 配置一个事务管理器
    //    Spring 框架使用 PlatFormTransactionManager 接口来管理事务,需要使用到它的实现类
    <bean id="transactionManager"
                class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        // 底层操作事务的是 connection, 该对象存放在连接池
        // 事务管理器管理事务,需要从连接池中获取 connection 对象
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    // 2. 配置事务管理的模板
    <bean id="transactionTemplate"
                    class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
     </bean>
    
    // 3. 在需要进行事务管理的类中,注入事务管理的模板
    //     备注: 事务需要在业务层开启
        <bean id="accountService" class="com.itheima.demo.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"/>
            <property name="transactionTemplate" ref="transactionTemplate"/>
        </bean>
    
    // 4. 在业务层使用模板管理事务
    public void AccountServiceImpl implements AccountService{
    
        private AccountDao accountDao;
        public void setAccountDao(AccountDao accountDao){
            this.accountDao = accountDao;
        }
    
        // 注入事务模板对象
        private TransactionTemplate transactionTemplate;
        public void setTransactionTemplate(TransactionTemplate transactionTemplate){
            this.transactionTemplate = transactionTemplate;
        }
    
        // 实现转账功能
        public void pay(final String out, final String in, final double money){
            transactionTemplate.execute(new TransactionCallbackWithoutResult(){
                protected void doInTransactionWithoutResult(TransactionStatus status){
                    // 扣钱
                    accountDao.outMoney(out,money);
    
                    // 异常
                    int a = 10 / 0;
    
                    // 加钱
                    accountDao.inMoney(in,money);
                }
            });
        }
    }
    
    2.4.2 声明式事务管理
    1. 声明式事务管理:即通过配置文件来完成事务管理(AOP 思想)
      • 基于AspectJ的XML方式;(重点掌握)
      • 基于AspectJ的注解方式;(重点掌握)
    基于AspectJ的XML方式
    // applicationContext.xml
    // 1. 配置一个事务管理器
    //    Spring 框架使用 PlatFormTransactionManager 接口来管理事务,需要使用到它的实现类
    <bean id="transactionManager"
                class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        // 底层操作事务的是 connection, 该对象存放在连接池
        // 事务管理器管理事务,需要从连接池中获取 connection 对象
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    // 2. 配置事务增强(通知)
    <tx:advice id="myAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--
              可以配置多个 method;
              name       : 绑定事务的方法名,可以使用通配符;
              propagation: 传播行为;
              isolation  : 隔离级别;
              read-only  : 缓存是否只读;
              timeout    : 超时信息;
              rollback-for: 发生哪些异常信息回滚;
              no-rollback-for: 发生哪些异常,不回滚;
              -->
    
              <tx:method name="pay" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    // 3. 配置 AOP 切面
    //    备注: 如果是自定义的切面,使用<aop:aspect>标签, 如果是系统自带的,使用<aop:advisor>标签
    <aop:config>
        <aop:advisor advice-ref="myAdvice"
                    pointcut="execution(public * com.itheima.demo.AccountServiceImpl.pay(..))"/>
    </aop:config>
    
    // 4. 持久层配置
        <bean id="accountService" class="com.itheima.demo.AccountServiceImpl">
            <property name="accountDao" ref="accountDao"/>
        </bean>
    
    基于AspectJ的注解方式(重点掌握,这是最简单的方式)
    // 1. 配置事务管理器
    <bean id="transactionManager"
                class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    // 2. 开启注解事务
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    // 3. 在业务层上添加一个注解: @Transactional
    // AccountServiceImpl.java
    
        // 如果在这个类上添加注解, 类中的所有方法全部都有事务
        @Transactional
        public class AccountServiceImpl implements AccountService{
    
            private AccountDao accountDao;
            public void setAccountDao(AccountDao accountDao){
                this.accountDao = accountDao;
            }
    
            // 实现转账功能
            // 如果在方法上添加,只有该方法有事务
            @Transactional
            public void pay(String out, String in, double money){
                accountDao.outMoney(out,money);
                accountDao.inMoney(in,money);
            }
        }
    

    参考资料

  • 相关阅读:
    不可小视视图对效率的影响力
    Maximum Margin Planning
    PhysicsBased Boiling Simulation

    Learning Behavior Styles with Inverse Reinforcement Learning
    Simulating Biped Behaviors from Human Motion Data
    Nearoptimal Character Animation with Continuous Control
    Apprenticeship Learning via Inverse Reinforcement Learning
    回报函数学习的学徒学习综述
    Enabling Realtime Physics Simulation in Future Interactive Entertainment
  • 原文地址:https://www.cnblogs.com/linkworld/p/7724625.html
Copyright © 2011-2022 走看看