5分鐘學(xué)會(huì)springboot整合多數(shù)據(jù)源解決分布式事務(wù)

一、前言

springboot整合多數(shù)據(jù)源解決分布式事務(wù)合武。
?????1.多數(shù)據(jù)源采用分包策略
?????2.全局分布式事務(wù)管理:jta-atomikos。
在此記錄下,分享給大家客给。


二袜漩、springboot整合多數(shù)據(jù)源解決分布式事務(wù)

1甜害、pom文件 依賴引入

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

    <dependencies>
        <!-- SpringBoot 測(cè)試 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- SpringBoot web組件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- mybatis 支持 SpringBoot -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>

        <!-- mysql 驅(qū)動(dòng) -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <!-- 全局事務(wù)集中管理 解決分布式事務(wù) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jta-atomikos</artifactId>
        </dependency>

        <!-- SpringBoot 自動(dòng)配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- 注解式 插入/構(gòu)建/優(yōu)雅代碼 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.4</version>
        </dependency>
    </dependencies>

2通砍、 application.yml 新增配置

spring:
  datasource:
    ## 用戶數(shù)據(jù)庫(kù)
    user:
      url: jdbc:mysql://127.0.0.1:3306/yys_user
      username: root
      password: 123456
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60
      maxLifetime: 20000
      maxPoolSize: 25
      minPoolSize: 3
      uniqueResourceName: userDataSource
      testQuery: select 1
    ## 訂單數(shù)據(jù)庫(kù)
    order:
      url: jdbc:mysql://127.0.0.1:3306/yys_order
      username: root
      password: 123456
      borrowConnectionTimeout: 30
      loginTimeout: 30
      maintenanceInterval: 60
      maxIdleTime: 60
      maxLifeTime: 20000
      maxPoolSize: 25
      minPoolSize: 3
      uniqueResourceName: orderDataSource
      testQuery: select 1

3、userConfig.java

@ConfigurationProperties(prefix = "spring.datasource.user")
@Data
public class UserConfig {

    private String url;

    private String userName;

    private String password;

    private int minPoolSize;

    private int maxPoolSize;

    private int maxLifeTime;

    private int maxIdleTime;

    private int loginTimeout;

    private int maintenanceInterval;

    private int borrowConnectionTimeout;

    private String testQuery;

    private String uniqueResourceName;

}

4前域、userDataSourceConfig.java

/**
 * 用戶數(shù)據(jù)源
 *      Config
 * @author yys
 */
@Configuration
@MapperScan(basePackages = "com.yys.user.mapper", sqlSessionTemplateRef = "userSqlSessionTemplate")
public class UserDataSourceConfig {

    /**
     * 創(chuàng)建 XADataSource
     * @return
     */
    @Bean("userDataSource")
    public DataSource userDataSource(UserConfig userConfig) throws SQLException {
        // 1辕近、創(chuàng)建Mysql XADataSource
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        mysqlXaDataSource.setUrl(userConfig.getUrl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(userConfig.getPassword());
        mysqlXaDataSource.setUser(userConfig.getUserName());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

        // 2、將本地事務(wù)注冊(cè)到 Atomikos 全局事務(wù)
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName(userConfig.getUniqueResourceName());
        xaDataSource.setMinPoolSize(userConfig.getMinPoolSize());
        xaDataSource.setMaxPoolSize(userConfig.getMaxPoolSize());
        xaDataSource.setMaxLifetime(userConfig.getMaxLifeTime());
        xaDataSource.setBorrowConnectionTimeout(userConfig.getBorrowConnectionTimeout());
        xaDataSource.setLoginTimeout(userConfig.getLoginTimeout());
        xaDataSource.setMaintenanceInterval(userConfig.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(userConfig.getMaxIdleTime());
        xaDataSource.setTestQuery(userConfig.getTestQuery());

        return xaDataSource;
    }

    /**
     * 創(chuàng)建 SQL會(huì)話工廠
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean("userSqlSessionFactory")
    public SqlSessionFactory userSqlSessionFactory(@Qualifier("userDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * 創(chuàng)建用戶 SqlSession模板
     * @param sqlSessionFactory
     * @return
     */
    @Bean("userSqlSessionTemplate")
    public SqlSessionTemplate userSqlSessionTemplate(@Qualifier("userSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

5匿垄、orderConfig.java

@ConfigurationProperties(prefix = "spring.datasource.order")
@Data
public class OrderConfig {

    private String url;

    private String userName;

    private String password;

    private int minPoolSize;

    private int maxPoolSize;

    private int maxLifeTime;

    private int maxIdleTime;

    private int loginTimeout;

    private int maintenanceInterval;

    private int borrowConnectionTimeout;

    private String testQuery;

    private String uniqueResourceName;

}

6移宅、orderDataSourceConfig.java

/**
 * 訂單數(shù)據(jù)源
 *      Config
 * @author yys
 */
@Configuration
@MapperScan(basePackages = "com.yys.order.mapper", sqlSessionTemplateRef = "orderSqlSessionTemplate")
public class OrderDataSourceConfig {

    /**
     * 創(chuàng)建 XADataSource
     * @return
     */
    @Bean("orderDataSource")
    public DataSource orderDataSource(OrderConfig orderConfig) throws SQLException {

        // 1、創(chuàng)建Mysql XADataSource
        MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
        mysqlXaDataSource.setUrl(orderConfig.getUrl());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
        mysqlXaDataSource.setPassword(orderConfig.getPassword());
        mysqlXaDataSource.setUser(orderConfig.getUserName());
        mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);

        // 2椿疗、將本地事務(wù)注冊(cè)到 Atomikos 全局事務(wù)
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
        xaDataSource.setXaDataSource(mysqlXaDataSource);
        xaDataSource.setUniqueResourceName(orderConfig.getUniqueResourceName());
        xaDataSource.setMinPoolSize(orderConfig.getMinPoolSize());
        xaDataSource.setMaxPoolSize(orderConfig.getMaxPoolSize());
        xaDataSource.setMaxLifetime(orderConfig.getMaxLifeTime());
        xaDataSource.setBorrowConnectionTimeout(orderConfig.getBorrowConnectionTimeout());
        xaDataSource.setLoginTimeout(orderConfig.getLoginTimeout());
        xaDataSource.setMaintenanceInterval(orderConfig.getMaintenanceInterval());
        xaDataSource.setMaxIdleTime(orderConfig.getMaxIdleTime());
        xaDataSource.setTestQuery(orderConfig.getTestQuery());

        return xaDataSource;
    }

    /**
     * 創(chuàng)建 SQL會(huì)話工廠
     * @param dataSource
     * @return
     * @throws Exception
     */
    @Bean("orderSqlSessionFactory")
    public SqlSessionFactory orderSqlSessionFactory(@Qualifier("orderDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean.getObject();
    }

    /**
     * 創(chuàng)建訂單 SqlSession模板
     * @param sqlSessionFactory
     * @return
     */
    @Bean("orderSqlSessionTemplate")
    public SqlSessionTemplate orderSqlSessionTemplate(@Qualifier("orderSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

}

7漏峰、MybatisController.java

/**
 * 多數(shù)據(jù)源解決分布式事務(wù)測(cè)試
 *      Controller
 * @author yys
 */
@RestController
@RequestMapping("/add")
public class MybatisController {

    @Autowired
    private UserService userService;

    @Autowired
    private OrderService orderService;

    /**
     * 新增用戶并生成訂單(解決分布式事務(wù)問(wèn)題)
     * @return
     */
    @RequestMapping("/user")
    public String addUser(String name, Integer age, Double amount, String address) {
        return userService.addUser(name, age, amount, address) ? "success" : "fail";
    }

}

8、UserService.java

/**
 * 用戶管理
 *      Service
 * @author yys
 */
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private OrderMapper orderMapper;

    // 全局事務(wù)處理器
    // 事務(wù)底層原理采用aop技術(shù)做增強(qiáng)
    // 無(wú)需再指定某個(gè)事務(wù)管理器届榄,全交給 Atomikos 全局事務(wù)
    @Transactional
    public Boolean addUser(String name, Integer age, Double amount, String address) {

        // 操作用戶庫(kù)
        int i = userMapper.addUser(name, age);
        // 操作訂單庫(kù)
        int j = orderMapper.addOrder(amount, address);

        // 測(cè)試事務(wù)回滾(age = 0:回滾浅乔;age > 0:事務(wù)提交)
        int flag = 1 / age;

        return i > 0 && j > 0;
    }

}

9、UserMapper.java

/**
 * 用戶管理
 *      Mapper
 * @author yys
 */
public interface UserMapper {

    @Insert("INSERT INTO user VALUES (NULL, #{name}, #{age}, 1, NOW(), NOW())")
    int addUser(@Param("name") String name, @Param("age") Integer age);

}

10铝条、OrderMapper.java

/**
 * 訂單管理
 *      Mapper
 * @author yys
 */
public interface OrderMapper {

    // order為數(shù)據(jù)庫(kù)關(guān)鍵字靖苇,記得使用``
    @Insert("INSERT INTO `order` VALUES (NULL, #{amount}, #{address}, 1, NOW(), NOW())")
    int addOrder(@Param("amount") Double amount, @Param("address") String address);

}

11、啟動(dòng)類(lèi)

@SpringBootApplication
@MapperScan("com.yys.mapper")
public class YysApp {

    public static void main(String[] args) {
        SpringApplication.run(YysApp.class, args);
    }

}

12班缰、初始化sql文件


-- Database:yys_user

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'ID贤壁,自增列',
  `name` varchar(32) NOT NULL COMMENT '用戶名',
  `age` int(11) NOT NULL COMMENT '用戶年齡',
  `status` tinyint(2) NOT NULL DEFAULT '1' COMMENT '狀態(tài):-1-刪除;1-正常鲁捏;',
  `create_time` datetime NOT NULL COMMENT '創(chuàng)建時(shí)間',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

-- Database:yys_order

DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT 'ID芯砸,自增列',
  `amount` double(11,2) NOT NULL COMMENT '訂單金額',
  `address` varchar(32) NOT NULL COMMENT '地址',
  `status` tinyint(2) NOT NULL DEFAULT '1' COMMENT '狀態(tài):-1-刪除萧芙;1-正常给梅;',
  `create_time` datetime NOT NULL COMMENT '創(chuàng)建時(shí)間',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時(shí)間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

13、測(cè)試

http://localhost:8080/add/user?name=古猿&age=0&amount=12.02&address=南方

a双揪、頁(yè)面結(jié)果 - 如下圖所示 :

b动羽、數(shù)據(jù)庫(kù)結(jié)果 - 如下圖所示 :

http://localhost:8080/add/user?name=古猿&age=18&amount=12.02&address=南方

a、頁(yè)面結(jié)果 - 如下圖所示 :

b渔期、數(shù)據(jù)庫(kù)結(jié)果 - 如下圖所示 :

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末运吓,一起剝皮案震驚了整個(gè)濱河市渴邦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拘哨,老刑警劉巖谋梭,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異倦青,居然都是意外死亡瓮床,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)产镐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)隘庄,“玉大人,你說(shuō)我怎么就攤上這事癣亚〕蟛簦” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵述雾,是天一觀的道長(zhǎng)街州。 經(jīng)常有香客問(wèn)我,道長(zhǎng)绰咽,這世上最難降的妖魔是什么菇肃? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮取募,結(jié)果婚禮上琐谤,老公的妹妹穿的比我還像新娘。我一直安慰自己玩敏,他們只是感情好斗忌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著旺聚,像睡著了一般织阳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砰粹,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天唧躲,我揣著相機(jī)與錄音,去河邊找鬼碱璃。 笑死弄痹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的嵌器。 我是一名探鬼主播肛真,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼爽航!你這毒婦竟也來(lái)了蚓让?” 一聲冷哼從身側(cè)響起乾忱,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎历极,沒(méi)想到半個(gè)月后窄瘟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡趟卸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年寞肖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衰腌。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡新蟆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出右蕊,到底是詐尸還是另有隱情琼稻,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布饶囚,位于F島的核電站帕翻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏萝风。R本人自食惡果不足惜嘀掸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望规惰。 院中可真熱鬧睬塌,春花似錦、人聲如沸歇万。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)贪磺。三九已至硫兰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寒锚,已是汗流浹背劫映。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留刹前,地道東北人泳赋。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像腮郊,于是被迫代替她去往敵國(guó)和親摹蘑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子筹燕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354