06-Spring03- transaction management

Knowledge today

1. Spring事务管理
2. 转账案例

Spring transaction management

1. 事务特性(ACID)
    1. 原子性:整体 【原子性是指事务包含的所有操作要么全部成功,要么全部失败】
    2. 一致性:数据 【一个事务执行之前和执行之后都必须处于一致性状态】
    3. 隔离性:并发 【对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。】
    4. 持久性:结果 【持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的】
* 隔离问题
    1. 脏读:一个事务读到另一个事务未提交的内容
    2. 不可重复读:一个事务读到另一个事务已提交的内容(update)这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。
    3. 虚读:一个事务读到另一个事务已提交的内容(delete,insert),这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。行数发生变化
    4. Serializable(可串行化)
    这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
* 隔离级别-解决问题
    1. read uncommitted,读未提交,存在三个问题
    2. read committed,读已提交,解决:脏读,存在两个问题
    3. repeatable read,可重复读,解决:脏读,和不可重复读,存在一个问题
    4. serializable,串行化。单事务。没有问题。一般不用,涉及IO操作,占用内存。
2. Spring提供的事务jar包
    * spring-tx jar包
    * jar 包包含三个顶级接口
        * PlatformTransactionManager:
        平台事务管理器,spring要管理事务,必须使用事务管理器,进行事务配置时,必须配置事务管理器
        * TransactionDefinition:
        事务详情(事务定义、事务属性),spring用于确定事务具体详情,
        * TransactionStatus:
        事务状态,spring用于记录当前事务运行状态。例如:是否有保存点,事务是否完成。
        spring底层根据状态进行相应操作。


3. 手动代理事务
    1. AccountServiceImpl写法注入TransactionTemplate
        * public class AccountServiceImpl implements AccountService {
    //spring底层使用 TransactionTemplate 事务模板进行操作。
    //注入已经 配置事务模板
    @Autowired
    TransactionTemplate transactionTemplate;
    //Spring注入AccountDao
    @Autowired
    AccountDao accountDao;
    public void tansfer(final String inner, final String outer, final Integer money) {
        //通过事务模板执行业务
        this.transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                //第一个进账
                accountDao.inner(inner,money);
                //第二个出账
               // int i=10/0;
                accountDao.out(outer,money);
            }
        });
    }
}
    2. xml中的配置
        * !--配置事务模板-->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager" ref="txManager"></property> </bean> <!--配置一个事务管理器--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager "> <property name="dataSource" ref="dataSource"></property> </bean> 4. 工厂bean生成代理事务:半自动 1. transactionAttributes:事务详情 prop.key :确定哪些方法使用当前事务配置 prop.text:用于配置事务详情 格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception 传播行为 隔离级别 是否只读 异常回滚 异常提交 2. AccountServiceImpl2直接普通的写法,不用引入TransactionTemplate事务模板 3. xml中的配置 * <!--配置accountService2,bean--> <bean id="accountService" class="com.rqy.service.impl.AccountServiceImpl2"/> <!--配置管理事务的代理工厂,代替上面的方法,到达半自动代理--> <bean id="proxyAccountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <!--配置接口--> <property name="proxyInterfaces" value="com.rqy.service.AccountService"/> <!--目标对象--> <property name="target" ref="accountService"/> <!--事务管理器--> <property name="transactionManager" ref="txManager"/> <!--事务详情--> <!-- transactionAttributes:事务详情 prop.key :确定哪些方法使用当前事务配置 prop.text:用于配置事务详情 格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception 传播行为 隔离级别 是否只读 异常回滚 异常提交 --> <property name="transactionAttributes"> <props> <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop> </props> </property> </bean> <!--配置一个事务管理器--> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager "> <property name="dataSource" ref="dataSource"></property> </bean>

The basic AOP transaction configuration (automatic)

1. xml配置(方法一)
    1. <!--配置一个事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager "> <property name="dataSource" ref="dataSource"></property> </bean> <!--配置事务属性,同时引入事务管理器--> <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <!--transfer。。。方法可读,--> <tx:method name="transfer*" propagation="REQUIRED" isolation="REPEATABLE_READ"/> <!-- 其它方法加可读写事务 --> <tx:method name="*"/> </tx:attributes> </tx:advice> <!-- 配置AOP:告诉spring框架哪些方法需要管理事务 --> <aop:config> <!-- 指定切入点 --> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.rqy.service.*.*(..))"/> </aop:config> 2. 注解事务(方法二) 1. 类里面加注解事务,就不用指明切入点了,默认在该类中加入该事务管理 2. xml需要声明自动开启事务注解驱动:<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven> 3. 注解直接加在方法上面 * @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT) * @Transactional:直接写这个就置默认隔离级别和传播行为

Pure javaConfig (full annotation configuration)

1. 类上面声明
    //声明我是配置文件
    @Configuration
    //声明扫描范围
    @ComponentScan(basePackages = "com.rqy") //声明自动开启事务注解 @EnableTransactionManagement //开启AspectJ注解 @EnableAspectJAutoProxy 2. 注解类 * //声明我是配置文件 @Configuration //声明扫描范围 @ComponentScan(basePackages = "com.rqy") //声明自动开启事务注解 @EnableTransactionManagement //开启AspectJ注解 @EnableAspectJAutoProxy public class SpringConfig { //配置数据源 @Bean public ComboPooledDataSource comboPooledDataSource() throws PropertyVetoException { ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver"); comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_day04?serverTimezone=UTC"); comboPooledDataSource.setUser("root"); comboPooledDataSource.setPassword("123456"); return comboPooledDataSource; } //配置JdbcTemplate @Bean public JdbcTemplate jdbcTemplate(ComboPooledDataSource dataSource){ JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(dataSource); return jdbcTemplate; } //配置事务管理器 @Bean public DataSourceTransactionManager dataSourceTransactionManager(ComboPooledDataSource dataSource){ DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); dataSourceTransactionManager.setDataSource(dataSource); return dataSourceTransactionManager; } } 3. 实例类 * @Component public class AccountDaoImpl2 implements AccountDao { @Autowired JdbcTemplate jdbcTemplate; public void out(String outer, Integer money) { String sql = "update account set money=money-? where username=?"; jdbcTemplate.update(sql, money, outer); } public void inner(String inner, Integer money) { String sql = "update account set money=money+? where username=?"; jdbcTemplate.update(sql, money, inner); } } * @Transactional @Component("accountService5") public class AccountServiceImpl5 implements AccountService { @Autowired AccountDao accountDao; public void transfer( String inner, String outer, Integer money) { //第一个进账 accountDao.inner(inner,money); //第二个出账 int i=10/0; accountDao.out(outer,money); } } 4. 测试类 * @RunWith(SpringJUnit4ClassRunner.class) //不加载配置文件的写法,如果有多个配置类,用,隔开。 @ContextConfiguration(classes = {SpringConfig.class}) public class ConfigTest { //去找代理对象 @Autowired @Qualifier("accountService5") AccountService accountService; @Test public void test(){ accountService.transfer("rose","jack",2000); } }

Propagation behavior

1. PROPAGATION_REQUIRED
required , 必须  【默认值】
    * 支持当前事务,A如果有事务,B将使用该事务。
如果A没有事务,B将创建一个新的事务。
2. PROPAGATION_SUPPORTS:supports     ·   
    * 支持当前事务,A如果有事务,B将使用该事务。 如果A没有事务,B将以非事务执行。 3. PROPAGATION_REQUIRES_NEW:如果A有事务,将A的事务挂起,B创 建一个新的事务如果A没有事务,B创建一个新的事务

Guess you like

Origin www.cnblogs.com/rqy0526/p/11277961.html