ps:这篇文章几个月前就整理好了,参考了很多好文章,吸取了他们的精华+自己的一些理解,分享给je的朋友们!
Spring框架引人注目的重要因素之一是它全面的事务支持。Spring框架提供了一致的事务管理抽象,这带来了以下好处:
•为复杂的事务API提供了一致的编程模型,如JTA、JDBC、Hibernate、JPA和JDO
•支持 声明式事务管理
•提供比大多数复杂的事务API(诸如JTA)更简单的,更易于使用的 编程式 事务管理API
•非常好地整合Spring的各种数据访问抽象
首先看下一个简单的应用配置:
声明式事务配置:
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory"/>
</property>
</bean>
<!-- 配置事务特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="insert" propagation="REQUIRED"/>
<tx:method name="save" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true" propagation="NEVER"/>
</tx:attributes>
</tx:advice>
<!-- 配置那些类的方法进行事务管理 -->
<aop:config proxy-target-class="true">
<aop:pointcut id="allManagerMethod" expression="execution (* org.lxh.ssh.PersonDAOImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod"/>
</aop:config>
采用spring注释配置:
<!-- 事务管理 "org.springframework.jdbc.datasource.DataSourceTransactionManager"-->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref = "sessionFactory "></property>
</bean>
<!-- 将所有具有@Transactional注解的Bean自动配置为声明式事务支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
已上配置只是基于单数据源的配置,如果一个事务包含了两个数据源的操作,这样的事务就不能正常运行,对应多事务源的程序里,还是需要老老实实使用用分布式事务管理服务(jta)。
注:如果只用Tomcat做应用服务器的话是不能使用JTA事务的
通过采用spring注释配置,我们可以使用@Transactional注解来进行事务的处理,@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。 然而,请注意只是使用 @Transactional 注解并不会启用事务行为, 它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。
@Transactional 注解是用来指定接口、类或方法必须拥有事务语义的元数据。 如:“当一个方法开始调用时就开启一个新的只读事务,并停止掉任何现存的事务”。 默认的 @Transactional 设置如下:
•事务传播设置是 PROPAGATION_REQUIRED
•事务隔离级别是 ISOLATION_DEFAULT
•事务是 读/写
•事务超时默认是依赖于事务系统的,或者事务超时没有被支持。
•任何 RuntimeException 将触发事务回滚,但是任何 checked Exception 将不触发事务回滚
spring事务都有哪一些传播特性:
1.
PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启
2.
PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
3.
PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4.
PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5.
PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
6.
PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
7.
PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务,则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行。
Spring事务的隔离级别:
1.
ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。
2.
ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
3.
ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取
该事务未提交的数据
4.
ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5.
ISOLATION_SERIALIZABLE: 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。除了防止脏读,不可重复读外,还避免了幻像读。
了解脏数据,脏读,不可重复读,幻觉读:
脏读: 指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据, 那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。
不可重复读: 指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
幻觉读: 指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
通过以上对事物的简单了解,我们知道在service这一层处理事务,覆盖的范围就很广了,但是实际上,并不是每个操作都能回滚的,只有那些有事务性的操作可以回滚。最简单的说,在事务中,发了email,修改了硬盘文件,那么这些操作都是不可以回滚的。而即使是修改数据库的操作,如果数据库不支持事务或者由于代码写得不支持事务,这部分的代码也是不能回滚的,那么也不会回滚。这个看起来有点废话,想说明的只是,事务不是什么神奇的东西,不要误会一回滚,什么东西都回复原来的现状了。包括工作流那些东东,不要以为是理所当然的,要记住,只有支持事务的操作,才是可以回滚的。所以,事务并不是万能的,并不是有了事务在出现异常的情况下,什么操作都可以恢复到本来的面貌。