springboot 事务例子(JTA双数据库)

Submitted by Lizhe on Fri, 07/28/2017 - 15:47

下面这个例子基于springboot+atomikos+jta实现的双数据库事务

/springbootJtaSample/pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>name.lizhe</groupId>
    <artifactId>springjtasamplebootannotation</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.5.RELEASE</version>
        <relativePath />
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>

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

        <dependency>
            <groupId>com.atomikos</groupId>
            <artifactId>transactions-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

    </dependencies>
</project>

 

/springbootJtaSample/src/main/java/springjtasample/App.java

package springjtasample;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableAutoConfiguration  
@EnableTransactionManagement
public class App {
    
    public static void main(String[] args) {
        new SpringApplicationBuilder(App.class).web(true).run(args);
    }
    
}
 

 

/springbootJtaSample/src/main/java/springjtasample/Controller.java

package springjtasample;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableTransactionManagement
@Transactional
public class Controller {

    
    @Autowired
    @Qualifier("primaryJdbcTemplate")
    JdbcTemplate jdbcTemplate1;

    @Autowired
    @Qualifier("secondaryJdbcTemplate")
    JdbcTemplate jdbcTemplate2;

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String hello(HttpServletRequest req) {
        doLogic();
        return "helloworld";
    }

    @Transactional(value = "transactionManager", rollbackFor = { Exception.class,
            RuntimeException.class }, propagation = Propagation.REQUIRES_NEW)
    public void doLogic() {
        jdbcTemplate1.update("insert into table1 (id) value (1)");
        jdbcTemplate2.update("insert into table1 (id) value (1)");
    }
}
 

 

/springbootJtaSample/src/main/java/springjtasample/DataSourceConfig.java

package springjtasample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.jta.JtaTransactionManager;

import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;

import java.util.Properties;

import javax.sql.DataSource;
import javax.transaction.SystemException;

@Configuration
public class DataSourceConfig {
    
    @Autowired
    private UserTransactionManager atomikosUserTransactionManager;
    
    @Bean(name = "primaryDataSource",destroyMethod = "close")
    @Qualifier("primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondaryDataSource",destroyMethod = "close")
    @Qualifier("secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource(){
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "primaryJdbcTemplate")
    public JdbcTemplate primaryJdbcTemplate(@Qualifier("db1")DataSource dataSource){
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "secondaryJdbcTemplate")
    public JdbcTemplate secondaryJdbcTemplate(@Qualifier("db2")DataSource dataSource){
        return new JdbcTemplate(dataSource);
    }
    
    @Bean(name = "atomikosUserTransactionManager",destroyMethod = "close", initMethod = "init")
    public UserTransactionManager getUserTransactionManager(){
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        userTransactionManager.setForceShutdown(true);
        return userTransactionManager;
    }
    
    @Bean(name = "atomikosUserTransaction")
    public UserTransactionImp getUserTransactionImp() throws SystemException{
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(300);
        return userTransactionImp;
    }
    
    @Bean(name = "transactionManager")
    public JtaTransactionManager getJtaTransactionManager(){
        JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
        jtaTransactionManager.setTransactionManager(atomikosUserTransactionManager);
        return jtaTransactionManager;
    }
    
    @Bean
    @Qualifier("db1")
    @Primary
    public AtomikosDataSourceBean db3DataSourceBean() {
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setUniqueResourceName("db3");
        atomikosDataSourceBean.setXaDataSourceClassName(
                "com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
        Properties properties = new Properties();
        properties.put("URL", "jdbc:mysql://172.28.128.4:3306/db1?useUnicode=true&amp;characterEncoding=utf-8");
        properties.put("user", "root");
        properties.put("password", "root");
        atomikosDataSourceBean.setXaProperties(properties);
        return atomikosDataSourceBean;
    }
    
    @Bean
    @Qualifier("db2")
    public AtomikosDataSourceBean db4DataSourceBean() {
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setUniqueResourceName("db4");
        atomikosDataSourceBean.setXaDataSourceClassName(
                "com.mysql.jdbc.jdbc2.optional.MysqlXADataSource");
        Properties properties = new Properties();
        properties.put("URL", "jdbc:mysql://172.28.128.4:3306/db2?useUnicode=true&amp;characterEncoding=utf-8");
        properties.put("user", "root");
        properties.put("password", "root");
        atomikosDataSourceBean.setXaProperties(properties);
        return atomikosDataSourceBean;
    }
    
 
}