`
wx1569567608
  • 浏览: 71219 次
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

19.从零开始学springboot-jdbc-atomikos多数据源分布式事务案例

 
阅读更多

前言

上章我们通过jpa和atomikos实现了分布式事务的处理案例。这节,我们来实现jdbc多数据源+atomikos的方式来实现分布式事务的处理案例。

Atomikos介绍

Atomikos 是一个为Java平台提供增值服务的并且开源类事务管理器。我们通过它来管理事务。springboot本身对其有很好的支持,依赖为spring-boot-starter-jta-atomikos。

创建空项目

3.png

添加依赖

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
      </dependency>

1.png

添加配置

application.yml:

spring:
  datasource:
    master:
      username: root
      password: 123456
      url: jdbc:mysql://192.168.145.131:3306/test
      driver-class-name: com.mysql.cj.jdbc.Driver
    slave:
      username: root
      password: 123456
      url: jdbc:mysql://192.168.145.131:3306/test2
      driver-class-name: com.mysql.cj.jdbc.Driver

建库

创建test、test2库 test:

CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) NOT NULL,
  `grade` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

test2:

CREATE TABLE `teacher` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) NOT NULL,
  `course` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


完善

目录结构 2.png

根据目录结构,请自行创建package和class。

config/DataSourceConfig

package com.mrcoder.sbjdbcmultidbatomikos.config;

import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.cj.jdbc.MysqlXADataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.jta.JtaTransactionManager;

import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import java.sql.SQLException;

@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
public class DataSourceConfig {

    //事务管理器配置start
    @Bean(name = "userTransaction")
    public UserTransaction userTransaction() throws Throwable {
        UserTransactionImp userTransactionImp = new UserTransactionImp();
        userTransactionImp.setTransactionTimeout(10000);
        return userTransactionImp;
    }

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

    @Bean(name = "transactionManager")
    @DependsOn({"userTransaction", "atomikosTransactionManager"})
    public PlatformTransactionManager transactionManager() throws Throwable {
        UserTransaction userTransaction = userTransaction();
        TransactionManager atomikosTransactionManager = atomikosTransactionManager();
        JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(userTransaction, atomikosTransactionManager);
        jtaTransactionManager.setAllowCustomIsolationLevels(true);
        return jtaTransactionManager;
    }


    //master数据源配置
    @Primary
    @Bean(name = "masterDataSourceProperties")
    @Qualifier("masterDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSourceProperties masterDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Primary
    @Bean(name = "masterDataSource", initMethod = "init", destroyMethod = "close")
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource masterDataSource() throws SQLException {
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        mysqlXaDataSource.setUrl(masterDataSourceProperties().getUrl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(masterDataSourceProperties().getPassword());
        mysqlXaDataSource.setUser(masterDataSourceProperties().getUsername());
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName("xads1");
        xaDataSource.setBorrowConnectionTimeout(60);
        xaDataSource.setMaxPoolSize(20);
        return xaDataSource;

    }

    @Bean(name = "masterJdbcTemplate")
    public JdbcTemplate masterJdbcTemplate() throws SQLException {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(masterDataSource());
        return jdbcTemplate;
    }

    //slave数据源配置
    @Bean(name = "slaveDataSourceProperties")
    @Qualifier("slaveDataSourceProperties")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSourceProperties slaveDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean(name = "slaveDataSource", initMethod = "init", destroyMethod = "close")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource slaveDataSource() throws SQLException {
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        mysqlXaDataSource.setUrl(slaveDataSourceProperties().getUrl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(slaveDataSourceProperties().getPassword());
        mysqlXaDataSource.setUser(slaveDataSourceProperties().getUsername());
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName("xads2");
        xaDataSource.setBorrowConnectionTimeout(60);
        xaDataSource.setMaxPoolSize(20);
        return xaDataSource;
    }

    @Bean(name = "slaveJdbcTemplate")
    public JdbcTemplate slaveJdbcTemplate() throws SQLException {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(slaveDataSource());
        return jdbcTemplate;
    }
}

entity/Student

package com.mrcoder.sbjdbcmultidbatomikos.entity;

import java.io.Serializable;

public class Student implements Serializable {
    private int id;

    private String name;

    private int age;

    private int grade;

    public Student() {
    }

    public Student(String name, int age, int grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", grade=" + grade +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getGrade() {
        return grade;
    }

    public void setGrade(int grade) {
        this.grade = grade;
    }
}

entity/Teacher

package com.mrcoder.sbjdbcmultidbatomikos.entity;

import java.io.Serializable;

public class Teacher implements Serializable {

    private int id;
    private String name;
    private int age;
    private int course;

    public Teacher() {
    }

    public Teacher(String name, int age, int course) {
        this.name = name;
        this.age = age;
        this.course = course;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", course='" + course + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getCourse() {
        return course;
    }

    public void setCourse(int course) {
        this.course = course;
    }
}

dao/StuentDao

package com.mrcoder.sbjdbcmultidbatomikos.dao;

import com.mrcoder.sbjdbcmultidbatomikos.entity.Student;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Repository
public class StudentDao {

    @Resource(name = "masterJdbcTemplate")
    private JdbcTemplate masterJdbcTemplate;

    @Resource(name = "slaveJdbcTemplate")
    private JdbcTemplate slaveJdbcTemplate;
    
    class StudentMapper implements RowMapper<Student> {
        @Override
        public Student mapRow(ResultSet resultSet, int i) throws SQLException {
            Student student = new Student();
            student.setAge(resultSet.getInt("age"));
            student.setGrade(resultSet.getInt("grade"));
            student.setName(resultSet.getString("name"));
            return student;
        }
    }


    public int save(Student student) {
        String sql = "INSERT INTO `test`.`student` (`age`, `grade`,`name`) VALUES (?, ?, ?)";
        int result = masterJdbcTemplate.update(sql, new Object[]{student.getAge(), student.getGrade(), student.getName()});
        return result;
    }

    public List<Student> getList() {
        String sql = "select * from student s";
        List<Student> list = masterJdbcTemplate.query(sql, new StudentMapper());
        return list;
    }
}

dao/TeacherDao

package com.mrcoder.sbjdbcmultidbatomikos.dao;

import com.mrcoder.sbjdbcmultidbatomikos.entity.Student;
import com.mrcoder.sbjdbcmultidbatomikos.entity.Teacher;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Repository
public class TeacherDao {

    @Resource(name = "masterJdbcTemplate")
    private JdbcTemplate masterJdbcTemplate;

    @Resource(name = "slaveJdbcTemplate")
    private JdbcTemplate slaveJdbcTemplate;


    class TeacherMapper implements RowMapper<Teacher> {
        @Override
        public Teacher mapRow(ResultSet resultSet, int i) throws SQLException {
            Teacher teacher = new Teacher();
            teacher.setAge(resultSet.getInt("age"));
            teacher.setCourse(resultSet.getInt("course"));
            teacher.setName(resultSet.getString("name"));
            return teacher;
        }
    }


    public int save(Teacher teacher) {
        String sql = "INSERT INTO `test2`.`teacher` (`age`, `course`,`name`) VALUES (?, ?, ?)";
        int result = slaveJdbcTemplate.update(sql, new Object[]{teacher.getAge(), teacher.getCourse(), teacher.getName()});
        return result;
    }

    public List<Teacher> getList() {
        String sql = "select * from teacher t ";
        List<Teacher> list = slaveJdbcTemplate.query(sql, new TeacherMapper());
        return list;
    }
}

service/CurdService

package com.mrcoder.sbjdbcmultidbatomikos.service;

import com.mrcoder.sbjdbcmultidbatomikos.dao.StudentDao;
import com.mrcoder.sbjdbcmultidbatomikos.dao.TeacherDao;
import com.mrcoder.sbjdbcmultidbatomikos.entity.Student;
import com.mrcoder.sbjdbcmultidbatomikos.entity.Teacher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(transactionManager = "transactionManager", propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = {Exception.class})
public class CurdService {

    @Autowired
    private StudentDao studentDao;

    @Autowired
    private TeacherDao teacherDao;

    public void add(int code) {
        Student s1 = new Student();
        s1.setAge(1);
        s1.setGrade(1);
        s1.setName("s1");
        studentDao.save(s1);

        Teacher t1 = new Teacher();
        t1.setAge(1);
        t1.setName("t1");
        t1.setCourse(1);
        teacherDao.save(t1);

        int result = 1 / code;
    }

}


controller/JdbcAtomikosController

package com.mrcoder.sbjdbcmultidbatomikos.controller;


import com.mrcoder.sbjdbcmultidbatomikos.dao.StudentDao;
import com.mrcoder.sbjdbcmultidbatomikos.dao.TeacherDao;
import com.mrcoder.sbjdbcmultidbatomikos.service.CurdService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JdbcAtomikosController {

    @Autowired
    private StudentDao studentDao;

    @Autowired
    private TeacherDao teacherDao;

    @Autowired
    private CurdService curdService;

    @RequestMapping("/commit")
    public void add() {
        curdService.add(1);
    }

    @RequestMapping("/rollback")
    public void rollback() {
        curdService.add(0);
    }

    @RequestMapping("/list")
    public void list() {
        System.out.println(studentDao.getList());
        System.out.println(teacherDao.getList());
    }
}

运行

http://localhost:8080/commit 会在test库的student和test2库的teacher表中各新增一条记录

http://localhost:8080/rollback 人为的制造1/0的异常,异常触发事务,会发现两张表都不会新增记录。

项目地址

https://github.com/MrCoderStack/SpringBootDemo/tree/master/sb-jdbc-multidb-atomikos

https://gitee.com/MrCoderStack/SpringBootDemo/tree/master/sb-jdbc-multidb-atomikos

注意点

请一定注意,两张表为innodb引擎,若出现分布式事务无法触发,请优先查看表引擎。

请关注我的订阅号

订阅号.png

转载于:https://my.oschina.net/u/3066875/blog/3055188

分享到:
评论

相关推荐

    SpringBoot+Atomikos分布式事务及多数据源动态切换,两种demo

    最后,压缩包中的"SpringBoot+Atomikos分布式事务及动态数据源"文件可能包含了具体的代码示例和配置文件,这些资源可以帮助开发者更好地理解和实践上述概念。通过分析和学习这些示例,可以快速上手Spring Boot与...

    springboot + mybatis + atomikos 多数据源分布式事物管理

    Spring Boot、MyBatis 和 Atomikos 的结合提供了一种解决方案,用于处理多数据源的分布式事务管理。以下是对这个主题的详细阐述。 首先,Spring Boot 是一个基于 Spring 框架的轻量级开发工具,它简化了配置过程并...

    Spring3.0+Hibernate+Atomikos多数据源分布式事务管理

    本教程将聚焦于如何利用Spring 3.0、Hibernate ORM框架以及Atomikos这个开源事务管理器来实现高效、可靠的多数据源分布式事务处理。 **Spring 3.0**: Spring是Java开发中最广泛使用的轻量级框架之一,它提供了一个...

    springboot多数据源即分布式事务解决方案

    SpringBoot作为一款轻量级的框架,提供了便捷的多数据源配置和分布式事务管理方案,使得开发者能够高效地管理和操作不同的数据库。本文将详细探讨SpringBoot如何实现多数据源以及分布式事务。 首先,我们要理解什么...

    Spring Boot + Druid + Mybatis + Atomikos 配置多数据源 并支持分布式事务

    本教程将探讨如何利用Spring Boot、Druid、Mybatis以及Atomikos来配置多数据源并实现分布式事务。 首先,Spring Boot是Java生态系统中的一个流行框架,它简化了设置和配置过程,使得开发人员可以快速启动新项目。在...

    springboot-jpa atomikos 分布式事务管理

    本文将详细讲解"springboot-jpa atomikos 分布式事务管理"这一主题,以及如何在SpringBoot 2.0.5版本中结合JPA、Hibernate和MyBatis实现多数据库事务控制。 首先,SpringBoot是一个简化Spring应用开发的框架,它...

    springboot-atomikos 多数据源统一事物管理demo

    本项目"springboot-atomikos 多数据源统一事物管理demo"主要展示了如何在Spring Boot应用中集成Atomikos来实现多数据源的统一事务管理。 首先,我们来详细解释一下Spring Boot和Atomikos: 1. **Spring Boot**:...

    springboot-mybatis-atomikos.zip

    《SpringBoot、MyBatis与Atomikos整合实现两阶段提交分布式事务》 在现代企业级应用中,尤其是在微服务架构下,分布式事务处理成为了一项挑战。本项目"springboot-mybatis-atomikos.zip"正是为了解决这一问题而设计...

    springboot-druid-atomikos.zip

    springboot-druid-atomikos分布式事务,动态数据源在本次Demo中频繁切换太过复杂,容易忘记,所以本Demo改成静态多数据源。只要配置完成,使用的时候就不必在意数据源需要切换的问题。

    使用springboot+jta+atomikos配置多数据源事务

    本教程将详细介绍如何使用Spring Boot结合JTA(Java Transaction API)和Atomikos来配置多数据源事务。 首先,我们需要理解JTA的含义。JTA是Java平台的标准,用于管理跨多个数据源的分布式事务。它允许应用程序在一...

    spring+druid+AtomikosDataSource实现多数据源切换及分布式事务控制

    在现代企业级应用开发中,多数据源切换和分布式事务管理是常见的需求,尤其是在大型分布式系统中。Spring框架因其强大的依赖注入和AOP(面向切面编程)特性,成为Java领域首选的轻量级框架。Druid是一个优秀的数据库...

    SpringBoot+Atomikos+动态多数据源+事务+2种切换数据源的方式

    本主题将深入探讨如何利用SpringBoot结合Atomikos实现动态多数据源以及事务管理,并介绍两种切换数据源的方法。 首先,SpringBoot简化了传统Spring应用的初始化过程,它通过自动配置和starter包让开发者快速搭建...

    SpringBoot+mybatisPlus+atomikos+druid.zip

    Spring Boot:mybatis-plus + atomikos + druid 实现不同实例数据库的多数据源配置和分布式事务管理(demo项目),想到工作上可能会用到多数据源,但是自己在这方面并不是很熟悉,于是在网上查阅了很多文章,结果...

    springboot多数据源即分布式事务解决方案,添加对多线程的支持

    本教程将深入探讨如何在Spring Boot环境下实现多数据源操作及分布式事务管理,并加入对多线程的支持。 首先,我们来理解多数据源的概念。在大型系统中,往往需要连接多个数据库,如主库、从库、测试库等。Spring ...

    java+spring+mybatis+mysql+RuoYi-atomikos-实现分布式事务.zip

    本项目"java+spring+mybatis+mysql+RuoYi-atomikos-实现分布式事务.zip"是一个基于若依(RuoYi)框架改造的多模块分布式事务解决方案,它利用了Atomikos这一强大的分布式事务管理器。以下将详细解析这个项目的知识点...

    springboot+mybatis+druid+atomikos 多数据源,分布式事务,集成websocket,redis,swagger2

    在本项目中,我们主要探讨的是如何利用Spring Boot、MyBatis、Druid、Atomikos、WebSocket、Redis以及Swagger2构建一个具有多数据源、分布式事务管理,并且集成了实时通信与API文档管理功能的高级应用。下面将对这些...

    分布式事务管理SpringBoot集成Atomikos使用Oracle数据库mybatis、jta框架.rar

    SpringBoot集成Atomikos使用Oracle数据库mybatisSpringBoot集成Atomikos使用Oracle数据库mybatisSpringBoot集成Atomikos使用Oracle数据库mybatisSpringBoot集成Atomikos使用Oracle数据库mybatis

    Atomikos分布式事务处理所需jar包

    4. **atomikos-transactions-jdbc.jar**:针对JDBC数据源的事务管理支持,使得Atomikos能管理与数据库相关的事务。 5. **atomikos-transactions-jms.jar**:提供了JMS(Java Message Service)的事务支持,使得消息...

    Springboot+Atomikos+Jpa+Mysql实现JTA分布式事务

    在IT行业中,分布式事务处理是复杂系统架构中的一个重要环节,特别是在微服务架构中,确保数据的一致性至关重要。本文将详细讲解如何利用Spring Boot、Atomikos、JPA(Java Persistence API)以及MySQL来实现JTA...

    SpringBoot+Mybatis+Atomikos+Mysql+Oracle 多数据源分布式事物后台搭建

    SpringBoot+Mybatis+Atomikos+Mysql+Oracle 多数据源分布式事物后台搭建 完整demo包,直接下下来解压,数据库配成自己的库,表自己的表,修改下脚本直接跑,网上大把资料,没一个能直接用的,这里花了点时间稍做...

Global site tag (gtag.js) - Google Analytics