- 数据库事务和spring事务的区别
- Spring 事务管理接口介绍
- PlatformTransactionManager :事务管理接口
- TransactionDefinition:事务属性
- TransactionStatus:事务状态
- spring事物使用
- 五大属性
- 事务失效的7种情况
- 如何快速定位事务相关bug?
二者本质上是同一个概念,spring的事务是对数据库的事务的封装。
封装原理:spring通过aop对bean创建代理对象来实现事务管理
Spring 框架中,事务管理相关最重要的 3 个接口如下:
PlatformTransactionManager: 事务管理器,核心。 TransactionDefinition: 事务定义信息(事务隔离级别、传播行为、超时、只读、回滚规则)。 TransactionStatus: 事务运行状态。
我们可以把 PlatformTransactionManager 接口看作是事务上层的管理者,而 TransactionDefinition 和 TransactionStatus 这两个接口可以看作是事物的描述。
PlatformTransactionManager 会根据 TransactionDefinition 的定义比如事务超时时间、隔离级别、传播行为等来进行事务管理 ,而 TransactionStatus 接口则提供了一些方法来获取事务相应的状态,比如是否新事务、是否可以回滚等等。
Spring 并不直接管理事务,而是提供了多种事务管理器 ,PlatformTransactionManager 就是其中之一的事务管理接口。
通过这个接口,Spring 为各个平台JDBC/Mybatis(DataSourceTransactionManager)、Hibernate(HibernateTransactionManager)、JPA(JpaTransactionManager)等都提供了对应的事务管理器,但是具体的实现就是各个平台自己的事情了。
PlatformTransactionManager接口中定义了三个方法:
public interface PlatformTransactionManager {
//获得事务
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
//提交事务
void commit(TransactionStatus var1) throws TransactionException;
//回滚事务
void rollback(TransactionStatus var1) throws TransactionException;
}
为什么要定义或者说抽象出来PlatformTransactionManager这个接口呢?
主要是因为要将事务管理行为抽象出来,然后不同的平台去实现它,这样我们可以保证提供给外部的行为不变,方便我们扩展。
TransactionDefinition:事务属性事务管理器接口 PlatformTransactionManager 通过 getTransaction(TransactionDefinition definition) 方法来得到一个事务,这个方法里面的参数就是 TransactionDefinition 类 ,这个类就定义了一些基本的事务属性。
那么什么是 事务属性 呢?
事务属性可以理解成事务的一些基本配置,描述了事务策略如何应用到方法上。
事务属性包含了 5 个方面:
TransactionDefinition 接口中定义了 5 个方法以及一些表示事务属性的常量比如隔离级别、传播行为等等。
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
// 返回事务的传播行为,默认值为 REQUIRED。
int getPropagationBehavior();
//返回事务的隔离级别,默认值是 DEFAULT
int getIsolationLevel();
// 返回事务的超时时间,默认值为-1。
//如果超过该时间限制但事务还没有完成,则自动回滚事务。
int getTimeout();
// 返回是否为只读事务,默认值为 false
boolean isReadOnly();
@Nullable
String getName();
}
五大属性详解
TransactionStatus:事务状态TransactionStatus接口用来记录事务的状态 ,该接口定义了一组方法,用来获取或判断事务的相应状态信息。
有如下状态信息:
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事物
boolean hasSavepoint(); // 是否有恢复点
void setRollbackOnly(); // 设置为只回滚
boolean isRollbackOnly(); // 是否为只回滚
boolean isCompleted; // 是否已完成
}
spring事物使用
五大属性
事务失效的7种情况
1、未启用spring事务管理功能
@EnableTransactionManagement 注解不要忘了
2、方法不是public类型的
4、必须通过代理对象访问目标方法,事务才会生效,普通对象访问会失效。
spring的事物是怎么实现的?通过aop给目标对象生成代理对象,然后通过代理对象拦截目标方法的执行,在目标方法前后添加了事务的功能,所以必须通过代理对象调用目标方法的时候,事务才会起效。
看下面代码,当外部直接调用m1的时候,m2方法的事务会生效么?
@Component
public class UserService {
public void m1(){
this.m2();
}
@Transactional
public void m2(){
//执行db操作
}
}
显然不会生效,因为m1中通过this的方式调用了m2方法,而this并不是代理对象,this.m2()不会被事务拦截器,所以事务是无效的,如果外部直接通过UserService这个bean来调用m2方法,事务是有效的,上面代码可以做一下调整,如下,@1在UserService中注入了自己,此时m1中的m2事务是生效的
@Component
public class UserService {
@Autowired //@1
private UserService userService;
public void m1() {
userService.m2();
}
@Transactional
public void m2() {
//执行db操作
}
}
5、发生异常
6、异常被吞了
当业务方法抛出异常,spring感知到异常的时候,才会做事务回滚的操作,若方法内部将异常给吞了,那么事务无法感知到异常了,事务就不会回滚了。
7、业务代码和事务代码必须在同一个线程中
spring事务实现中使用了ThreadLocal,这就要求业务代码和事务代码必须在一个线程中,数据才可以共享,才会受spring事务的控制。
比如下面代码,方法内部的子线程内部执行的事务操作将不受m1方法上spring事务的控制,这个大家一定要注意
@Transactional
public void m1() {
new Thread() {
一系列事务操作
}.start();
}
如何快速定位事务相关bug?
方式1:看日志
如果你使用了logback或者log4j来输出日志,可以修改一下日志级别为debug模式,可以看到事务的详细执行日志,帮助你定位错误
方式2:调试代码
如果你对源码比较了解,那么你会知道被spring管理事务的业务方法,执行的时候都会被TransactionInterceptor拦截器拦截,会进入到它的invoke方法中,咱们可以在invoke方法中设置一些断点,可以看到详细的执行过程,排错也就比较容易了。



