Simple to use
Configuration class
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 and 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();
}
Source code analysis
Click into @EnableTransactionManagement to see
@Import(TransactionManagementConfigurationSelector.class)
that a Selector is imported
Use TransactionManagementConfigurationSelector to import components into the container.
Look at the properties of AdviceMode to import different components. See the screenshot above
AdviceMode mode() default AdviceMode.PROXY; the default is PROXY,
so two components will be imported
AutoProxyRegistrar
ProxyTransactionManagementConfiguration
AutoProxyRegistrar
Click in to AutoProxyRegistrar, which is also to register components for the container.
Click in AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); one is
registered. InfrastructureAdvisorAutoProxyCreator的组件
Look at the following AnnotationAwareAspectJAutoProxyCreator
, isn't this the component registered during AOP?
InfrastructureAdvisorAutoProxyCreator, like the previous AOP, is also a post processor
InfrastructureAdvisorAutoProxyCreator
Click to InfrastructureAdvisorAutoProxyCreator
view and
you can find that it doesn't do much, mainly using the post-processor mechanism to wrap the object after creating the object, and return a proxy object (enhancer), and the proxy object execution method is called using the interceptor chain
ProxyTransactionManagementConfiguration
Click ProxyTransactionManagementConfiguration
to register the transaction enhancer to the container,
Transaction enhancer needs onetransactionAttributeSource()
Transaction annotation information, parsing transaction annotations.
This object is AnnotationTransactionAttributeSource();
it is SpringTransactionAnnotationParser (spring parser)
JtaTransactionAnnotationParser (Jta parser)
Ejb3TransactionAnnotationParser (Ejb3 parser)
These parsers are mainly used to analyze the attributes that can be written by annotations
Transaction enhancer also needs a transaction interceptortransactionInterceptor()
TransactionInterceptor saves transaction attribute information and transaction manager.
Click into TransactionInterceptor and find that it is a MethodInterceptor. In AOP, all enhancers will be packaged into MethodInterceptor and
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
enter the TransactionInterceptor, invoke() method
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback()
method.
First execute the interceptor chain. There is only TransactionInterceptor in the interceptor chain. Transaction interceptor
workflow:
1) Obtain transaction-related attributes
2) Then obtain PlatformTransactionManager. If no TransactionManager is specified in advance, it
will eventually be selected from the container according to the type. Get a PlatformTransactionManager
3) Execution target method
If abnormal, get the transaction manager, use the transaction manager to roll back
If the transaction manager is used normally to commit the transaction