0.环境准备
0.1 安装mysql
版本:mysql-installer-community-5.6.41.0.msi
账号/密码:root/root
端口:3307
0.2 在数据库test下创建表test
CREATE TABLE order_tbl(
orderid INT NOT NULL AUTO_INCREMENT,
ordertime datetime DEFAULT NULL,
ordermoney decimal(20,0) DEFAULT NULL,
orderstatus char(1) DEFAULT NULL,
PRIMARY KEY(orderid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
在创建表的时候,发生error 1064 (42000)错误,是因为order是关键字,所以改为order_tbl,在mysql中使用与关键字同名的名字时,可以使用反引号(` `):
0.3 使用相应的第三方组件
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.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>5.0.6.RELEASE</version>
</dependency>
0.4 使用c3p0在配置类中创建数据源
@Configuration
@ComponentScan("com.wangzhen.ch11")
public class Ch11MainConfig {
//创建数据源
@Bean
public DataSource dataSource() throws PropertyVetoException {
//这个c3p0封装了JDBC, dataSource接口的实现
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3307/test");
return dataSource;
}
//jdbcTemplate能简化增删改查的操作
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException{
return new JdbcTemplate(dataSource());
}
}
0.5 业务类
- 具体的数据库插入语句
@Repository
public class OrderDao {
@Autowired
private JdbcTemplate jdbcTemplate;
//操作数据的方法
public void insert(){
String sql = "insert into order_tbl (ordertime, ordermoney, orderstatus) values(?,?,?)";
jdbcTemplate.update(sql,new Date(),20,0);
}
}
- service向外提供服务
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
public void addOrder(){
orderDao.insert();
System.out.println("操作完成.........");
}
}
0.6 测试
public class Ch11Test {
@Test
public void test01() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch11MainConfig.class);
OrderService bean = app.getBean(OrderService.class);
bean.addOrder();
app.close();
}
}
结果:
1.事务处理
- @EnableTransactionalManagement开启基于注解的事务管理功能
- 将事务管理器的bean加载到容器中(DataSourceTransactionManager)
@Configuration
@ComponentScan("com.wangzhen.ch11")
@EnableTransactionManagement
public class Ch11MainConfig {
//创建数据源
@Bean
public DataSource dataSource() throws PropertyVetoException {
//这个c3p0封装了JDBC, dataSource接口的实现
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser("root");
dataSource.setPassword("root");
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3307/test");
return dataSource;
}
//jdbcTemplate能简化增删改查的操作
@Bean
public JdbcTemplate jdbcTemplate() throws PropertyVetoException{
return new JdbcTemplate(dataSource());
}
//注册事务管理器
@Bean
public PlatformTransactionManager platformTransactionManager() throws PropertyVetoException{
return new DataSourceTransactionManager(dataSource());
}
}
- 给OrderService添加事务
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Transactional
public void addOrder(){
orderDao.insert();
System.out.println("操作完成.........");
int a = 1/0;
}
}
-
事务执行结果
2.事务管理源码分析
2.1 @EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
TransactionManagementConfigurationSelector给容器导入两个组件:
- AutoProxyRegistrar
- ProxyTransactionManagementConfiguration
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
-
selectImports执行时机(调用栈)
2.2 AutoProxyRegistrar
* @author Chris Beams
* @since 3.1
* @see EnableAspectJAutoProxy
*/
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
-
registerBeanDefinitions执行时机(调用栈)
在该方法中注册了一个新的组件:InfrastructureAdvisorAutoProxyCreator。是基本的动态代理创建器。其beanName为org.springframework.aop.config.internalAutoProxyCreator。
利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用。
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
-
调用栈如下
2.2.1 InfrastructureAdvisorAutoProxyCreator
2.3 ProxyTransactionManagementConfiguration
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
2.3.1 AnnotationTransactionAttributeSource
事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解。
2.3.2 事务拦截器TransactionInterceptor
TransactionInterceptor保存了事务属性信息和事务管理器,是一个 MethodInterceptor。
在目标方法执行的时候:
- 执行拦截器链;
- 事务拦截器:
1)先获取事务相关的属性
2)再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger最终会从容器中按照类型获取一个PlatformTransactionManager;
3)执行目标方法
如果异常,获取到事务管理器,利用事务管理回滚操作;
如果正常,利用事务管理器,提交事务
事务处理的关键方法:
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
调用栈:
3.Spring事务总结
参考
- 1)享学课堂James老师笔记
- 2)享学课堂zhq同学