既然讲spring事务源码分析,想必读者都知道什么是事务吧!包括事务四大特性ACID,4大隔离级别。笔者就不详细讲这些简单的知识了,简单列一下事务的概念。
进入正题
spring并不直接管理事务,而是提供了多种事务管理器,他们将事务的管理职责委托给Hibernate或JTA等持久化机制所提供的相关平台框架的事务来实现。通过这个接口,spring为各个平台如JDBC、Hibernate等提供了对应的事务管理器,但是事务的实现就是各平台自己的事情了。
public interface PlatformTransactionManager {
//根据事务定义TransactionDefinition,获取事务
TransactionStatus getTransaction(TransactionDefinition definition);
//提交事务
void commit(TransactionStatus status);
//回滚事务
void rollback(TransactionStatus status);
}
该接口定义了5个方法以及一些表示事务属性的常量。
public interface TransactionDefinition {
/**
* 传播行为值
*/
//当前如果有事务,Spring就会使用该事务; 否则会开始一个新事务
int PROPAGATION_REQUIRED = 0;
//当前如果有事务,Spring就会使用该事务;否则不会开始一个新事务
int PROPAGATION_SUPPORTS = 1;
//当前如果有事务,Spring就会使用该事务;否则会抛出异常
int PROPAGATION_MANDATORY = 2;
//Spring总是开始一个新事务。如果当前有事务,则该事务挂起
int PROPAGATION_REQUIRES_NEW = 3;
//Spring不会执行事务中的代码。代码总是在非事务环境下执行,如果当前有事务,则该事务挂起
int PROPAGATION_NOT_SUPPORTED = 4;
//即使当前有事务,Spring也会在非事务环境下执行。如果当前有事务,则抛出异常
int PROPAGATION_NEVER = 5;
//如果当前有事务,则在嵌套事务中执行。如果没有,那么执行情况与
//Transaction- Definition.PROPAGATION_REQUIRED一样
int PROPAGATION_NESTED = 6;
/**
* 隔离级别
*/
//默认隔离级别(对大多数数据库来说就是ISOLATION_ READ_COMMITTED)
int ISOLATION_DEFAULT = -1;
//最低的隔离级别。事实上我们不应该称其为隔离级别,因为在事务完成前,
//其他事务可以看到该事务所修改的数据。
//而在其他事务提交前,该事务也可以看到其他事务所做的修改
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
//大多数数据库的默认级别。在事务完成前,其他事务无法看到该事务所修改的数据。
//遗憾的是,在该事务提交后,你就可以查看其他事务插入或更新的数据。
// 这意味着在事务的不同点上,如果其他事务修改了数据,你就会看到不同的数据
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
//该隔离级别确保如果在事务中查询了某个数据集,你至少还能再次查询到相同的
// 数据集,即使其他事务修改了所查询的数据。
//然而如果其他事务插入了新数据,你就可以查询到该新插入的数据
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
//代价最大、可靠性最高的隔离级别,所有的事务都是按顺序一个接一个地执行
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
//默认事务的超时时间
int TIMEOUT_DEFAULT = -1;
//获取事务的传播行为
int getPropagationBehavior();
//获取事务的隔离级别
int getIsolationLevel();
//获取超时时间
int getTimeout();
//是否只读
boolean isReadOnly();
//事务名称
@Nullable
String getName();
}
记录事务的状态,该接口定义了一组方法,用来获取或判断事务相应状态信息。PlatformTransactionManager.getTransaction(TransactionDefinition definition);方法返回一个TransactionStatus对象,该对象可能代表一个新的或已经存在的事务(如果在当前调用堆栈有一个符合条件的事务)。
public interface TransactionStatus extends SavepointManager, Flushable {
//获取是否是新事务
boolean isNewTransaction();
//获取是否存在保存点
boolean hasSavepoint();
//设置事务回滚
void setRollbackOnly();
//获取是否回滚
boolean isRollbackOnly();
//刷新事务
@Override
void flush();
//获取事务是否完成
boolean isCompleted();
}
老规矩,先祭出我们的测试代码!为源码讲解做准备。
配置类,注意,我们添加了@EnableTransactionManagement
注解
@ComponentScan("com.config.transaction")
@Configuration
@EnableAspectJAutoProxy
@EnableTransactionManagement
public class Config {
}
数据源
@Configuration
@MapperScan("com.config.transaction")
public class DaoConfig {
private String driverClass = "com.mysql.jdbc.Driver";
private String username="root";
private String password="123456";
private String url="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong";
//注册数据源
@Bean
public DataSource getDataSorce() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
/**
* 获取sessionFactory
*/
@Bean
public SqlSessionFactory getSqlSessionFactory() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(getDataSorce());
return sqlSessionFactoryBean.getObject();
}
//注册jdbc事务管理器
@Bean
public TransactionManager getTrans() throws Exception {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(getDataSorce());
return transactionManager;
}
}
mybatis的Mapper
@Mapper
public interface DaoMapper {
@Insert("insert into user values(1,'name')")
public void add();
}
业务逻辑,注意,我们添加了@Transactional
事务注解
@Service
@Transactional(propagation= Propagation.REQUIRED,isolation = Isolation.DEFAULT)
public class ServiceImpl {
@Autowired
DaoMapper daoMapper;
public void add(){
daoMapper.add();
System.out.println("add");
}
public void del(){
System.out.println("del");
}
}
测试类
public class SpringTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Config.class);
context.refresh();
ServiceImpl serviceImpl = context.getBean(ServiceImpl.class);
serviceImpl.add();
}
}
OK,运行上面的测试类,就能往数据库添加一条记录。
本文,就来讲讲事务的源码。注意,源码的讲解,需要你知道循环依赖源码和AOP源码,前面的博文我们详细讲解了,本文会直接定位到AOP源码处,不再讲解前置知识,详细参见《spring循环依赖源码讲解》和《AOP源码讲解》。
以debug模式运行上面的测试类:
我们在ServiceImpl业务类上加了@Transactional
注解,调试代码发现,ServiceImpl类生成的实例被CGLIB动态代理了。
我们去掉@Transactional
注解再看看:
此时的实例,没有被CGLIB动态代理。好,这就说明,事务是通过AOP的方式实现的。
所以,研究spring事务源码,就是研究事务是怎么通过AOP实现的,没问题吧?
先写到这,读者先去自行分析。没阅读过循环依赖和AOP源码的,赶紧回去看,不然你听不懂。