一、定义
二、核心概念
1、@EnableTransactionManager
作用:在Spring开启事务功能。
2、数据源DataSource
A、Spring的DataSource种类
- org.springframework.jdbc.datasource.DriverManagerDataSource
DriverManagerDataSource建立连接是只要有连接就新建一个connection,根本没有连接池的作用。
- org.apache.commons.dbcp.BasicDataSource
BasicDataSource是一种推荐的数据源配置方式,它真正使用了连接池技术
- org.springframework.jndi.JndiObjectFactoryBean
JndiObjectFactoryBean能够通过JNDI获取DataSource,但要在web server中配置数据源,不方便于部署
B、DataSource的配置
3、事务管理器TransactionManager
A、TransactionManager的种类
B、TransactionManager的使用
4、@Transactional
A、作用
用@Transactional注解声明某个类或者某个方法具备事务功能。
B、失效场景
- 开启事务、执行sql、回滚sql不是同一个连接
- 目标方法不是公共方法
- 抛出的异常被try{}catch住
- 只有RuntimeException及其子类会默认回滚,除此之外的异常需要手动指定rollbackForClassName
- 在同个类中,一个没有事务的方法内部调用另一个有事务的方法
解决方法:
a、把有事务的方法提到另一个类
b、自己注入自己,然后用这个注入的类调取这个有事务的方法。
参考地址:https://blog.csdn.net/qq_45607784/article/details/134897741
三、原理
1、认识
2、总体流程
a、前置准备
有一个SysConfig类使用了@EnableTransactionManangement和@Configuration注解进行声明,类里面使用@Bean注解声明了DataSource、TestAopMethod类的bean信息。TestAopMethod里有一个testTransaction方法声明了@Transactional注解。
@EnableTransactionManagement
@Configuration
// 实现TransactionManagementConfigurer接口可以重新设置TransactionManagement
public class SysConfig
{
@Bean
DataSource dataSource() {
CustomDataSource dataSource = new CustomDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://xxx:xxx/xxx?characterEncoding=utf-8&useSSL=false");
dataSource.setUsername("xxx");
dataSource.setPassword("xxx");
return dataSource;
}
@Bean
DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public TestAopMethod testAopMethod() {
return new TestAopMethod();
}
}
public class CustomDataSource extends DriverManagerDataSource {
private Connection conn;
@Override
public Connection getConnection() throws SQLException {
if(conn==null){
// 保证同个连接
conn=super.getConnection();
}
return conn;
}
}
public class TestAopMethod {
@Transactional
public void testTransaction(DataSource ds) throws SQLException {
Connection conn=ds.getConnection();
Statement sm=conn.createStatement();
ResultSet res=sm.executeQuery("SELECT * FROM label");
while(res.next()){
System.out.println(res.getString("name"));
}
res.close();
sm.close();
conn.close();
System.out.println("I AM TESTTRANSACTION");
}
}
public static void main(String[] args) throws SQLException {
AnnotationConfigApplicationContext context1=new AnnotationConfigApplicationContext(SysConfig.class);
TestAopMethod obj= (TestAopMethod) context1.getBean("testAopMethod");
DataSource ds= (DataSource) context1.getBean("dataSource");
obj.testTransactionAboutInsert(ds);
}
b、Spring事务执行过程
(1)启动容器
(2)创建并初始化容器
添加ConfigurationClassPostProcessor类的bean信息到容器中
(3)添加配置类SysConfig的bean信息到容器中
(4)容器刷新
a、调用invokeBeanFactoryPostProcessor方法解析SysConfig配置类上标注的@EnableTransactionManagement注解,真正解析的是里面的@Import注解,调用@Import注解的TransactionManagementConfigurationSelector类的selectImports方法,该方法会返回AutoProxyRegistrar和ProxyTransactionManagementConfiguration的Bean信息。根据返回的bean信息继续解析ProxyTransactionManagementConfiguration bean信息里面声明了@Bean注解的方法,即BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource、TransactionInterceptor这3个bean信息。BeanFactoryTransactionAttributeSourceAdvisor是Spring AOP的Advisor的实现类,包含AnnotationTransactionAttributeSource和通知TransactionInterceptor,而BeanFactoryTransactionAttributeSourceAdvisor里面的切点TransactionAttributeSourcePointcut是通过getTransactionAttributeSourcePointcut方法获得,方法内容是返回AnnotationTransactionAttributeSource实例。接着会通过loadBeanDefinitionFromRegistrars方法执行AutoProxyRegistrar类的registerBeanDefinitions方法。该方法会向容器中添加InfrastructureAdvisorAutoProxyCreator的bean信息。
b、调用finishBeanFactoryInitialization方法实例化所有非懒加载的bean信息。该方法的核心是调用容器的getBean方法。
在getBean方法对bean实例进行applyBeanPostProcessorsAfterInitialization初始化后处理阶段,会在这个阶段调用InfrastructureAdvisorAutoProxyCreator的postProcessAfterInitialization方法,该方法是创建那些声明了@Transactional注解的类的代理对象。这里实际调用的是InfrastructureAdvisorAutoProxyCreator的祖父类AbstractAutoProxyCreator的postProcessAfterInitialization方法。该方法里面的核心逻辑是执行wrapIfNecessary方法。wrapIfNecessary方法会去执行findAdvisorBeans方法来找到所有isEligibleBean方法为true的Advisor实现类。这里实际调用的是InfrastructureAdvisorAutoProxyCreator的isEligibleBean方法,它的判断逻辑是Bean信息上是否声明了role属性BeanDefinition.ROLE_INFRASTRUCTURE(即声明了@Role注解,且value为BeanDefinition.ROLE_INFRASTRUCTURE)。找到所有Advisor实现类后,会去调用findAdvisorsThatCanApply筛出切入点和bean实例符合的Advisor实现类。筛选方式是调用PointCut实现类的内部类ClassFilter的matches方法是否为true,这里是调用TransactionAttributeSourcePointCut里面的内部类TransactionAttributeSourceClassFilter的matches方法。该matches方法会去调用Advisor实现类的切入点TransactionAttributeSource的isCandidateClass方法,即实际调用的是AnnotationTransactionAttributeSource的isCandidateClass方法,该isCandidateClass的核心逻辑是执行TransactionAnnotationParser的isCandidateClass方法。这里的默认TransactionAnnotationParser是SpringTransactionAnnotationParser类。而SpringTransactionAnnotationParser类的isCandidateClass方法是判断目标类是否声明了@Transactional注解。找到符合条件的Advisor实现类后,就会基于这些实现类创建代理对象,代理方法内容是对目标方法使用环绕通知TransactionInterceptor。
(5)调用容器的getBean方法获取TestAopMethod实例
(6)执行TestAopMethod实例的testTransactional方法,这里实际上是执行TestAopMethod代理对象的testTransactional方法。真正执行的是TransactionInterceptor的invoke方法(这个invoke方法已经合成在代理对象中),该方法的核心是invokeWithTransaction方法,该方法对目标方法的增强方式是在目标方法前开启事务,在目标方法后关闭事务,出现异常会回滚事务