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

    1、概念

    • 事务: 逻辑上的一组操作,这组操作要么全部成功,要么全部失败。
    • 特性:
      • 原子性:不可分割
      • 统一性:数据完整性要一致
      • 隔离线:线程安全(多个用户并发访问数据)
      • 持久性:事务被提交后,数据的改变就是永久性的,及时数据库发生故障也不能对其有任何影响

    2、事务管理高层抽象接口

    • PlatformTransaction:事务管理器
      • spring为不同的持久化框架提供了不同的PlatformTtansactionManager接口实现:
    事务 说明
    org.springframework.jdbc.datasource.DataSourceTransactionManager 使用Spring JDBC或mybatis进行持久化数据时使用
    org.springframework.orm.hibernate3.HibernateTransactionManager 使用Hibernate3.0进行持久化数据时使用
    org.springframework.jpa.JpaTransactionManager 使用JPA进行持久化时使用
    org.springframework.jdo.JdpTransactionManager 当持久化机制是Jdo时使用
    org.springframework.transaction.jta.JtaTransactionManager 使用一个JTA实现来管理事务,在一个事务跨越多个资源时必须使用
    • TransactionDefinition: 事务定义信息(隔离、传播、超时、只读)
      • 事务隔离级别:
    隔离级别 说明
    DEFAULT 使用后端数据库默认的隔离级别(Spring中的选择项)
    READ_UNCOMMITED 允许 你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
    REPEATABLE_READ 对相同的字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍有可能发生
    SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的
      • 脏读:一个事务读取了另一个事务该写的但还未提交的数据,如果这些数据被回滚,则读到的数据时无效的。
      • 不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同
      • 幻读:一个事务读取了几行记录后,另一个事务插入一些记录,幻读就发生了,再后来的查询中,第一个事务就会发现有些原理没有的记录
      • 事务传播行为
    事务传播行为类型 说明
    PROPAGATION_REQUIRED 支持当前事务,如果不存在就新建一个
    PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
    PROPAGATION_MANDATORY 支持当前事务,如果不存在,就抛出异常
    PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
    PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
    PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
    PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
    • TransactionStatus: 事务具体运行状态

    3、事务管理方式

    3.1、编程式事务管理(很少用到)

    • 在AccountService中使用TransactionTemplate
    • TransactionTemplate依赖DataSourceTransactionManager
    • DataSourceTransactionManager依赖DataSource构造
      <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->  
        <bean id="transactionManager"  
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
            <property name="dataSource" ref="dataSource" />  
        </bean>  
        
        <!-- 配置事务管理模板:Spring为了简化事务管理的代码而提供的类 -->
        <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        	<property name="transactionManager" ref="transactionManager"></property>
        </bean>
    

    service实现,包含了事务管理

    package com.sysker.spring.dome.service.impl;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.TransactionCallbackWithoutResult;
    import org.springframework.transaction.support.TransactionTemplate;
    
    import com.sysker.spring.dome.dao.AccountDao;
    import com.sysker.spring.dome.service.AccountService;
    
    @Service
    public class AccountServiceImpl implements AccountService {
        
        @Autowired
        private AccountDao accountDao;
        
        @Autowired
        private TransactionTemplate transactionTemplate;
        
        @Override
        public void transfer(String out, String in, String money) {
            /**
             * 事务管理,execute()方法中创建了一个匿名内部类,在匿名内部类中操作业务,即可实现事务管理
             */
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                    accountDao.outMoney(out, money);
                    int i = 1/0;
                    accountDao.inMoney(in, money);
                    
                }
            });
            
            
        }
    
    }
    
    

    测试类

    package com.sysker.spring.dome.test;
    
    
    import javax.annotation.Resource;
    
    import org.apache.log4j.Logger;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.sysker.spring.dome.service.AccountService;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
    public class TestMybatis {
        private static Logger logger = Logger.getLogger(TestMybatis.class);
        @Resource
        private AccountService accountService = null;
        
        @Test
        public void test1() {
            accountService.transfer("aaa", "bbb", "200");
            logger.info("success");
            
        }
        
    }
    
    
    • 缺点: 在开发中需要修改过java代码,在实际开发中不会用到

    3.2、声明式事务事务管理

    • 使用XML配置声明式事务(原始方式)(很少用到)
      • 使用TransactionProxyFactoryBean
    <!-- 配置事务管理器 -->
    <bean id="transactionManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    <!-- 配置业务层的代理 -->
     <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" >
     <!-- 配置目标对象 -->
        <property name="transactionManager" ref="transactionManager"></property>
        <!-- 注入事务管理器 -->
        <property name="target" ref="accountService"></property>
        <!-- 注入事务属性 -->
        <property name="transactionAttributes">
            <props>
            <!-- 
            prop的格式:
                PROPAGATION : 事务的传播行为,必须有
                ISOLATION   : 事务的隔离级别
                readOnly    :只读
                -Exception  :发生哪些异常回滚事务
                +Exception  :发生哪些异常不回滚事务
            
            -->
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
     </bean>
    
      • prop格式:
        • PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
        • 传播行为,隔离级别,只读事务,发生这些异常回滚事务,发生这些异常提交事务

    测试类

    package com.sysker.spring.dome.test;
    
    
    import javax.annotation.Resource;
    
    import org.apache.log4j.Logger;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.sysker.spring.dome.service.AccountService;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
    public class TestMybatis {
        private static Logger logger = Logger.getLogger(TestMybatis.class);
        @Resource(name="accountServiceProxy")
        private AccountService accountService;
        
        @Test
        public void test1() {
            accountService.transfer("aaa", "bbb", "200");
            logger.info("success");
            
        }
        
    }
    
    

    service实现,包含了事务管理

    package com.sysker.spring.dome.service.impl;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.TransactionCallbackWithoutResult;
    import org.springframework.transaction.support.TransactionTemplate;
    
    import com.sysker.spring.dome.dao.AccountDao;
    import com.sysker.spring.dome.service.AccountService;
    
    @Service
    public class AccountServiceImpl implements AccountService {
        
        @Autowired
        private AccountDao accountDao;
        
        
        @Override
        public void transfer(String out, String in, String money) {
                    accountDao.outMoney(out, money);
                    int i = 1/0;
                    accountDao.inMoney(in, money);
                    
            
            
        }
    
    }
    
    
    • 基于AOP的事务管理(实际开发会经常用到)
    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    	<bean id="transactionManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    	
    	<!-- 基于aop的事务管理 -->
    	<tx:advice id="txAdvice"
    		transaction-manager="transactionManager">
    		<tx:attributes>
    		<!-- 
    		    PROPAGATION : 事务的传播行为,必须有
                ISOLATION   : 事务的隔离级别
                readOnly    :只读
                rollback-for  :发生哪些异常回滚事务
                no-rollback-for  :发生哪些异常不回滚事务
                timeout : 过期信息
    		-->
    			<tx:method name="transfer" />
    		</tx:attributes>
    	</tx:advice>
     <!-- 配置切面 -->
    	<aop:config>
    	<!-- 配置切点 -->
    		<aop:pointcut id="fooServiceOperation"
    			expression="execution(* com.sysker.spring.dome.service.impl.*.*(..))" />
    			<!-- 配置切面 -->
    		<aop:advisor advice-ref="txAdvice"
    			pointcut-ref="fooServiceOperation" />
    	</aop:config>
    
    

    service实现,包含了事务管理

    package com.sysker.spring.dome.service.impl;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.TransactionCallbackWithoutResult;
    import org.springframework.transaction.support.TransactionTemplate;
    
    import com.sysker.spring.dome.dao.AccountDao;
    import com.sysker.spring.dome.service.AccountService;
    
    @Service
    public class AccountServiceImpl implements AccountService {
        
        @Autowired
        private AccountDao accountDao;
        
        
        @Override
        public void transfer(String out, String in, String money) {
                    accountDao.outMoney(out, money);
                    int i = 1/0;
                    accountDao.inMoney(in, money);
                    
            
            
        }
    
    }
    
    

    测试类

    package com.sysker.spring.dome.test;
    
    
    import javax.annotation.Resource;
    
    import org.apache.log4j.Logger;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.sysker.spring.dome.service.AccountService;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
    public class TestMybatis {
        private static Logger logger = Logger.getLogger(TestMybatis.class);
        @Resource(name="accountService)
        private AccountService accountService;
        
        @Test
        public void test1() {
            accountService.transfer("aaa", "bbb", "200");
            logger.info("success");
            
        }
        
    }
    
    
    • 基于注解的事务管理 (实际开发会经常用到)
    <!-- 配置事务管理器 -->
    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    	<bean id="transactionManager"
    		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    		<property name="dataSource" ref="dataSource" />
    	</bean>
    	
    	!-- 基于注解的事务管理 -->
    	<tx:annotation-driven transaction-manager="transactionManager" />
    
    

    service实现,包含了事务管理

    package com.sysker.spring.dome.service.impl;
    
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.TransactionCallbackWithoutResult;
    import org.springframework.transaction.support.TransactionTemplate;
    
    import com.sysker.spring.dome.dao.AccountDao;
    import com.sysker.spring.dome.service.AccountService;
    
    @Service
    @Transactional
    public class AccountServiceImpl implements AccountService {
        
        @Autowired
        private AccountDao accountDao;
        
        
        @Override
        public void transfer(String out, String in, String money) {
                    accountDao.outMoney(out, money);
                    int i = 1/0;
                    accountDao.inMoney(in, money);
                    
            
            
        }
    
    }
    
    

    测试类

    package com.sysker.spring.dome.test;
    
    
    import javax.annotation.Resource;
    
    import org.apache.log4j.Logger;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    import com.sysker.spring.dome.service.AccountService;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})
    public class TestMybatis {
        private static Logger logger = Logger.getLogger(TestMybatis.class);
        @Resource(name="accountService)
        private AccountService accountService;
        
        @Test
        public void test1() {
            accountService.transfer("aaa", "bbb", "200");
            logger.info("success");
            
        }
        
    }
    
    
  • 相关阅读:
    剑指Offer 07 重建二叉树
    剑指Offer 06 从尾到头打印链表
    剑指Offer 05 替换空格
    剑指Offer 04 二维数组中的查找
    剑指Offer 03 数组中重复的数字
    leetcode518
    leetcode474
    leetcode376
    leetcode646
    leetcode213
  • 原文地址:https://www.cnblogs.com/caoleiCoding/p/9286589.html
Copyright © 2011-2022 走看看