Spring注解驱动
声明式事务
一、环境搭建
1、导入相关依赖
数据源、数据库驱动、Spring-jdbc模块
2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据库
导入相关依赖:
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
配置文件:
db.user=root
db.password=00000
db.url=jdbc:mysql://localhost:3306/
db.driverClass=com.mysql.jdbc.Driver
配置类:
@PropertySource("classpath:/dbconfig.properties")
@Configuration
@ComponentScan("com.achang.tx")
public class TxConfig {
@Value("${db.user}")
private String user;
@Value("${db.password}")
private String pwd;
@Value("${db.driverClass}")
private String driverClass;
//数据源
@Bean
public DataSource dataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate;
}
}
dao类:
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
String sql ="INSERT INTO tbl_user(username,age) VALUES(?,?)";
String username = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql,username,20);
}
}
service类:
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void insertUser(){
userDao.insert();
int i = 10 / 0; //出现异常后 方法不会回滚
System.out.println("插入成功");
}
}
测试类:
public class IOCTest_tx {
@Test
public void test01(){
//创建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.insertUser();
}
}
二、开启事务
开启事务流程:
1、开启事务管理功能 标注@EnableTransactionManagement
2、给需要加事务的方法上标注@Transactional
3、在配置类中,配置事务管理器,来控制事务
- 在配置类上标注
@EnableTransactionManagement
@EnableTransactionManagement
public class TxConfig {}
- 给需要加事务的方法标注
@Transactional
@Transactional
public void insertUser(){
userDao.insert();
int i = 10 / 1;
System.out.println("插入成功");
- 在配置类中,
配置事务管理器
,来控制事务
//注册事务管理器在容器中
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);//要加入数据源,控制数据源
}
三、源码分析
事务管理通过AOP机制实现
1、@EnableTransactionManagement
利用 TransactionManagementConfigurationSelector 给容器中导入组件
导入两个组件:
AutoProxyRegistrar
ProxyTransactionManagementConfiguration
2、AutoProxyRegistrar:
给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件
InfrastructureAdvisorAutoProxyCreator: ?
利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
3、ProxyTransactionManagementConfiguration
1)、给容器中注册 事务增强器
①事务增强器要用事务注解的信息
AnnotationTransactionAttributeSource 解析事务注解
②事务拦截器:
TransactionInterceptor 保存了事务的属性信息,事务管理器
他是一个MethodInterceptor
在目标方法执行的时候:
执行拦截器链;
事务拦截器TransactionInterceptor
1、先获取事务相关的属性
2、再获取PlatformTransactionManager事务管理器;
如果事先没有添加指定任何TransactionManager
最终会从容器中按照类型获取一个PlatformTransactionManager
3、执行目标方法:
如果异常,获取到事务管理器,利用事务管理器回滚这次操作
如果正常,利用事务管理器,提交事务
总结
通过@EnableTransactionManagement
注解会为容器中导入AutoProxyRegistrar
、ProxyTransactionManagementConfiguration
两个组件;
AutoProxyRegistrar会给容器再注册InfrastructureAdvisorAutoProxyCreator
组件,利用后置处理器在对象创建以后,将包装对象
,并返回一个代理对象
(增强器),返回的代理对象执行方法利用拦截器链调用
;
ProxyTransactionManagementConfiguration会给容器中注册事务增强器
,并给其获取解析事务注解的信息
;同时也用事务拦截器先获取事务相关属性
,再获取PlatformTransactionManager事务管理器
,再执行目标方法
,如果异常就回滚操作
,正常
则利用事务管理器提交事务
。
感谢尚硅谷