隔离属性
主要是保证并发条件下事务对数据读取和更新安全性。
并发过程中事务可能出现的问题:
1) 脏读:一个事务读取到了另一个事务还没有提交的数据。
2) 不可重复读:一个事务两次读取同一个资源,读到的结果不同。具体原因是中间另一个事物修改了资源。
3) 幻象读:事务在进行表级运算(例如sum,max…)中间有insert或delete对象,这段是我的理解,一般资料写是insert。
4) 第一类更新丢失(回滚丢失):两个事务都对同一个资源先后做了更新,但是先更新的事务回滚了。造成后更新的时候更新操作失败。即回滚造成的更新丢失。
5) 第二类更新丢失(覆盖丢失):和不可重复读类似,两个事务同事读取一个资源进行更新,但是没有同步,造成后提交的事务覆盖了先提交事务做的更新。即覆盖造成的更新丢失。
Spring的事务隔离级别:
1) DEFAULT 使用数据库中设置的隔离级别 ( 默认 ) ,由 DBA默认的设置来决定隔离级别 .
2)READ_UNCOMMITTED 未提交读,没有隔离机制,会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
3)READ_COMMITTED 提交读,保证当前事务读取到的资源是已经被修改提交的。一个事务能读取到别的事务提交的更新数据,不能看到未提交的更新数据,不可能可能出现丢失更新、脏读,但可能出现不可重复读、幻读;
4)REPEATABLE_READ 可重复读,保证同一事务中先后执行的多次查询将返回同一结果,不受其他事务影响,可能可能出现丢失更新、脏读、不可重复读,但可能出现幻读;
5) SERIALIZABLE序列化,最高隔离级别,不允许事务并发执行,而必须串行化执行,最安全,不可能出现更新、脏读、不可重复读、幻读。实质是锁表。
传播属性
主要是定义方法是否以事务方式运行还有嵌套情况下如何执行。目前看事务的属性以注解方式设置最好最方便。
关于propagation属性的7个传播行为 REQUIRED SUPPORTS NOT_SUPPORTED REQUIRES_NEW NESTED 抛异常的两个 MANDATORY NEVER
最常用的两个required 优先以事务方式执行
supports 优先以非事务方式执行
NOT_SUPPORTED 以非事务方式执行
抛异常的两个
MANDATORY 当前必须已经存在一个事务,否则报错。如果存在则放在一起执行。
NEVER 必须以非事务方式执行,必须当前没有事务执行,否则报错
涉及嵌套的两个
REQUIRES_NEW 无论有没有被嵌套或者已经存在一个事务,都新建一个事务,在新事务中单独执行,外层事务或已经存在的事务先挂起。也就是说这个新的事务作为单独的一个原子。
NESTED 如果被嵌套,就在嵌套事务中执行,如果没有被嵌套,则按照required的方式执行
理解REQUIRES_NEW 和NOT_SUPPORTED,这两种其实都是限定当前事务已经存在事务隔离,互不影响。已经存在的事务作为两个事务来运行的。比如:一个单号发生器的方法可以设置为REQUIRES_NEW方法,保证并发下的单例模式,外部方法获取单号以后,内部设置数据库的单号自增1。这个即便旧的事务出现问题回滚,新的事务也是不需要回滚的。
下面两段是否正确还需要验证:
PROPAGATION_REQUIRES_NEW时,内层事务与外层事务就像两个独立的事务一样,一旦内层事务进行了提交后,外层事务不能对其进行回滚。两个事务互不影响。两个事务不是一个真正的嵌套事务。同时它需要JTA 事务管理器的支持。
使用PROPAGATION_NESTED时,外层事务的回滚可以引起内层事务的回滚。而内层事务的异常并不会导致外层事务的回滚,它是一个真正的嵌套事务。
要了解事务之间的关系,如果是嵌套事务关系,需要考虑父子关系。判断当前事务是否是被嵌套的。
深层需要考虑分布式和各种场景下事务的关系:分布式事务 嵌套事务 多层事务
Spring中事务的配置方法:
XML方式的配置
Spring中的事务配置方式是按照AOP,在类中设置切入点,引入事务处理策略。然后通过代理模式,定义事务处理策略。
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!--以事务的方式执行 匹配所有以save开头的方法 propagation事务传播属性-->
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="merge*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="put*" propagation="REQUIRED" />
<!--以非事务的方式执行-->
<tx:method name="get*" propagation="NOT_SUPPORTED" read-only="true" />
<tx:method name="count*" propagation="NOT_SUPPORTED" read-only="true" />
<tx:method name="find*" propagation="NOT_SUPPORTED" read-only="true" />
<tx:method name="list*" propagation="NOT_SUPPORTED" read-only="true" />
<tx:method name="*" propagation="NOT_SUPPORTED" read-only="true" />
<!--rollback-for配置触发回滚的异常 -->
<!--isolation事务隔离级别,默认为“DEFAULT” no-rollback-for配置不被触发回滚的异常-->
<tx:method name="doComplexLogic" propagation="NESTED"
isolation="REPEATABLE_READ" timeout="1000" rollback-for="java.lang.Exception"
no-rollback-for="com.mysrc.service.CustomRuntimeException" />
</tx:attributes>
</tx:advice>
<aop:config>
<!--切入点 表达式的意思是拦截cn包及子包下的chapter9. service包及子包下的任何类的任何方法-->
<aop:pointcut id="txPointcut" expression="execution(* cn.javass..service.*.*(..))" />
<!--表示切入点txPointcut 使用的事务规则是txAdvice -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>
java注解方式配置:
package com.baobaotao.service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
public class ForumService {
private UserService userService;
@Transactional(propagation=Propagation.NEVER)
public void addTopic(){
//add Topic
userService.addCredits();
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
事务的特性
ACID
原子性 一个事务中的所有事务作为一个整体即一个原子,如果执行失败要回滚则一起回滚。
一致性 在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。
隔离性 不同的同类事务事务之间相互隔离,类似于不同的线程,不会相互影响。
持久性 事务执行的结果会持久化到存储介质。
事务常问问题
事务有哪几个特性?
原子性 一致性 隔离性 持久性
Spring事务,Hibernate事务,JTA,数据库事务,他们之间的有什么关系?
1 一般底层的一个事务对应一个jdbc的connection session连接。
2事务通俗的理解,事务是一组原子操作的一个单元,从数据库角度说,就是一组SQL指令,要么全部执行成功,若因为某个原因其中一条指令执行有错误,则撤销先前执行过的所有指令。更简答的说就是:要么全部执行成功,要么全部撤销不执行。
3 JTA是一个协议和接口定义api,支持分布式的同事访问多个多种连接。Hibernate实现了这个协议和接口。
JTA的例子https://www.ibm.com/developerworks/cn/java/j-lo-jta/
4
Hibernate的缓存详解
http://www.cnblogs.com/hnlshzx/p/3497545.html
参考:
http://sishuok.com/forum/blogPost/list/2508.html图书 Spring 3.x 企业应用开发实战