跟着刚哥学习Spring框架--事务配置(七)

事务

事务用来保证数据的完整性和一致性。

事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
1、原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
2、一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
3、隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作对并发执行的各个事务之间不能互相干扰。
4、持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

Spring事务管理

Spring事务管理即支持编程式事务管理,也支持声明式事务。
1、编程式事务:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚。
2、声明式事务:将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。Spring通过AOP框架支持声明式事务。

Spring事务示例(XML)

先定义一个applicationContext.xml

 1 <context:component-scan base-package="com.hzg.spring.jdbc"/>  
 2   
 3 <!-- 配置数据源 -->      
 4 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
 5     <!-- Connection Info -->  
 6     <property name="driverClass" value="${db.driverClass}" />  
 7     <property name="jdbcUrl" value="${db.url}" />  
 8     <property name="user" value="${db.username}" />  
 9     <property name="password" value="${db.password}" />  
10           
11     <!-- Connection Pooling Info -->  
12     <property name="initialPoolSize" value="1" />  
13     <property name="minPoolSize" value="1" />  
14     <property name="maxPoolSize" value="15" />  
15     <property name="maxIdleTime" value="1800" />  
16     <property name="maxStatements" value="0" />  
17 </bean>  
18       
19 <bean id="jdbcTemplateDao" class="com.hzg.spring.jdbc.dao.JdbcTemplateDao" >  
20     <property name="dataSource" ref="dataSource" />  
21 </bean>  
22       
23 <!-- JDBC事务管理器 -->  
24 <bean id="jdbctTxManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
25     <property name="dataSource" ref="dataSource" />  
26 </bean>  
27       
28 <tx:advice id="txAdvice" transaction-manager="jdbctTxManager">  
29     <tx:attributes>  
30         <tx:method name="domain*"/>  
       31 </tx:attributes> 32 </tx:advice> 33 34 <aop:config proxy-target-class="true"> 35 <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.chou.spring.jdbc.service.JdbcTemplateService.*(..))"/> 36 </aop:config>

DAO文件:

 1 public class JdbcTemplateDao extends JdbcDaoSupport{  
 2   
 3     public void save() {  
 4         String insertSql = "insert into tab_item values(?,?,?)";  
 5         Assert.isTrue(getJdbcTemplate().update(insertSql, new Object[]{6, "HP", "PT540"}) == 1, "插入失败");  
 6     }  
 7       
 8     public void delete() {  
 9         String deleteSql = "delete tab_item where id = ?";  
10         Assert.isTrue(getJdbcTemplate().update(deleteSql, new Object[]{6}) == 1, "删除失败");  
11     }  
12       
13     public void update() {  
14         String updateSql = "update tab_item set itemno = ?, itemname = ? where id = ?";  
15         Assert.isTrue(getJdbcTemplate().update(updateSql, new Object[]{"HP", "PT555", 6}) == 1, "修改失败");  
16     }  
17 } 

service文件:

 1 @Service  
 2 public class JdbcTemplateService {  
 3       
 4     @Autowired  
 5     private JdbcTemplateDao jdbcTemplateDao;  
 6       
 7     public void domain(){  
 8         jdbcTemplateDao.save();  
 9         int i = 2/0;//这里出错了,事务就会回滚,之前的save就无效了  
10         jdbcTemplateDao.update();  
11         jdbcTemplateDao.delete();  
12     }  
13 } 

Main方法

1 //main方法  
2 String[] configLocations = new String[] {"applicationContext.xml"};    
3 ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);  
4 JdbcTemplateService j = ctx.getBean(JdbcTemplateService.class);  
5 j.domain(); 

<tx:advice/>配置详解 

 1 <tx:advice id="……" transaction-manager="……">  
 2 <tx:attributes>  
 3         <tx:method name="*"  
 4                            propagation="REQUIRED"  
 5                            isolation="DEFAULT"  
 6                            timeout="-1"  
 7                            read-only="true"  
 8                            no-rollback-for=""   
 9                            rollback-for="java.lang.Exception"/>  
10     </tx:attributes>  
11 </tx:advice>  
12   
13 <!-- 最常用的配置 -->  
14 <tx:advice id="txAdvice" transaction-manager="txManager">  
15 <tx:attributes>  
16            <tx:method name="save*" propagation="REQUIRED" />  
17            <tx:method name="add*" propagation="REQUIRED" />  
18            <tx:method name="create*" propagation="REQUIRED" />  
19            <tx:method name="insert*" propagation="REQUIRED" />  
20            <tx:method name="update*" propagation="REQUIRED" />  
21            <tx:method name="merge*" propagation="REQUIRED" />  
22            <tx:method name="del*" propagation="REQUIRED" />  
23            <tx:method name="remove*" propagation="REQUIRED" />  
24            <tx:method name="put*" propagation="REQUIRED" />  
25            <tx:method name="get*" propagation="SUPPORTS" read-only="true" />  
26            <tx:method name="count*" propagation="SUPPORTS" read-only="true" />  
27            <tx:method name="find*" propagation="SUPPORTS" read-only="true" />  
28            <tx:method name="list*" propagation="SUPPORTS" read-only="true" />  
29            <tx:method name="*" propagation="SUPPORTS" read-only="true" />  
30            <tx:method name="batchSaveOrUpdate" propagation="REQUIRES_NEW" />  
31        </tx:attributes>  
32 </tx:advice>  
33 <aop:config>  
34        <aop:pointcut id="txPointcut" expression="execution(* cn.javass..service.*.*(..))" />  
35        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />  
36 </aop:config>  

XML形式的事务配置<tx:method >的属性详解 

属性
类型
默认值
说明
propagation Propagation枚举 REQUIRED 事务传播属性
isolation isolation枚举 DEFAULT(所用数据库默认级别) 事务隔离级别
readOnly boolean false 是否才用优化的只读事务
timeout int -1 超时(秒)
rollbackFor Class[] {} 需要回滚的异常类
rollbackForClassName String[] {} 需要回滚的异常类名
noRollbackFor Class[] {} 不需要回滚的异常类
noRollbackForClassName String[] {} 不需要回滚的异常类名

readOnly 

事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。如果值为true就会告诉Spring我这个方法里面没有insert或者update,你只需要提供只读的数据库Connection就行了,这种执行效率会比read-write的Connection高,所以这是一个最优化提示。在一些情况下,一些事务策略能够起到显著的最优化效果,例如在使用Object/Relational映射工具(如:Hibernate或TopLink)时避免dirty checking(试图“刷新”)。 

timeout 
在属性中还有定义“timeout”值的选项,指定事务超时为几秒。一般不会使用这个属性。在JTA中,这将被简单地传递到J2EE服务器的事务协调程序,并据此得到相应的解释。 

Isolation Level(事务隔离等级)的5个枚举值 
1、DEFAULT:采用数据库默认隔离级别 
2、SERIALIZABLE:最严格的级别,事务串行执行,资源消耗最大; 
3、REPEATABLE_READ:保证了一个事务不会修改已经由另一个事务读取但未提交(回滚)的数据。避免了“脏读取”和“不可重复读取”的情况,但是带来了更多的性能损失。 
4、READ_COMMITTED:大多数主流数据库的默认事务等级,保证了一个事务不会读到另一个并行事务已修改但未提交的数据,避免了“脏读取”。该级别适用于大多数系统。 
5、READ_UNCOMMITTED:保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。 

propagation属性的7个传播行为 
1、REQUIRED:指定当前方法必需在事务环境中运行,如果当前有事务环境就加入此事务环境,如果没有就新建一个事务。(默认值) 
2、SUPPORTS:指定当前方法加入当前事务环境,如果当前没有事务,就以非事务方式执行。 
3、MANDATORY:指定当前方法必须加入当前事务环境,如果当前没有事务,就抛出异常。 
4、REQUIRES_NEW:指定当前方法总是发起一个新事务,存在别的事务就被挂起,直到我的事务方法commit结束,原先事务才恢复。 
5、NOT_SUPPORTED:指定当前方法以非事务方式执行,如果当前存在事务就挂起,等我以非事务的状态运行完,再继续原来事务。 
6、NEVER:指定当前方法绝对不能在事务范围内执行,如果方法在事务范围内执行,容器就抛异常,只有没关联到事务,才正常执行。 
7、NESTED:指定当前方法执行时,如果已经有一个事务存在,则运行在这个嵌套的事务中.如果当前环境没有运行的事务,就新建一个事务,并与父事务相互独立,这个事务拥有多个可以回滚的保证点。就是指我自己内部事务回滚不会对外部事务造成影响,只对DataSourceTransactionManager事务管理器起效。 

Spring事务示例(注解形式@Transactional)

注意@Transactional只能被应用到public方法上,对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能。 
默认情况下,一个有事务的方法,遇到RuntiomeException时会回滚。遇到受检查的异常是不会回滚的,要想所有异常都回滚,要加上属性rollbackFor={Exception.class}

1 <!-- 事务管理器配置 -->  
2 <bean id="txManager"     class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
3     <property name="sessionFactory" ref="sessionFactory" />  
4 </bean>  
5 
6 <!-- 使用annotation定义事务 -->  
7 <tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />  

transaction-manager:指定事务管理器名字,默认为transactionManager,当使用其他名字时需要明确指定; 
proxy-target-class:默认false表示使用JDK代理,如果为true将使用CGLIB代理 
order:定义事务通知顺序,默认Ordered.LOWEST_PRECEDENCE,表示将顺序决定权交给AOP来处理。

 1 @Transactional//放在这里表示所有方法都加入事务管理  
 2 public class AnnotationUserServiceImpl implements IUserService {  
 3     private IUserDao userDao;  
 4     private IAddressService addressService;  
 5       
 6     @Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED)  
 7     public void save(UserModel user) {  
 8         userDao.save(user);  
 9         user.getAddress().setUserId(user.getId());  
10         addressService.save(user.getAddress());  
11     }  
12   
13     @Transactional(propagation=Propagation.REQUIRED, readOnly=true,  
14                    isolation=Isolation.READ_COMMITTED)  
15     public int countAll() {  
16         return userDao.countAll();  
17     }  
18     //setter...  
19 } 

 -----------------------------------------------------------------------------------------------------------------------

跟着刚哥学习Spring框架--创建HelloWorld项目(一)

跟着刚哥学习Spring框架--Spring容器(二)

跟着刚哥学习Spring框架--通过XML方式配置Bean(三)

跟着刚哥学习Spring框架--通过注解方式配置Bean(四)

跟着刚哥学习Spring框架--AOP(五)

跟着刚哥学习Spring框架--JDBC(六)

跟着刚哥学习Spring框架--事务配置(七)

原文地址:https://www.cnblogs.com/hzg110/p/6833252.html