环境准备
1、准备配置环境pom.xml包导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
注:这里只导入本次使用的包,其他的基础包不包含
2、设置数据库连接DataSource(数据源)和数据库连接驱动Driver
@Bean
DataSource getDataSource() throws Exception {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai";
//username=root
//password=123456
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setJdbcUrl(url);
dataSource.setDriverClass(driver);
return dataSource;
}
@Bean
JdbcTemplate initJdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate;
}
3、测试时使用jdbcTemplate进行
4、要想方法具备事务功能,首先给方法加上@Transactional,那加上这个注解就起作用了吗?否
5、需要告诉spring容器,我要开启事务功能,并且你把事务相关的依赖组件帮我加载好;所以在配置类上面需要加上@EnableTransactionManagement注解
开启事务(开启基于注解的事务) <tx:annotation-driven transaction-manager="transactionManager"/> 这个注解开启相当于xml配置的功能
6、由于开启了事务,在spring容器加载的时候,事务肯定需要某个东西管理,所以这里需要定义一个事务管理器,然后持有数据源(这样就可以控制数据源里面的是事务功能)
//事务管理器(把数据库连接交给他管理)
@Bean
TransactionManager getTransactionMa(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
一切准备就绪后,开始测试
@Repository
public class OrderDao {
@Autowired
JdbcTemplate jdbcTemplate;
public void saveOrder() {
String sql = "insert into `order`(id,id_product,`name`) values(?,?,?)";
jdbcTemplate.update(sql, UUID.randomUUID().toString().replace("-",""),"1","奥尼啊");
}
}
@Service
public class UserService {
@Autowired
private OrderDao orderDao;
//如果这个方法抛出异常了,事务是会进行回滚的
@Transactional
public void addUser(){
orderDao.saveOrder();
}
}
/**
* 1、导入依赖jar包
* <dependency>
* <groupId>org.springframework.boot</groupId>
* <artifactId>spring-boot-starter-jdbc</artifactId>
* </dependency>
* <dependency>
* <!--数据库连接池-->
* <groupId>c3p0</groupId>
* <artifactId>c3p0</artifactId>
* <version>0.9.1.2</version>
* </dependency>
* 2、设置数据源、数据库驱动
* 3、配置数据源,使用JdbcTemplate(测试)
* 4、给方法上加入@Transactional注解,表示为事务方法
* 5、需要开启事务管理功能@EnableTransactionManagement
* 6、配置事务管理器,来管理事务,因为事务管理器需要持有数据库连接,只有拿到数据库连接才能控制实现对连接的
* 提交还是回滚
*/
@Configuration
@ComponentScan("com.tractional")
@EnableTransactionManagement//开启事务(开启基于注解的事务) <tx:annotation-driven transaction-manager="transactionManager"/>
public class TxConfig {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
UserService userService = context.getBean(UserService.class);
userService.addUser();
}
//事务管理器(把数据库连接交给他管理)
@Bean
TransactionManager getTransactionMa(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
DataSource getDataSource() throws Exception {
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai";
//username=root
//password=123456
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("123456");
dataSource.setJdbcUrl(url);
dataSource.setDriverClass(driver);
return dataSource;
}
@Bean
JdbcTemplate initJdbcTemplate(DataSource dataSource) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
return jdbcTemplate;
}
}
到此为止,针对声明式事务的使用就OK了;
问???事务是如何起作用的,分析一下spring源码底层如何实现的?
【下面是思路,不是对源码一句一句代码进行分析,那样没意义:学源码学的是思想和人家的实现步骤,并不说去研究人家代码怎么写】
/**
* 声明式事务实现原理
* 1、只有开启了声明式事务,事务才会起作用
* @see EnableTransactionManagement //@EnableTransactionManagement
* 在注解EnableTransactionManagement中导入了@Import(TransactionManagementConfigurationSelector.class)
* 利用TransactionManagementConfigurationSelector给容器导入组件(实现了ImportSelector接口)
* 默认是AdviceMode为AdviceMode.PROXY
* 所以导入了2个组件AutoProxyRegistrar和ProxyTransactionManagementConfiguration
* 如果AdviceMode为AdviceMode.ASPECTJ(切面)
* 导入组件AspectJJtaTransactionManagementConfiguration和AspectJTransactionManagementConfiguration
* 2、AutoProxyRegistrar 干了什么事情【给容器注册了一个InfrastructureAdvisorAutoProxyCreator组件】
* AutoProxyRegistrar implements ImportBeanDefinitionRegistrar
* 通过 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)给容器注册了一个InfrastructureAdvisorAutoProxyCreator组件
* InfrastructureAdvisorAutoProxyCreator 又是做什么的呢?
* InfrastructureAdvisorAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor,BeanPostProcessor 后置处理器
* org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
* 实现了这个方法 public Object postProcessAfterInitialization--这个在bean的后置处理器,
* 也就是bean-InfrastructureAdvisorAutoProxyCreator创建完成后做的事情
* public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
* if (bean != null) {
* Object cacheKey = getCacheKey(bean.getClass(), beanName);
* if (this.earlyProxyReferences.remove(cacheKey) != bean) {
* return wrapIfNecessary(bean, beanName, cacheKey);
* }
* }
* return bean;
* }
* 利用bean的后置处理器在对象创建后,包装一个对象,返回一个代理对象(可以理解为是加了其他功能的增强对象),代理对象
* 执行方法利用拦截器链的模式进行拦截处理(跟AOP思想一模一样)
* 3、ProxyTransactionManagementConfiguration 干了什么事情
* @Configuration(proxyBeanMethods = false) 它是一个配置类
* 1)、给容器注册transactionAdvisor:BeanFactoryTransactionAttributeSourceAdvisor事务增强器
* 1)、需要事务属性transactionAttributeSource
* 2)、事务拦截器transactionInterceptor
* 2)、transactionAttributeSource:AnnotationTransactionAttributeSource 注解属性(用于解析@Transactional注解)
* 3)、transactionInterceptor 事务拦截器
* TransactionInterceptor implements MethodInterceptor(也就是他是一个方法拦截器)
* 需要设置interceptor.setTransactionManager(this.txManager)
* txManager是通过ImportAware设置,importMetadata.getAnnotationAttributes(EnableTransactionManagement)
* 通过TransactionAspectSupport.determineTransactionManager
* beanFactory.getBean(TransactionManager.class)去找,找到了就缓存起来,也就是事务管理器,只要我们定义好bean注册到spring容器,这里就
* 拿得到咯
* 1)、transactionAttributeSource 注解属性
* 2)、TransactionManager 事务管理器
* TransactionInterceptor--》invoke(MethodInvocation invocation)
* --》invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed)
* org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction核心方法,利用事务进行工作
* 3)、事务处理 PlatformTransactionManager implements TransactionManager
* 获取一个事务:TransactionManager.getTransaction(txAttr)
* 事务提交:TransactionInfo.getTransactionManager().commit(txInfo.getTransactionStatus())
* 回滚事务:TransactionInfo.getTransactionManager().rollback(txInfo.getTransactionStatus())
* 4)、执行目标方法
* 1)、如果没有异常,利用事务管理器的commit方法,提交事务
* 2)、如果有异常,利用事务管理器的rollback,回滚事务
*
* 【实现原理跟https://blog.csdn.net/qqzhengwei/article/details/112788609】AOP的原理是一样的
*
*/