【Transaction】jta-atomikos + Springboot JPA 多数据源事务回滚

依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

配置

# 多数据源配置
spring:
  datasource:
    ds1:
      driverClassName: org.postgresql.Driver
      jdbcUrl: jdbc:postgresql://xxx/bigdata?currentSchema=public
      username: xxx
      password: xxx
    ds3:
      driverClassName: org.postgresql.Driver
      jdbcUrl: jdbc:postgresql://xxx/xxx?currentSchema=public
      username: xxxx
      password: xxxx
jpa:
    hibernate:
      dialect: org.hibernate.dialect.PostgreSQLDialect
    open-in-view: true
    show-sql: true
    database-platform: org.hibernate.dialect.PostgreSQLDialect

配置类

@Configuration
@ConfigurationProperties(prefix = "spring.datasource.ds2")
@Data
public class GPProperties {
    
    

    private String jdbcUrl;
    private String username;
    private String password;
    private String driverClassName;

}
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.ds1")
@Data
public class PGProperties {
    
    

    private String jdbcUrl;
    private String username;
    private String password;
    private String driverClassName;

}
@Configuration
@EnableTransactionManagement
@DependsOn("transactionManager")
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerPrimary",
        transactionManagerRef = "transactionManager",
        basePackages = {
    
    "com.kanq.bigdata.greenplum.dao.ds1"}) //设置Repository所在位置
public class PrimaryConfig {
    
    

    @Autowired
    private JpaVendorAdapter jpaVendorAdapter;

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Bean(name = "entityManagerPrimary")
    public LocalContainerEntityManagerFactoryBean orderEntityManager() throws Throwable {
    
    

        HashMap<String, Object> properties = new HashMap<String, Object>();
        properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
        properties.put("javax.persistence.transactionType", "JTA");

        LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
        entityManager.setJtaDataSource(primaryDataSource);
        entityManager.setJpaVendorAdapter(jpaVendorAdapter);
        entityManager.setPackagesToScan("com.kanq.bigdata.greenplum.entity.pg");
        entityManager.setPersistenceUnitName("layerPersistenceUnit");
        entityManager.setJpaPropertyMap(properties);
        return entityManager;
    }
}
@Configuration
@DependsOn("transactionManager")
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerSecond",
        transactionManagerRef = "transactionManager",
        basePackages = {
    
    "com.kanq.bigdata.greenplum.dao.ds2"}) //设置Repository所在位置
public class SecondConfig {
    
    

    @Autowired
    private JpaVendorAdapter jpaVendorAdapter;

    @Autowired
    @Qualifier("secondDataSource")
    private DataSource secondDataSource;

    @Bean(name = "entityManagerSecond")
    public LocalContainerEntityManagerFactoryBean orderEntityManager() throws Throwable {
    
    

        HashMap<String, Object> properties = new HashMap<String, Object>();
        properties.put("hibernate.transaction.jta.platform", AtomikosJtaPlatform.class.getName());
        properties.put("javax.persistence.transactionType", "JTA");

        LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
        entityManager.setJtaDataSource(secondDataSource);
        entityManager.setJpaVendorAdapter(jpaVendorAdapter);
        entityManager.setPackagesToScan("com.kanq.bigdata.greenplum.entity.gp");
        entityManager.setPersistenceUnitName("metaPersistenceUnit");
        entityManager.setJpaPropertyMap(properties);
        return entityManager;
    }
    
}
@Configuration
@ComponentScan
@EnableTransactionManagement
public class DataSourceConfig {
    
    

    //    @ConfigurationProperties(prefix="spring.datasource.ds1")
    @Bean(name = "primaryDataSource",initMethod = "init", destroyMethod = "close")
    @Qualifier("primaryDataSource")
    @Primary
    public DataSource primaryDataSource(PGProperties pgProperties) {
    
    
    //    DataSource pg = DataSourceBuilder.create().build();

        PGXADataSource pgxa=new PGXADataSource();
        pgxa.setURL(pgProperties.getJdbcUrl());
        pgxa.setUser(pgProperties.getUsername());
        pgxa.setPassword(pgProperties.getPassword());

        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(pgxa);
        xaDataSource.setUniqueResourceName("primaryDataSource");
        return xaDataSource;
    }


    @Bean(name = "secondDataSource")
    @Qualifier("secondDataSource")
    public DataSource secondaryDataSource(GPProperties gpProperties) {
    
    
        PGXADataSource gpxa=new PGXADataSource();
        gpxa.setURL(gpProperties.getJdbcUrl());
        gpxa.setUser(gpProperties.getUsername());
        gpxa.setPassword(gpProperties.getPassword());

        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(gpxa);
        xaDataSource.setUniqueResourceName("secondDataSource");
        return xaDataSource;
    }

    @Bean
    public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
    
    
        return new PropertySourcesPlaceholderConfigurer();
    }


    //设置JPA特性
    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {
    
    
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        //显示sql
        hibernateJpaVendorAdapter.setShowSql(true);
        //自动生成/更新表
        hibernateJpaVendorAdapter.setGenerateDdl(false);
        //设置数据库类型
        hibernateJpaVendorAdapter.setDatabase(Database.POSTGRESQL);
        return hibernateJpaVendorAdapter;
    }

    @Bean(name = "atomikosTransactionManager",initMethod = "init", destroyMethod = "close")
    public TransactionManager atomikosTransactionManager() throws Throwable {
    
    
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(false);
        AtomikosJtaPlatform.transactionManager = userTransactionManager;
        return userTransactionManager;
    }

    @Bean(name = "userTransaction")
    public UserTransaction userTransaction() throws Throwable {
    
    
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(10000);
        return userTransactionImp;
    }

    @Bean(name = "transactionManager")
    @DependsOn({
    
    "userTransaction", "atomikosTransactionManager"})
    public PlatformTransactionManager transactionManager() throws Throwable {
    
    
        UserTransaction userTransaction = userTransaction();
        AtomikosJtaPlatform.transaction = userTransaction;
        TransactionManager atomikosTransactionManager = atomikosTransactionManager();
        return new JtaTransactionManager(userTransaction, atomikosTransactionManager);
    }
}
import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

public class AtomikosJtaPlatform extends AbstractJtaPlatform {
    
    

    private static final long serialVersionUID = 1L;

    static TransactionManager transactionManager;
    static UserTransaction transaction;
    @Override
    protected TransactionManager locateTransactionManager() {
    
    
        return transactionManager;
    }

    @Override
    protected UserTransaction locateUserTransaction() {
    
    
        return transaction;
    }
}

Entity、Repository

Entity、Repository都需要分2个文件夹,配置中配置了不同数据源使用不同的文件夹
在这里插入图片描述

Controller

需要加事务@Transactional

 @RequestMapping(value = "/test", method = RequestMethod.POST)
 @Transactional
public ResultModel test(){
    
    
		Map<String,Object> res=null;
  		res=service.test();
        return Message.success(res);
}

Service

如果Controller没有@Transactional注解,这里回滚会出错,提示没有事务。

//atomikos事务
    @Transactional
    public boolean test(){
    
    
        try {
    
    
        	XXX xxx=new XXX("wo",1);
        	YYY yyy=new YYY("qaq",2);
            xxxDao.saveAndFlush(xxx);
            yyyDao.saveAndFlush(yyy);
        }catch (Exception e){
    
    
            log.error("数据更新异常",e);
         TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return false;
        }
        return true;
    }

2个不同数据源的事务都会回滚。

猜你喜欢

转载自blog.csdn.net/qq_42158942/article/details/108407230