spring事务管理

来源:互联网 发布:开源电商源码 编辑:程序博客网 时间:2024/06/05 20:30
事务管理是企业级应用程序开发中必不可少的技术,用来确保一组操作的时候       数据的完整性和一致性


技术委员  没钱了   班长----2000      班长  ---   转钱         (1:从班长的卡里扣钱    2:给技术组长的卡里增钱)
2000               0

例如去银行存款转账张三给李四转钱,这个过程就是我们所说的一个事物
   
一个完整的事物需要满足以下的特性 ACID
 原子性(atomicity):事务的原子性确保动作要么全部完成,要么完全不起作用
 一致性(consistency):一旦所有事务动作完成,事务就被提交。也就是说要么都成功,要么都不成功
 隔离性(isolation):多个事物同时处理一个数据的时候,每个事物都应该与其他事务隔离开来,防止数据损坏
 持久性(durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响。应该被持久化到数据库中


这就是事务的四个关键属性(ACID)


Spring既支持编程式事务管理,也支持声明式的事务管理


1:编程式事务管理:将事务管理代码嵌入到业务方法中来控制事务的提交和回滚,在编程式事务中,必须在每个业务操作中包含额外的事务管理代码


2:声明式事务管理:大多数情况下比编程式事务管理更好用。它将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。事务管理作为一种横切关注点,可以通过AOP方法模块化。Spring通过Spring AOP框架支持声明式事务管理。
REQUERED
A


我们需要首先来解释两个比较专业的概念,事物的传播行为和事物的隔离特性


spring事务的传播行为说的是当一个方法调用另一个方法时,事务该如何操作。 
spring中常用的的事物类型有着些


1:REQUERED--------------PROPAGATION_REQUIRED
支持当前事务,如果没有事物则新建事物----最常用
2:SUPPORTS
支持当前事务,如果没有事物,则以非事物的模式进行
3:MANDATORY
支持当前事务,如果当前没有事物,则抛出异常
4:REQUIRES-NEW
新建一个事物,如果当前存在事物,则将当前事务挂起
5:NOT-SUPPORTED
以非事物的方式进行,如果当前有事物则将事物挂起
6:NEVER
以非事物的方式进行,如果有事物则挂起
7:NESTED
如果当前存在事物,则嵌套在事物内进行,如果当前没有事物,则和1的方式一样




解释几个非常重要的概念
1:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
张三原来有3000块钱,又存款2000(这个时间比较长)。同一时间,张三老婆看到的张三卡里的钱还是只有3000,取款了2800,张三悲剧了,着就是脏读
  
2. 不可重复读 :是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据---并且修改。那么,在第一个事务中的两 次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的
3. 幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样


不一定把这三种问题都解决


spring的事务隔离级别 
ISOLATION_DEFAULT:使用数据库默认的隔离级别。
 
ISOLATION_READ_UNCOMMITTED:允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读。 
是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。


ISOLATION_READ_COMMITTED:允许并发事务提交之后读取,可以避免脏读,可能导致重复读和幻读。 
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据


ISOLATION_REPEATABLE_READ:对相同字段的多次读取结果一致,可导致幻读。 
  它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。


ISOLATION_SERIALIZABLE:完全服从ACID的原则,确保不发生脏读、不可重复读和幻读。 

这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。



首先在applicationContext.xml中配置:


<!-- 利用注解生成 处理事物 -->
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager"/>

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

<!-- 事物配置的模板  定义个通知,指定事务管理器 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="delete*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="update*" propagation="REQUIRED" read-only="false"
rollback-for="java.lang.Exception" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="load*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>

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

在service层方法中:


@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.SERIALIZABLE)
public void transfer(int Aid,int Bid,double money){
//这一组操作应该是一个事物   是事物就应该满足事物的特性  4
//从上往下依次执行,哪里有错哪里断
double moneyA=mapper.findUserMoney(Aid)-money;
double moneyB=mapper.findUserMoney(Bid)+money;
mapper.transfer(Aid, moneyA);
// String s=null;//如果有一场发生,事务回滚
// System.out.println(s.length());
mapper.transfer(Bid, moneyB);
//调用userService  ---findUser(事物)
}

public void setMapper(BankMapper mapper) {
this.mapper = mapper;
}