本章分两节
- 1.事务环境搭建
- 2.事务原理分析
事务环境搭建
- 1.导入相关依赖(数据源、数据库驱动、Spring-jdbc模块)
- 2.配置数据源、mybatis的Mapper
- 3.给方法上标注 @Transactional 表示当前方法是一个事务方法;
- 4.@EnableTransactionManagement 开启基于注解的事务管理功能
- 5.配置事务管理器来控制事务;
1.导入相关依赖(数据源、数据库驱动、Spring-jdbc模块)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
2.配置数据源、mybatis的Mapper
@Configuration
@MapperScan("com.ddc.mcn.mapper")
@Data
public class MybatisConf {
@Value("${apollo.dataSource.read01.jdbc.url}")
private String read01url;
@Value("${apollo.dataSource.read01.jdbc.username}")
private String read01username;
@Value("${apollo.dataSource.read01.jdbc.password}")
private String read01password;
@Value("${apollo.dataSource.write01.jdbc.url}")
private String write01url;
@Value("${apollo.dataSource.write01.jdbc.username}")
private String write01username;
@Value("${apollo.dataSource.write01.jdbc.password}")
private String write01password;
// @Bean
private DruidDataSource read01DataSource() {
DruidDataSource read01DataSource = new DruidDataSource();
read01DataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
read01DataSource.setUrl(read01url);
read01DataSource.setUsername(read01username);
read01DataSource.setPassword(read01password);
read01DataSource.setInitialSize(5);
read01DataSource.setMaxActive(50);
read01DataSource.setMinIdle(5);
// 配置获取连接等待超时的时间
read01DataSource.setMaxWait(60000);
read01DataSource.setPoolPreparedStatements(false);
read01DataSource.setMaxPoolPreparedStatementPerConnectionSize(0);
read01DataSource.setValidationQuery("SELECT 'x'");
read01DataSource.setValidationQueryTimeout(5);
read01DataSource.setTestOnBorrow(false);
read01DataSource.setTestOnReturn(false);
read01DataSource.setTestWhileIdle(true);
// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
read01DataSource.setTimeBetweenEvictionRunsMillis(60000);
// 配置一个连接在池中最小生存的时间,单位是毫秒
read01DataSource.setMinEvictableIdleTimeMillis(300000);
read01DataSource.setMaxEvictableIdleTimeMillis(1800000);
read01DataSource.setRemoveAbandoned(true);
try {
read01DataSource.setFilters("stat");
} catch (SQLException e) {
e.printStackTrace();
}
return read01DataSource;
}
// @Bean
private DruidDataSource write01DataSource() {
DruidDataSource write01DataSource = new DruidDataSource();
write01DataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
write01DataSource.setUrl(write01url);
write01DataSource.setUsername(write01username);
write01DataSource.setPassword(write01password);
write01DataSource.setInitialSize(5);
write01DataSource.setMaxActive(50);
write01DataSource.setMinIdle(5);
// 配置获取连接等待超时的时间
write01DataSource.setMaxWait(60000);
write01DataSource.setPoolPreparedStatements(false);
write01DataSource.setMaxPoolPreparedStatementPerConnectionSize(0);
write01DataSource.setValidationQuery("SELECT 'x'");
write01DataSource.setValidationQueryTimeout(5);
write01DataSource.setTestOnBorrow(false);
write01DataSource.setTestOnReturn(false);
write01DataSource.setTestWhileIdle(true);
// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
write01DataSource.setTimeBetweenEvictionRunsMillis(60000);
// 配置一个连接在池中最小生存的时间,单位是毫秒
write01DataSource.setMinEvictableIdleTimeMillis(300000);
write01DataSource.setMaxEvictableIdleTimeMillis(1800000);
write01DataSource.setRemoveAbandoned(true);
try {
write01DataSource.setFilters("stat");
} catch (SQLException e) {
e.printStackTrace();
}
return write01DataSource;
}
@Bean
@Primary
public DynamicDataSource dynamicDataSource() {
Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
targetDataSources.put("write01", write01DataSource());
targetDataSources.put("read01", read01DataSource());
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSources);
dataSource.setDefaultTargetDataSource(write01DataSource());
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource());
sqlSessionFactoryBean.setTypeAliasesPackage("com.ddc.mcn.domain");
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:mybatis/*Mapper.xml"));
sqlSessionFactoryBean.setConfigLocation(resolver.getResource("classpath:config/mybatis-config.xml"));
return sqlSessionFactoryBean;
}
}
因为我用的是读写分离的,所有有两个数据源,关于如何在service层做数据库的读写分离,后面会单独写文章介绍
给方法上标注 @Transactional 表示当前方法是一个事务方法;
@Transactional
@Override
@DataSource(DataSourceTypeEnum.MASTER)
public int save(UserRequestDTO user) {
UserDO u = new UserDO();
BeanUtils.copyProperties(user, u);
u.setGmtCreate(new Date());
int count = userMapper.save(u);
Long userId = u.getUserId();
List<Long> roles = user.getRoleIds();
userRoleMapper.removeByUserId(userId);
List<UserRoleDO> list = new ArrayList<>();
if (roles != null && roles.size() != 0) {
for (Long roleId : roles) {
UserRoleDO ur = new UserRoleDO();
ur.setUserId(userId);
ur.setRoleId(roleId);
list.add(ur);
}
}
if (list.size() > 0) {
userRoleMapper.batchSave(list);
}
return count;
}
4.@EnableTransactionManagement 开启基于注解的事务管理功能
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
public class TransactionManagementConf implements TransactionManagementConfigurer {
// @Resource(name = "txManager")
private PlatformTransactionManager transactionManager;
// 创建事务管理器1,其中 dataSource 框架会自动为我们注入
//这一步为操作步骤5.配置事务管理器来控制事务;
@Bean
@Qualifier(value = "transactionManager")
public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
public PlatformTransactionManager annotationDrivenTransactionManager() {
return transactionManager;
}
}
其中,以下代码为配置事务管理器
//这一步为操作步骤5.配置事务管理器来控制事务;
@Bean
@Qualifier(value = "transactionManager")
public PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
以上步骤完成,便实现了声明式事务的全部编写步骤,其中在第四步,TransactionManagementConf实现了TransactionManagementConfigurer接口,这个主要的作用是,返回系统默认的事务管理器,因为我们一个系统当中,可能会出现多种事务类型,比如JpaTransactionManager,DataSourceTransactionManager,HibernateTransactionManager等