前言
事务是大家用的最多的,也是比较关心的一个功能。本章就详细讲解spring-tx模块中事务的实现与spring-boot事务的处理。可能这一节就会把spring-tx说完,事务没有大家想象的那么复杂。
jdbc基本操作
java的连接池,事务管理,持久层(MyBtais,hibernation)都是基于jdbc(Java DataBase Connectivity,java数据库连接)进行演进的。那么仔细看下下面的jdbc代码,从而理解连接池,事务管理,持久层(MyBtais,hibernation)。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Random;
public class Demo {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement ps = null;
try {
Class.forName("com.mysql.jdbc.Driver");// 1. 注册驱动
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","mysql"); // 2. 创建连接
con.setAutoCommit(false);// 3. 不自动提交,开始事务
conn.setReadOnly(true);// 4. 设定只读,或者其他连接设定
String sql = "insert into t_user(userName,pwd)values(?,?)"; // 需要执行的sql语句
ps = conn.prepareStatement( sql );// 5. 在不同的statement中设置需要执行的sql语句
ps.setObject(1, "小高" + i);// 6. 预编译,参数设置
ps.setObject(2, "123");
ps.execute(); // 7. 执行语句
// 8. 如果是查询插座,对查询结果进行操作
con.commit(); // 9. 提交
} catch (ClassNotFoundException e) {
con.rollback(); // 9, 回滚
e.printStackTrace();
} catch (SQLException e) {
con.rollback(); // 9. 回滚
e.printStackTrace();
} finally{
try {
if (ps!=null) {
ps.close(); // 10. 资源释放
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (conn!=null) {
conn.close(); // 10. 资源释放
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
连接池 | 事务管理器 | 持久 | |
---|---|---|---|
1 | 注册驱动 | ||
2 | 创建连接 | ||
3 | 不自动提交,开始事务 | ||
4 | 设定只读,或者其他连接设定 | ||
5 | 在不同的statement中设置需要执行的sql语句 | ||
6 | 预编译,参数设置 | ||
7 | 执行语句 | ||
8 | 如果是查询操作,对查询结果进行操作 | ||
9 | 提交或者回滚 | ||
10 | 资源释放 | 资源释放 |
// 时序图
spring事务体系
- 事务管理器
- 事务Interceptor
- spring-boot如何启动事务
事务管理器
<! ------------------------- 无情分割线 --------------------------------------------------->
下面声明了TransactionStatus的接口, 实现了TransactionStatus的抽象类AbstractTransactionStatus,还有AbstractTransactionStatus的子类DefaultTransactionStatus与内部类TransactionInfo,其实只需要TransactionInfo一个类就行了,上面几个类的细节不讲述了。
为什么spring-tx需要设计那么多类了。其实就是为了实现spring中一个很鸡肋的功能,事务传播功能。为了实现事务传播功能的设计,代码还有很多,本人非常不喜欢这个功能,所以不会讲述事务传播的细节,如果有读者想了解,可以依据本接内容为基本自行扩展。 为什么spring-tx需要设计那么多类了。其实就是为了实现spring中一个很鸡肋的功能,事务传播功能。为了实现事务传播功能的设计,代码还有很多,本人非常不喜欢这个功能,所以不会讲述事务传播的细节,如果有读者想了解,可以依据本接内容为基本自行扩展。 为什么spring-tx需要设计那么多类了。其实就是为了实现spring中一个很鸡肋的功能,事务传播功能。为了实现事务传播功能的设计,代码还有很多,本人非常不喜欢这个功能,所以不会讲述事务传播的细节,如果有读者想了解,可以依据本接内容为基本自行扩展。
public abstract class AbstractTransactionStatus implements TransactionStatus {
private boolean rollbackOnly = false;
private boolean completed = false;
@Nullable
private Object savepoint
}
public class DefaultTransactionStatus extends AbstractTransactionStatus {
@Nullable
private final Object transaction;
private final boolean newTransaction;
private final boolean newSynchronization;
private final boolean readOnly;
private final boolean debug;
@Nullable
private final Object suspendedResources;
}
protected final class TransactionInfo {
@Nullable
private final PlatformTransactionManager transactionManager;
@Nullable
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
@Nullable
private TransactionStatus transactionStatus;
@Nullable
private TransactionInfo oldTransactionInfo;
}
<! ------------------------- 无情分割线结束 --------------------------------------------------->
spring事务的核心体系是PlatformTransactionManager以及实现了DataSourceTransactionManager(数据源事务管理器,比如mybatis,spring-jdbc),JpaTransactionManager(Jpa事务管理器),HibernateTransactionManager(hibernate5事务管理器)。本节直接讲解DataSourceTransactionManager,其他的管理器使用场景非常少不做讲解了。
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
- getTransaction[ 获得事务 ]
- commit[ 提交事务 ]
- rollback [ 回滚事务 ]
看下这个方法的调用流程,就很容易懂了。一些其他的代码就不要看了,基本是为了jta做了准备
事务Interceptor
TransactionInterceptor 只做了一件事情调用了父类TransactionAspectSupport的invokeWithinTransaction方法,那么大家把注意力放到TransactionAspectSupport的invokeWithinTransaction方法上吧
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
// PlatformTransactionManager 事务管理
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
}
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// 得到对象与方法上的Transactio注解
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
// 得到事务管理器,@Transactio注解变量transactionManager,可以指定这个事务由那个事务管理器执行。
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
//开启事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 执行方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 清理TransactionInfo
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
......
}
}
protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
// 如果 条件成立,返回默认事务管理器
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
// 获得 事务管理器的名字
String qualifier = txAttr.getQualifier();
// 如果有
if (StringUtils.hasText(qualifier)) {
// 通过事务管理器的名字获得事务管理器,
return determineQualifiedTransactionManager(qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
// 默认管理器名字获得管理器
return determineQualifiedTransactionManager(this.transactionManagerBeanName);
}
else {
// 获得默认管理器
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
return defaultTransactionManager;
}
}
// 通过事务管理器的名字获得事务管理器
private PlatformTransactionManager determineQualifiedTransactionManager(String qualifier) {
PlatformTransactionManager txManager = this.transactionManagerCache.get(qualifier);
if (txManager == null) {
txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
this.beanFactory, PlatformTransactionManager.class, qualifier);
this.transactionManagerCache.putIfAbsent(qualifier, txManager);
}
return txManager;
}
spring-boot如何启动事务
spring-boot启动事务很简单只需要EnableTransactionManagement注解或者TransactionManagementConfigurationSelector被ApplicationContext加载,那么就会自动启动事务。详细请看下面的流程
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
// 创建Advisor
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// 创建 注解识别
advisor.setTransactionAttributeSource(transactionAttributeSource());
// 创建方法拦截器与处理器
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
总结
事务真的很简单,但是为了做很多的兼容于扩展,spring-tx写得很复杂。个人感觉在分布式的微服务框架设计下,很多都不应该要了。