SpringBoot蜈块、Mybatis多數(shù)據(jù)源配置與事務(wù)管理

SpringBoot多數(shù)據(jù)源的基本配置

  1. 配置文件將數(shù)據(jù)源連接信息配置好迷扇,注意配置數(shù)據(jù)源的name屬性不要重復(fù)

  2. 創(chuàng)建配置類,構(gòu)建DataSource蜓席、DataSourceTransactionManager、SqlSessionFactory厨内、SqlSessionTemplate等對(duì)象祈秕。題主使用的springboot版本為2.2.6请毛,要求在構(gòu)建這些對(duì)象時(shí)添加@Primary注解,題主理解的是類似于指定主數(shù)據(jù)源瞭亮。

    示例代碼如下

    package com.demo.config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    
    import javax.sql.DataSource;
    
    @Configuration
    // 掃描 Mapper 接口并容器管理
    @MapperScan(basePackages = Ds1DataSourceConfig.PACKAGE,sqlSessionFactoryRef = "ds1SqlSessionFactory")//
    public class Ds1DataSourceConfig {
    
    
        // 精確到 firm 目錄,以便跟其他數(shù)據(jù)源隔離
        static final String PACKAGE = "com.demo.mapper.ds1";
        /**本數(shù)據(jù)源掃描的mapper路徑*/
        static final String MAPPER_LOCATION = "classpath:com/demo/mapper/ds1/*.xml";
    
        @Value("${spring.datasource.ds1.url}")
        private String url;
    
        @Value("${spring.datasource.ds1.username}")
        private String user;
    
        @Value("${spring.datasource.ds1.password}")
        private String password;
    
        @Value("${spring.datasource.ds1.driver-class-name}")
        private String driverClass;
        /**創(chuàng)建數(shù)據(jù)源*/
        @Bean(name = "ds1DataSource")
        @Primary
        public DataSource firmDataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(driverClass);
            dataSource.setUrl(url);
            dataSource.setUsername(user);
            dataSource.setPassword(password);
            return dataSource;
        }
        /**創(chuàng)建事務(wù)管理器*/
        @Bean(name = "ds1TransactionManager")
        @Primary
        public DataSourceTransactionManager firmTransactionManager() {
            return new DataSourceTransactionManager(firmDataSource());
        }
        /**創(chuàng)建SessionFactory*/
        @Bean(name = "ds1SqlSessionFactory")
        @Primary
        public SqlSessionFactory firmSqlSessionFactory()
                throws Exception {
            final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
            sessionFactory.setDataSource(firmDataSource());
    
            //支持屬性使用駝峰的命名,mapper配置不需要寫字段與屬性的配置此洲,會(huì)自動(dòng)映射。
            org.apache.ibatis.session.Configuration configuration = new                 org.apache.ibatis.session.Configuration();
            //使用jdbc的getGeneratedKeys獲取數(shù)據(jù)庫(kù)自增主鍵值
            configuration.setUseGeneratedKeys(true);
            //使用列別名替換列名 select user as User
            configuration.setUseColumnLabel(true);
            //-自動(dòng)使用駝峰命名屬性映射字段   userId    user_id
            configuration.setMapUnderscoreToCamelCase(true);
            //打印sql--需要調(diào)試時(shí)打開(kāi)
            //configuration.setLogImpl(StdOutImpl.class);
    
            sessionFactory.setConfiguration(configuration);
    
            //設(shè)置mapper配置文件
            sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                    .getResources(Ds1DataSourceConfig.MAPPER_LOCATION));
            return sessionFactory.getObject();
        }
    
        /**創(chuàng)建SqlSessionTemplate*/
        @Bean(name = "ds1SqlSessionTemplate")
        @Primary
        public SqlSessionTemplate firmSqlSessionTemplate(@Qualifier("ds1SqlSessionFactory") SqlSessionFactory sessionFactory) {
            return new SqlSessionTemplate(sessionFactory);
        }
    }
    
    

    其余數(shù)據(jù)源配置類似呜师,注意@Primary只在一個(gè)數(shù)據(jù)源中配置即可。多數(shù)據(jù)源mapper掃描位置盡量區(qū)分開(kāi)

  3. 創(chuàng)建測(cè)試類進(jìn)行測(cè)試匣掸,這里只貼serviceImpl,mapper以及xml自動(dòng)生成即可

    ds1:service

    package com.demo.service.Impl;
    
    import com.demo.entity.ds1.Demo;
    import com.demo.mapper.ds1.DemoMapper;
    import com.demo.service.DemoService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.math.BigDecimal;
    
    /**
     * @author zy
     * @version V1.0
     * @date 2022/9/7 17:52
     */
    @Service
    public class DemoServiceImpl implements DemoService {
        @Autowired
        private DemoMapper demoMapper;
    
        //因?yàn)槿执嬖诙鄠€(gè)事務(wù)控制器,這里開(kāi)啟事務(wù)時(shí)需要指定事務(wù)控制器
        @Transactional(transactionManager = "idsTransactionManager", rollbackFor = Exception.class)
        @Override
        public int insert(Demo demo) {
            demo.setId(new BigDecimal(66666));
            int insert = demoMapper.insert(demo);
            int s = insert / 0;
            return insert;
        }
    
    }
    

    ds2:service

    package com.demo.service.Impl;
    
    import com.demo.entity.ds2.Student;
    import com.demo.mapper.ds2.StudentMapper;
    import com.demo.service.StudentService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * @author zy
     * @version V1.0
     * @date 2022/9/7 17:53
     */
    @Service
    public class StudentServiceImpl implements StudentService {
        @Autowired
        private StudentMapper studentMapper;
        
        @Transactional(transactionManager = "ds2TransactionManager", rollbackFor = Exception.class)
        @Override
        public int insert(Student student) {
            student.setId(3L);
            int insert = studentMapper.insert(student);
            return insert;
        }
    }
    
    

    testService

    package com.demo.service.Impl;
    
    import com.demo.entity.ds1.Demo;
    import com.demo.entity.ds2.Student;
    import com.demo.service.DemoService;
    import com.demo.service.StudentService;
    import com.demo.service.TestService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    /**
     * @author zy
     * @version V1.0
     * @date 2022/9/7 18:10
     */
    @Service
    public class TestServiceImpl implements TestService {
        @Autowired
        private DemoService demoService;
        @Autowired
        private StudentService studentService;
    
        @Transactional(rollbackFor = Exception.class)
        @Override
        public void testTransactional() {
            studentService.insert(new Student());
            demoService.insert(new Demo());
        }
    }
    
    

    測(cè)試類

    package com.demo;
    
    import com.demo.entity.ds1.Demo;
    import com.demo.entity.ds2.Student;
    import com.demo.service.DemoService;
    import com.demo.service.StudentService;
    import com.demo.service.TestService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.context.web.WebAppConfiguration;
    
    /**
     * @description:
     * @author: wzy
     * @date: 2021/12/24 11:24
     * @version: V1.0
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @WebAppConfiguration
    public class DemoServiceImplTest {
        @Autowired
        private TestService testService;
        @Autowired
        private DemoService demoService;
        @Autowired
        private StudentService studentService;
    
        //測(cè)試事務(wù)
        @Test
        public void testTransactional() {
            testService.testTransactional();
        }
        //測(cè)試兩個(gè)數(shù)據(jù)源
        @Test
        public void testInsert() {
            demoService.insert(new Demo());
            studentService.insert(new Student());
        }
    
    }
    
  4. 執(zhí)行testTransactional會(huì)發(fā)現(xiàn),拋出異常戴差,但是student數(shù)據(jù)沒(méi)有回滾。

多數(shù)據(jù)源的事務(wù)管理

多數(shù)據(jù)源事務(wù)控制需要引入spring-boot-starter-jta-atomikos暖释,maven依賴如下

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

將上述數(shù)據(jù)源配置類只需要將DataSource創(chuàng)建為XAdDataSource并且使用AtomikosDataSourceBean進(jìn)行管理即可。同時(shí)注掉DataSourceTransactionManager球匕,因?yàn)槲覀兊氖聞?wù)管交由spring管理,不需要為每個(gè)數(shù)據(jù)源指定事務(wù)管理器帖烘。

如下

/**創(chuàng)建數(shù)據(jù)源*/
   @Bean(name = "ds1DataSource")
   @Primary
   public DataSource firmDataSource() throws SQLException {
       DruidXADataSource xa = new DruidXADataSource();
       xa.setUrl(url);
       xa.setUsername(user);
       xa.setPassword(password);
       xa.setDbType(JdbcUtils.ORACLE);
       xa.setDriverClassName(driverClass);
       AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
       xaDataSource.setXaDataSource(xa);
       xaDataSource.setUniqueResourceName("ds1");
       return xaDataSource;
   }
   /**創(chuàng)建事務(wù)管理器*/
   /*@Bean(name = "ds1TransactionManager")
   @Primary
   public DataSourceTransactionManager firmSqlSessionFactory() {
       return new DataSourceTransactionManager(firmDataSource());
   }*/

同時(shí)修改service層的事務(wù)注解

    @Transactional(rollbackFor = Exception.class)
    //@Transactional(transactionManager = "idsTransactionManager", rollbackFor = Exception.class)
    @Override
    public int insert(Demo demo) {
        demo.setId(new BigDecimal(66666));
        int insert = demoMapper.insert(demo);
        int s = insert / 0;
        return insert;
    }
//    @Transactional(transactionManager = "yzxTransactionManager", rollbackFor = Exception.class)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insert(Student student) {
        student.setId(3L);
        int insert = studentMapper.insert(student);
        return insert;
    }

再次執(zhí)行測(cè)試類,可以發(fā)現(xiàn)照卦,拋出異常的同時(shí),student也進(jìn)行了回滾.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末役耕,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子聪廉,更是在濱河造成了極大的恐慌,老刑警劉巖板熊,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異邻邮,居然都是意外死亡竣况,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門情萤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人摹恨,你說(shuō)我怎么就攤上這事∩购澹” “怎么了睁宰?”我有些...
    開(kāi)封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵柒傻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我较木,道長(zhǎng),這世上最難降的妖魔是什么伐债? 我笑而不...
    開(kāi)封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮峰锁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘虹蒋。我一直安慰自己糜芳,他們只是感情好魄衅,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著徐绑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪傲茄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天盘榨,我揣著相機(jī)與錄音喻粹,去河邊找鬼草巡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的查乒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼玛迄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蓖议?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤勒虾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后修然,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體州弟,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年拯杠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潭陪。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖依溯,靈堂內(nèi)的尸體忽然破棺而出老厌,到底是詐尸還是另有隱情黎炉,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布慷嗜,位于F島的核電站,受9級(jí)特大地震影響庆械,放射性物質(zhì)發(fā)生泄漏薇溃。R本人自食惡果不足惜缭乘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧策幼,春花似錦、人聲如沸垄惧。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)铣口。三九已至觉壶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铜靶,已是汗流浹背叔遂。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工争剿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚕苇。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像涩笤,于是被迫代替她去往敵國(guó)和親嚼吞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蹬碧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容