场景:
在方法中,使用了hana数据源从hana数据库中查出数据,然后将数据写到mysql数据库中,对数据库进行修改操作时,我们一般会添加事务回滚的操作,以便程序出错时可以还原数据库。
问题:
在方法中添加能使程序异常的代码(比如:int i = 1/0;)进行测试,并在方法中贴上以下注解:
@Transactional(rollbackFor = Exception.class)
但是发现事务并没有回滚
检查了项目的配置, 两个数据源配置了事务管理器:
hana数据源配置:
import javax.sql.DataSource;
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import top.ibase4j.core.Constants;
import top.ibase4j.core.util.PropertiesUtil;
import top.ibase4j.core.util.SecurityUtil;
@Configuration
@MapperScan(basePackages = "com.xxx.mapper.hana",sqlSessionTemplateRef ="hanaSqlSessionTemplate")
public class HanaDataSourceConfig {
@Bean(name = "hanaDataSource")
@Primary
public DataSource gethanaDataSource() {
DataSource build = DataSourceBuilder.create()
.driverClassName(PropertiesUtil.getString("hana.driverClassName"))
.url(PropertiesUtil.getString("hana.url"))
.username(PropertiesUtil.getString("hana.username"))
.password(SecurityUtil.decryptDes(PropertiesUtil.getString("hana.password"), Constants.DB_KEY.getBytes()))
.build();
return build;
}
@Bean(name = "hanaSqlSessionFactory")
@Primary
public SqlSessionFactory hanaSqlSessionFactory(@Qualifier("hanaDataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
//设置mapper配置文件
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/hana
@Bean("hanaTransactionManger")
@Primary
public DataSourceTransactionManager hanaTransactionManger(@Qualifier("hanaDataSource") DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "hanaSqlSessionTemplate")
@Primary
public SqlSessionTemplate hanaSqlSessionTemplate(@Qualifier("hanaSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
mysql数据源配置:
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import top.ibase4j.core.util.PropertiesUtil;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = "com.xxx.mapper.mysql",sqlSessionTemplateRef ="mysqlSqlSessionTemplate")
public class MysqlDataSourceConfig {
@Resource
private MybatisPlusConfig mybatisPlusConfig;
@Bean(name = "mysqlDataSource")
public DataSource getmysqlDataSource() {
DataSource build = DataSourceBuilder.create()
.driverClassName(PropertiesUtil.getString("druid.default.driverClassName"))
.url(PropertiesUtil.getString("druid.writer.default.url"))
.username(PropertiesUtil.getString("druid.writer.default.username"))
.password(PropertiesUtil.getString("druid.writer.default.password"))
.build();
return build;
}
@Bean(name = "mysqlSqlSessionFactory")
public SqlSessionFactory mysqlSqlSessionFactory(@Qualifier("mysqlDataSource") DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
bean.setDataSource(dataSource);
//设置mapper配置文件
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/mysql
@Bean("mysqlTransactionManger")
public DataSourceTransactionManager mysqlTransactionManger(@Qualifier("mysqlDataSource") DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "mysqlSqlSessionTemplate")
public SqlSessionTemplate mysqlSqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory){
return new SqlSessionTemplate(sqlSessionFactory);
}
}
由于默认的数据源是hana数据源,但是现在我们要将mysql的事务进行回滚,如果不将默认的事务管理器设置mysql对应的事务管理器为默认的话, 事务回滚将不起作用。
因此,可以添加配置类,以配置默认的事务管理器为mysql的,配置类要实现TransactionManagementConfigurer
@Configuration
public class SpecifyDefaultTransactionManagerConfig implements TransactionManagementConfigurer {
@Autowired
private MysqlDataSourceConfig mysqlDataSourceConfig;
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return mysqlDataSourceConfig.mysqlTransactionManger(mysqlDataSourceConfig.getmysqlDataSource());
}
再次进行测试,事务将回滚成功
如果不想添加配置类,可以在注解中标明使用的是哪个事务管理器
这里我们要用的是mysql的,因此可以这样配置
@Transactional(value = "mysqlTransactionManger",rollbackFor = Exception.class)
value的值就是事务管理器bean的名称



