引用:Spring 中常用的两种事务配置方式以及事务的传播性、隔离级别
-
事务的属性
-
原子性
事务有一个原子组成,确保动作要么都完成,要么都不完成
-
一致性
事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态
A给B转钱,无论怎么转,A和B的钱的总数都是一致的
-
隔离性
多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰
-
持久性
指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的
Spring的事务分为声明式和编程式两种
编程式事务 是在代码中加入处理事务的逻辑,在代码中显式的调用beginTransaction(),commit(),rollback()等
声明式事务 建立在AOP上,本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完看情况进行回滚或者提交
区别:
声明式事务不需要在业务逻辑代码中惨杂事务管理的代码,做到了非侵入式的开发,但是不足的是编程式事务可以作用到代码块的级别,而声明式事务只能作用到方法
声明式事务又分为基于配置的和基于@Transactional注解的
-
基于配置
配置事务管理器
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
配置需要加入事务的规则
<!-- 定义事务管理器 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 下面使用aop切面的方式来实现 -->
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
<!--配置事务传播性,隔离级别以及超时回滚等问题 -->
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="*" rollback-for="Exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<!--配置事务切点 -->
<aop:pointcut id="services"
expression="execution(* com.website.service.*.*(..))" />
<aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />
</aop:config>
-
基于@Transactional注解
配置事务管理器
<!-- 定义事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!--使用注释事务 -->
<tx:annotation-driven transaction-manager="transactionManager" />
在需要加入事务的方法或者类上添加@Transactional
PS:annotation-driven 这样的注解,其含义就是支持注解
@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置
@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为
-
Spring事务7个传播级别
@Transactional(propagation=Propagation.REQUIRED)
定义在存在多个事务同时存在的时候,Spring应该如何处理这些事务的行为。这些属性在TransactionDefinition中定义
-
PROPAGATION_REQUIRED:
支持当前事务,如果当前没有事务,就新建一个事务(默认)
-
PROPAGATION_REQUIRES_NEW:
新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务
-
PROPAGATION_SUPPORTS:
支持当前事务,如果当前没有事务,就以非事务方式执行
-
PROPAGATION_MANDATORY:
支持当前事务,如果当前没有事务,就抛出异常
-
PROPAGATION_NOT_SUPPORTED:
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
-
PROPAGATION_NEVER:
以非事务方式执行,如果当前存在事务,则抛出异常
-
PROPAGATION_NESTED(没明白):
如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行
-
Spring事务5个隔离级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
-
ISOLATION_DEFAULT:
这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
-
ISOLATION_READ_UNCOMMITTED:
这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读
-
ISOLATION_READ_COMMITTED:
保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
-
ISOLATION_REPEATABLE_READ:
这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
-
ISOLATION_SERIALIZABLE :
这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
除了防止脏读,不可重复读外,还避免了幻像读。
脏读:事务A对数据进行增删改,但是并未提交,在这时事务B获取了未提交的数据,然后事务A回滚,此时事务B就读到了脏数据
不可重复读:事务A读取了两次数据,在读取的两次中间,事务B修改了数据,导致事务A读取的两次结果不一样
幻读:事务A对一定范围的数据批量修改,此时事务B在范围内插入了一条新数据,则事务A失去了对新增数据的修改,用户发现表中还有没有修改的数据行,就好象发生了幻觉一样
-
Spring事务 只读
@Transactional(readOnly=true)
-
Spring事务 超时
@Transactional(timeout=30)
-
Spring事务 回滚
指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})