简单使用
配置类
package jane.tx;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/*
* 声明式事务:
* 环境搭建:
* 1.导入相关的依赖:数据源,数据库驱动,spring-jdbc模块
* 2.配置数据源,JdbcTemplate操作数据
* 3.给方法上标注@Transactional,表示当前是一个事务方法
* 4.@EnableTransactionManagement开启基于注解的事务管理功能
*/
@EnableTransactionManagement
@ComponentScan({"jane.tx"})
@Configuration
public class MyConfigOftx
{
//数据源
@Bean
public DataSource dataSource() throws Exception
{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("1234");
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate() throws Exception
{
//spring对@Configuration类会特殊处理,
//给容器中加组件的方法,多次调用都只是从容器中找组件,不会多次创建对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
return jdbcTemplate;
}
//注册事务管理器在容器中
@Bean
public PlatformTransactionManager transactionManager() throws Exception
{
return new DataSourceTransactionManager(dataSource());
}
}
Dao和Service
package jane.tx;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao
{
@Autowired
JdbcTemplate jdbcTemplate;
public void insert()
{
String sql="insert into user (name ,age) values (?,?)";
String name = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql,name,18 );
}
}
package jane.tx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService
{
@Autowired
UserDao userDao;
@Transactional
public void insertUser()
{
userDao.insert();
System.out.println("插入成功");
int i=10/0;
}
}
@Test
public void testTX()
{
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfigOftx.class);
UserService userService = applicationContext.getBean(UserService.class);
JdbcTemplate bean = applicationContext.getBean(JdbcTemplate.class);
System.out.println(bean);
System.out.println(userService);
userService.insertUser();
System.out.println("容器关闭");
applicationContext.close();
}
原码解析
点进@EnableTransactionManagement查看
@Import(TransactionManagementConfigurationSelector.class)
里面导入了一个Selector
利用TransactionManagementConfigurationSelector给容器中导入组件
看AdviceMode的属性导入不同的组件,看上面的一张截图
AdviceMode mode() default AdviceMode.PROXY;默认是PROXY
所以就会导入两个组件
AutoProxyRegistrar
ProxyTransactionManagementConfiguration
AutoProxyRegistrar
点进去AutoProxyRegistrar,它也是给容器注册组件的
点进AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
注册了一个InfrastructureAdvisorAutoProxyCreator的组件
你看下面的AnnotationAwareAspectJAutoProxyCreator
,这不是AOP时候注册的组件吗?
InfrastructureAdvisorAutoProxyCreator和之前的AOP一样,也是一个后置处理器
InfrastructureAdvisorAutoProxyCreator
点进InfrastructureAdvisorAutoProxyCreator
查看
可以发现它没干什么,主要是利用后置处理器机制在创建对象之后包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用
ProxyTransactionManagementConfiguration
点进ProxyTransactionManagementConfiguration
给容器注册了事务增强器,
事务增强器需要一个transactionAttributeSource()
事务注解信息,解析事务注解
这个对象是AnnotationTransactionAttributeSource();
它是SpringTransactionAnnotationParser(spring的解析器)
JtaTransactionAnnotationParser(Jta解析器)
Ejb3TransactionAnnotationParser(Ejb3解析器)
这些解析器主要是解析注解能写的属性
事务增强器还需要一个事务拦截器transactionInterceptor()
TransactionInterceptor保存了事务属性信息和事务管理器
点进TransactionInterceptor,发现它是一个MethodInterceptor,AOP的时候所有的增强器都会包装成MethodInterceptor
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
进入TransactionInterceptor,invoke()方法的
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback()
方法
首先执行拦截器链,拦截器链里面就只有TransactionInterceptor一个拦截器
事务拦截器工作流程:
1)先获取事务相关的属性
2)再获取PlatformTransactionManager,如果事先没有指定任何的TransactionManager
最终会从容器中按照类型获取一个PlatformTransactionManager
3)执行目标方法
如果异常,获取事务管理器,利用事务管理器回滚
如果正常利用事务管理器提交事务