Spring事务的本质是,封装数据库事务,而数据库事务的本质则是基于数据库锁实现指定隔离级别的事务。
事务的基本特性
-
原子性(Atomicity): 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
-
一致性(Aonsistency): 执行事务前后,数据保持一致;
-
隔离性(Isolation): 并发访问数据库时,一个用户的事物不被其他事务所干扰也就是说多个事务并发执行时,一个事务的执行不应影响其他事务的执行;
-
持久性(Durability): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
Spring事务管理方式
编程式事务管理
需要按照规则编写代码,侵入性高。
TransactionTemplate、PlatformTransactionManager
@Autowired
private TransactionTemplate transactionTemplate;
public void testTransaction() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
// ... 业务代码
} catch (Exception e){
//回滚
transactionStatus.setRollbackOnly();
}
}
});
}
----------------
@Autowired
private PlatformTransactionManager transactionManager;
public void testTransaction() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
// ... 业务代码
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}
}
声明式事务管理
基于注解的实现
基于AOP实现,代码侵入性小。
作用范围
方法 :推荐将注解使用于方法上,不过需要注意的是:该注解只能应用到 public 方法上,否则不生效。
类 :如果这个注解使用在类上的话,表明该注解对该类中所有的 public 方法都生效。
接口 :不推荐在接口上使用。
@Transactional(propagation=propagation.PROPAGATION_REQUIRED)
public void daoMethod {
// ... 业务代码
}
基于XML的实现
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" propagation="NOT_SUPPORTED" />
<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
<tx:method name="del*" propagation="REQUIRED" rollback-for="Exception" />
<!-- ... -->
</tx:attributes>
</tx:advice>
<!-- 配置参与事务的类 -->
<aop:config>
<aop:pointcut id="transcationPointcut" expression="execution(* service.impl.*.*(..))"/>
<aop:advisor pointcut-ref="transcationPointcut" advice-ref="txAdvice" />
</aop:config>
事务注解
注解说明
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
事务传播机制
事务类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 表示如果当前事务存在,则支持当前事务。否则,会启动一个新的事务。xorm中默认事务类型。 |
PROPAGATION_REQUIRES_NEW | 表示新建一个全新Session开启一个全新事务,如果当前存在事务,则把当前事务挂起。 |
PROPAGATION_NESTED | 表示如果当前事务存在,则在嵌套事务内执行,如嵌套事务回滚,则只会在嵌套事务内回滚,不会影响当前事务。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。 |
PROPAGATION_SUPPORTS | 表示如果当前事务存在,则支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_NOT_SUPPORTED | 表示以非事务方式执行操作,如果当前存在事务,则新建一个Session以非事务方式执行操作,把当前事务挂起。 |
PROPAGATION_MANDATORY | 表示如果当前事务存在,则支持当前事务,如果当前没有事务,则返回事务嵌套错误。 |
PROPAGATION_NEVER | 表示以非事务方式执行操作,如果当前存在事务,则返回事务嵌套错误。 |
PROPAGATION_NOT_REQUIRED | 表示如果当前没有事务,就新建一个事务,否则返回错误。 |
事务失效场景
-
@Transactional 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用。
-
避免同一个类中自调用 @Transactional 注解的方法。
-
正确的设置 @Transactional 的 rollbackFor 和 propagation 属性。
-
组件类上需配置Spring的注解,否则Spring无法识别为Bean。
-
事务内部异常被捕获,事务内部抛出的异常范围大于注解配置异常。
-
数据源未配置事务管理器。