您的位置:首页 > 编程语言 > Java开发

JavaEE_Spring_Spring中的事务声明, 事务隔离和事务传播等

2016-05-25 13:49 302 查看
最近面试经常被问到事务的隔离与事务传播等方面的知识,现在留下一篇博文整理了网上几篇博文的资料。记录一下



0.Spring中的事务以及事务声明

这里只讲解Spring中的事务,对于SQL事务的概念以及ACID性质可以参见另一博文 http://kingj.iteye.com/admin/blogs/1675011

1)  Spring的管理的事务可以分为如下2类:

(1)逻辑事务:  在Spring中定义的事务通常指逻辑事务,提供比物理事务更抽象,方便的事务配置管理,但也基于物理事务。

(2)物理事务:  特定于数据库的事务。

2)Spring中支持的2种事务声明方式

(1)编程式事务:  当系统需要明确的,细粒度的控制各个事务的边界,应选择编程式事务

(2)声明式事务:  当系统对于事务的控制粒度较粗时,应该选择申明式事务

无论你选择上述何种事务方式去实现事务控制,spring都提供基于门面设计模式的事务管理器供选择,如下是spring事务中支持的事务管理器

 

事务管理器实现(org.springframework.*)

使用时机

jdbc.datasource.DataSourceTransactionManager

使用jdbc的抽象以及ibatis支持

orm.hibernate.HibernateTransactionManager

使用hibernate支持(默认3.0以下版本)

orm.hibernate3.HibernateTransactionManager

使用hibernate3支持

transaction.jta.JtaTransactionManager

使用分布式事务(分布式数据库支持) 

orm.jpa.JpaTransactionManager

使用jpa做为持久化工具

orm.toplink.TopLinkTransactionManager

使用TopLink持久化工具

orm.jdo.JdoTransactionManager 

使用Jdo持久化工具

jms.connection.JmsTransactionManager

使用JMS 1.1+

jms.connection.JmsTransactionManager102 

使用JMS 1.0.2

transaction.jta.OC4JJtaTransactionManager 

使用oracle的OC4J JEE容器

transaction.jta.WebLogicJtaTransactionManager

在weblogic中使用分布式数据库

jca.cci.connection.CciLocalTransactionManager

使用jrping对J2EE Connector Architecture (JCA)和Common Client Interface (CCI)的支持

UML类结构示意图



3)Spring中配置事务

1.声明式事务配置方式(以JDBC事务举例)

(1)Annotation方式配置事务

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:annotation-driven transaction-manager="txManager"/>

   

   Service层中的注解

@Transactional(readOnly=true)
public void add(User user) {

userDAO.save(user);
Log log = new Log();
log.setMsg("a user saved!");
logDAO.save(log);

}


(2)XML方式配置事务

 i.定义事务管理器,里面存放了数据库连接等信息

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
<property name="dataSource" ref="dataSource"/>  
</bean>  


 ii.定义事务Aop通知

<tx:advice id="txAdvice" transactionManager="transactionManager">  
     <tx:attributes>  
        <tx:method name="add*" propagation="REQUIRED"/>  
    </tx:attributes>  
</tx:advice> 


 iii.定义事务的切面,哪些地方需要事务

<aop:config>  
<aop:advisor pointcut="execution(* *..zx.spring.UserService*.*(..))||
execution(* *..spring.ServiceFacade.*(..))||
execution(* *..spring.BookService.*(..))" advice-ref="txAdvice"/>  
</aop:config>  


1.Spring中的事务传播

spring的 7种事务传播行为类型

实际测试总结 http://blog.csdn.net/u010003835/article/details/51498560



Spring特有的事务传播行为,Spring支持7种事务传播行为,确定客户端和被调用端的事务边界(说得通俗一点就是多个具有事务控制的service的相互调用时所形成的复杂的事务边界控制)下图所示为7钟事务传播机制

传播行为含义
PROPAGATION_REQUIRED(XML文件中为REQUIRED)表示当前方法必须在一个具有事务的上下文中运行,如有客户端有事务在进行,

那么被调用端将在该事务中运行,否则的话重新开启一个事务。

(如果被调用端发生异常,那么调用端和被调用端事务都将回滚)
PROPAGATION_SUPPORTS(XML文件中为SUPPORTS)表示当前方法不必需要具有一个事务上下文,

但是如果有一个事务的话,它也可以在这个事务中运行
PROPAGATION_MANDATORY(XML文件中为MANDATORY)表示当前方法必须在一个事务中运行,

如果没有事务,将抛出异常
PROPAGATION_NESTED(XML文件中为NESTED)表示如果当前方法正有一个事务在运行中,则该方法应该运行在一个嵌套事务中,

被嵌套的事务可以独立于被封装的事务中进行提交或者回滚。
如果封装事务存在,并且外层事务抛出异常回滚,那么内层事务必须回滚,

反之,内层事务并不影响外层事务。

如果封装事务不存在,则同PROPAGATION_REQUIRED的一样
PROPAGATION_NEVER(XML文件中为NEVER)表示当方法务不应该在一个事务中运行,如果存在一个事务,则抛出异常
PROPAGATION_REQUIRES_NEW(XML文件中为REQUIRES_NEW)表示当前方法必须运行在它自己的事务中。
一个新的事务将启动,而且如果有一个现有的事务在运行的话,

则这个方法将在运行期被挂起,直到新的事务提交或者回滚才恢复执行。
PROPAGATION_NOT_SUPPORTED

(XML文件中为NOT_SUPPORTED)
表示该方法不应该在一个事务中运行。
如果有一个事务正在运行,他将在运行期被挂起,

直到这个事务提交或者回滚才恢复执行
当使用 PROPAGATION_NESTED 时,
底层的数据源必须基于 JDBC 3.0 ,并且实现者需要支持保存点事务机制。

 


2.Spring中的事务隔离

事务隔离级别基本概念


      数据库并发操作存在的异常情况:
1. 更新丢失(Lost update): 两个事务都同时更新一行数据但是第二个事务却中途失败退出导致对数据两个修改都失效了这是系统没有执 行任何锁操作因此并发事务并没有被隔离开来。
2. 脏读取(Dirty Reads): 一个事务开始读取 了某行数据但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险很可能所有操作都被回滚。
3. 不可重复读取(Non-repeatable Reads): 一 个事务对同一行数据重复读取两次但是却得到了不同结果。例如在两次读取中途有另外一个事务对该行数据进行了修改并提交。
4. 两次更新问题(Second lost updates problem): 无法重复读取特例,有两个并发事务同时读取同一行数据然后其中一个对它进行修改提交而另一个也进行了修改提交这就会造成 第一次写操作失效。
5. 幻读(Phantom Reads): 也称为幻像(幻 影)。事务在操作过程中进行两次查询,第二次查询结果包含了第一次查询中未出现的数据(这里并不要求两次查询SQL语句相同)这是因为在两次查询过程中有 另外一个事务插入数据造成的。

      为了避免上面出现几种情况在标准SQL规范中定义了4个事务隔离级别,不同隔离级别对事务处理不同 。
1.未授权读取(Read Uncommitted): 也称 未提交读。允许脏读取但不允许更新丢失,如果一个事务已经开始写数据则另外一个数据则不允许同时进行写操作但允许其他事务读此行数据。该隔离级别可以通过 “排他写锁”实现。事务隔离的最低级别,仅可保证不读取物理损坏的数据。与READ COMMITTED 隔离级相反,它允许读取已经被其它用户修改但尚未提交确定的数据。
2. 授权读取(Read Committed): 也称提交 读。允许不可重复读取但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现,读取数据的事务允许其他事务继续访问该行数据,但是未提交写事务将 会禁止其他事务访问该行。SQL Server 默认的级别。在此隔离级下,SELECT 命令不会返回尚未提交(Committed) 的数据,也不能返回脏数据。
3. 可重复读取(Repeatable Read): 禁止 不可重复读取和脏读取。但是有时可能出现幻影数据,这可以通过“共享读锁”和“排他写锁”实现,读取数据事务将会禁止写事务(但允许读事务),写事务则禁 止任何其他事务。在此隔离级下,用SELECT 命令读取的数据在整个命令执行过程中不会被更改。此选项会影响系统的效能,非必要情况最好不用此隔离级。
4. 串行(Serializable): 也称可串行读。提 供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机 制保证新插入的数据不会被刚执行查询操作事务访问到。事务隔离的最高级别,事务之间完全隔离。如果事务在可串行读隔离级别上运行,则可以保证任何并发重叠 事务均是串行的。

隔离级别     更新丢失 脏读取 重复读取 幻读 

未授权读取     N            Y         Y          Y 

授权读取        N            N         Y          Y 

可重复读取     N            N         N         Y 

串行               N            N         N         N

Spring的事务隔离级别其实本质上是对SQL92标准的4种事务隔离级别的一种封装,具体参考博文:http://kingj.iteye.com/admin/blogs/1675011

Spring中的事务隔离级别




隔离级别 含义
ISOLATION_DEFAULT使用数据库默认的事务隔离级别
ISOLATION_READ_UNCOMMITTED允许读取尚未提交的修改,可能导致脏读、幻读和不可重复读
ISOLATION_READ_COMMITTED
允许从已经提交的事务读取,可防止脏读、但幻读,不可重复读

仍然有可能发生。
ISOLATION_REPEATABLE_READ对相同字段的多次读取的结果是一致的,除非数据被当前事务自生修改。

可防止脏读和不可重复读,但幻读仍有可能发生
ISOLATION_SERIALIZABLE
完全服从ACID隔离原则,确保不发生脏读、不可重复读、和幻读,

但执行效率最低。



3.Spring事务中的只读属性(优化)

readOnly  只进行读取的业务可以设置,进行优化

      事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。这 是一个最优化提示 。在一些情况下,一些事务策略能够起到显著的最优化效果,例如在使用Object/Relational映射工具 (如:hibernate或TopLink)时避免dirty
checking(试图“刷新”)。

 





4.Spring其他的事务属性

Timeout
       在事务属性中还有定义“timeout”值的选项,指定事务超时为几秒。在JTA中,这将被简单地传递到J2EE服务器的事务协调程序,并据此得到相应的 解释。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: