【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务

1 环境

(1) 数据库
【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务_第1张图片

 CREATE TABLE `t_student` (
  `n_id` int(11) NOT NULL AUTO_INCREMENT,
  `c_name` varchar(255) DEFAULT NULL,
  `c_age` int(12) DEFAULT NULL,
  PRIMARY KEY (`n_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

CREATE TABLE `t_teacher` (
  `n_id` int(11) NOT NULL AUTO_INCREMENT,
  `c_name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`n_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

(2) 工程
【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务_第2张图片

2 pom

<!--spring boot 版本依赖-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <!-- spring boot 对 web的依赖 可用 spring-boot:run启动 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- spring boot 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 测试包 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--mapper -->
        <!-- https://mvnrepository.com/artifact/tk.mybatis/mapper-spring-boot-starter-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.1.5</version>
        </dependency>
        <!--pagehelper -->
        <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.10</version>
        </dependency>
        <!-- MySQL 连接驱动依赖 -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
        </dependency>
    </dependencies>

3 application.yml

#配置端口
server:
  port: 8080
#配置数据源
spring:
  #student的配置
  student:
    uniqueResourceName: studentDatasource
    jdbcUrl: jdbc:mysql://localhost:3306/db_student?characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
    poolSize: 10
    dataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
  #teacher配置
  teacher:
    uniqueResourceName: teacherDatasource
    jdbcUrl: jdbc:mysql://localhost:3306/db_teacher?characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456
    poolSize: 10
    dataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlXADataSource

4 student数据源配置

@ConfigurationProperties(prefix = "spring.student")
@Data
public class StudentDataSourceProperties {
    /**
     * 数据源唯一资源名
     */
    private String uniqueResourceName;
    /**
     * jdbc链接URL
     */
    private String jdbcUrl;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 连接池
     */
    private Integer poolSize;
    /**
     * 数据源类名
     */
    private String dataSourceClassName;
}
@Configuration
@Import(StudentDataSourceProperties.class)
@MapperScan(basePackages = "com.spring.student.mapper", sqlSessionFactoryRef = "studentSqlSessionFactory")
public class StudentDatasourceConfig {
    @Autowired
    private StudentDataSourceProperties studentProperties;
    /**
     * 配置AtomikosDataSourceBean数据源
     *
     */
    @Bean(name = "studentDatasource")
    @Primary
    public DataSource studentDataSource() {
        //属性
        Properties properties = new Properties();
        properties.put("URL",studentProperties.getJdbcUrl());
        properties.put("user", studentProperties.getUsername());
        properties.put("password", studentProperties.getPassword());
        //数据源
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setUniqueResourceName(studentProperties.getUniqueResourceName());
        atomikosDataSourceBean.setXaDataSourceClassName(studentProperties.getDataSourceClassName());
        atomikosDataSourceBean.setPoolSize(studentProperties.getPoolSize());
        atomikosDataSourceBean.setXaProperties(properties);
        return atomikosDataSourceBean;
    }
    /**
     * 获取sqlSessionFactory
     */
    @Bean
    public SqlSessionFactory studentSqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(studentDataSource());
        return factoryBean.getObject();
    }
    /**
     * 获取会话模板
     */
    @Bean
    public SqlSessionTemplate studentSqlSessionTemplate() throws Exception {
        return new SqlSessionTemplate(studentSqlSessionFactory());
    }
    /*
     * 使用这个来做总事务 后面的数据源就不用设置事务了
     * */
    @Bean(name = "transactionManager")
    @Primary
    public JtaTransactionManager regTransactionManager () {
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        UserTransaction userTransaction = new UserTransactionImp();
        return new JtaTransactionManager(userTransaction, userTransactionManager);
    }
}

5 Teacher配置


@ConfigurationProperties(prefix = "spring.teacher")
@Data
public class TeacherDataSourceProperties {
    /**
     * 数据源唯一资源名
     */
    private String uniqueResourceName;
    /**
     * jdbc链接URL
     */
    private String jdbcUrl;
    /**
     * 用户名
     */
    private String username;
    /**
     * 密码
     */
    private String password;
    /**
     * 连接池
     */
    private Integer poolSize;
    /**
     * 数据源类名
     */
    private String dataSourceClassName;
}


@Configuration
@Import(TeacherDataSourceProperties.class)
@MapperScan(basePackages  = "com.spring.teacher.mapper", sqlSessionFactoryRef = "teacherSqlSessionFactory")
public class TeacherDatasourceConfig {
    @Autowired
    private TeacherDataSourceProperties teacherProperties;
    /**
     * 获取数据源
     * ConfigurationProperties:读取spring.datasource01的数据源
     */
    @Bean(name = "teacherDatasource")
    public DataSource teacherDataSource() {
        //属性
        Properties properties = new Properties();
        properties.put("URL",teacherProperties.getJdbcUrl());
        properties.put("user", teacherProperties.getUsername());
        properties.put("password", teacherProperties.getPassword());
        //数据源
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setUniqueResourceName(teacherProperties.getUniqueResourceName());
        atomikosDataSourceBean.setXaDataSourceClassName(teacherProperties.getDataSourceClassName());
        atomikosDataSourceBean.setPoolSize(teacherProperties.getPoolSize());
        atomikosDataSourceBean.setXaProperties(properties);
        return atomikosDataSourceBean;
    }
    /**
     * 获取sqlSessionFactory
     */
    @Bean
    public SqlSessionFactory  teacherSqlSessionFactory() throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(teacherDataSource());
        return factoryBean.getObject();
    }
    /**
     * 获取会话模板
     */
    @Bean
    public SqlSessionTemplate teacherSqlSessionTemplate() throws Exception {
        return new SqlSessionTemplate(teacherSqlSessionFactory());
    }
}

6 po


@Data
@Table(name = "t_student")
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    @Id
    @Column(name = "n_id")
    private Integer id;
    @Column(name = "c_name")
    private String name;
    @Column(name = "c_age")
    private Integer age;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "t_teacher")
public class Teacher {
    @Id
    @Column(name = "n_id")
    private Integer id;
    @Column(name = "c_name")
    private String name;
}

7 mapper

@Mapper
public interface StudentMapper  extends BaseMapper<Student> {
}

@Mapper
public interface TeacherMapper extends BaseMapper<Teacher> {
}

8 service


@Service
public class CommonService {
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private TeacherMapper teacherMapper;
   
    @Transactional
    public void addSuccessTest(){
        studentMapper.insertSelective(new Student(null, "张三",15));
        teacherMapper.insertSelective(new Teacher(null,"张三"));
    }
   
   @Transactional
    public void addRollbackTest(){
        studentMapper.insertSelective(new Student(null, "张三",15));
        teacherMapper.insertSelective(new Teacher(null,"张三"));
        int a=1/0;
    }
}

9 启动类

@SpringBootApplication
public class MybatisApplicationContext {
    public static void main(String[] args) {
        SpringApplication.run(MybatisApplicationContext.class);
    }
}

9 测试 addSuccessTest

@RunWith(SpringRunner.class)
//主application方法
@SpringBootTest(classes=MybatisApplicationContext.class)
public class MybatisTest {
    @Autowired
    private CommonService commonService;
    @Test
    public void addSuccessTest(){
        commonService.addSuccessTest();
    }
    @Test
    public void addRollbackTest(){
        commonService.addRollbackTest();
    }
}

【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务_第3张图片
【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务_第4张图片

【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务_第5张图片

10 测试 addRollbackTest,回滚成功

【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务_第6张图片
【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务_第7张图片
【Spring实战】springboot+Atomikos+mybatis+mysql 实现分布式事务_第8张图片

你可能感兴趣的:(Spring,源码解析与实战)