SpringBoot和Mybatis配置多數(shù)據(jù)源連接多個(gè)數(shù)據(jù)庫(kù)


SpringBoot和Mybatis配置多數(shù)據(jù)源連接多個(gè)數(shù)據(jù)庫(kù)


目前業(yè)界操作數(shù)據(jù)庫(kù)的框架一般是 Mybatis昭躺,但在很多業(yè)務(wù)場(chǎng)景下近弟,我們需要在一個(gè)工程里配置多個(gè)數(shù)據(jù)源來(lái)實(shí)現(xiàn)業(yè)務(wù)邏輯壳鹤。在SpringBoot中也可以實(shí)現(xiàn)多數(shù)據(jù)源并配合Mybatis框架編寫xml文件來(lái)執(zhí)行SQL京髓。在SpringBoot中,配置多數(shù)據(jù)源的方式十分便捷或粮,

下面開(kāi)始上代碼:

  • pom.xml文件中需要添加一些依賴
<!-- Spring Boot Mybatis 依賴 -->
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>1.2.0</version>
</dependency>

<!-- MySQL 連接驅(qū)動(dòng)依賴 -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.39</version>
</dependency>

<!-- Druid 數(shù)據(jù)連接池依賴 -->
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.0.18</version>
</dependency>
  • application.properties 配置兩個(gè)數(shù)據(jù)源配置
# master 數(shù)據(jù)源配置
master.datasource.url=jdbc:mysql://localhost:3306/springbootdb?useUnicode=true&characterEncoding=utf8
master.datasource.username=root
master.datasource.password=321
master.datasource.driverClassName=com.mysql.jdbc.Driver

# second 數(shù)據(jù)源配置
second.datasource.url=jdbc:mysql://localhost:3306/springbootdb_second?useUnicode=true&characterEncoding=utf8
second.datasource.username=root
second.datasource.password=321
second.datasource.driverClassName=com.mysql.jdbc.Driver
  • 數(shù)據(jù)源配置
多數(shù)據(jù)源配置的時(shí)候注意导饲,必須要有一個(gè)主數(shù)據(jù)源捞高,即 MasterDataSourceConfig 配置
  • @Primary 標(biāo)志這個(gè) Bean 如果在多個(gè)同類 Bean 候選時(shí)氯材,該 Bean 優(yōu)先被考慮∠醺冢「多數(shù)據(jù)源配置的時(shí)候注意氢哮,必須要有一個(gè)主數(shù)據(jù)源,用 @Primary 標(biāo)志該 Bean
  • @MapperScan 掃描 Mapper 接口并容器管理型檀,包路徑精確到 master冗尤,為了和下面 cluster 數(shù)據(jù)源做到精確區(qū)分
  • @Value 獲取全局配置文件 application.properties 的 kv 配置,并自動(dòng)裝配sqlSessionFactoryRef 表示定義了 key ,表示一個(gè)唯一 SqlSessionFactory 實(shí)例

MasterDataSourceConfig的代碼:

@Configuration
// 掃描 Mapper 接口并容器管理
@MapperScan(basePackages = MasterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
 
    // 精確到 master 目錄胀溺,以便跟其他數(shù)據(jù)源隔離
    static final String PACKAGE = "org.spring.springboot.dao.master";
    static final String MAPPER_LOCATION = "classpath:mapper/master/*.xml";
 
    @Value("${master.datasource.url}")
    private String url;
 
    @Value("${master.datasource.username}")
    private String user;
 
    @Value("${master.datasource.password}")
    private String password;
 
    @Value("${master.datasource.driverClassName}")
    private String driverClass;
 
    @Bean(name = "masterDataSource")
    @Primary
    public DataSource masterDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }
 
    @Bean(name = "masterTransactionManager")
    @Primary
    public DataSourceTransactionManager masterTransactionManager() {
        return new DataSourceTransactionManager(masterDataSource());
    }
 
    @Bean(name = "masterSqlSessionFactory")
    @Primary
    public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(masterDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(MasterDataSourceConfig.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }
}

第二個(gè)數(shù)據(jù)源SecondDataSourceConfig的配置如下:

@Configuration
// 掃描 Mapper 接口并容器管理
@MapperScan(basePackages = SecondDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "secondSqlSessionFactory")
public class SecondDataSourceConfig {

    // 精確到 cluster 目錄裂七,以便跟其他數(shù)據(jù)源隔離
    static final String PACKAGE = "com.springboot.dao.second";
    static final String MAPPER_LOCATION = "classpath:mapper/second/*.xml";

    @Value("${second.datasource.url}")
    private String url;

    @Value("${second.datasource.username}")
    private String user;

    @Value("${second.datasource.password}")
    private String password;

    @Value("${second.datasource.driverClassName}")
    private String driverClass;

    @Bean(name = "secondDataSource")
    public DataSource clusterDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean(name = "secondTransactionManager")
    public DataSourceTransactionManager clusterTransactionManager() {
        return new DataSourceTransactionManager(clusterDataSource());
    }

    @Bean(name = "secondSqlSessionFactory")
    public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("secondDataSource") DataSource clusterDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(clusterDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(SecondDataSourceConfig.MAPPER_LOCATION));
        return sessionFactory.getObject();
    }
}

到此,不同的數(shù)據(jù)源配置就已經(jīng)完成仓坞,剩下的只需要將將Mybatis的xml文件和DAO層的接口寫好背零,并在Service層注入,直接使用就行无埃。

Service層的代碼:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private SchoolDao schoolDao;

    public UserVo getUser(Long id) {
        UserVo userVo = userDao.findById(id);
        SchoolVo schoolVo = schoolDao.findByName("清華");
        userVo.setSchoolVo(schoolVo);
        return userVo;
    }

}

Mybatis的xml文件UserDao.xmlSchoolDao.xml的內(nèi)容:

UserDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.springboot.dao.master.UserDao">
    <resultMap id="BaseResultMap" type="com.springboot.vo.UserVo">
        <result column="id" property="id" />
        <result column="user_name" property="userName" />
    </resultMap>

    <sql id="Base_Column_List">
        id, user_name
    </sql>

    <select id="findById" resultMap="BaseResultMap" parameterType="java.lang.Long">
        select
            <include refid="Base_Column_List" />
        from
            user
        where
            id = #{id}
    </select>
</mapper>

SchoolDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.springboot.dao.second.SchoolDao">
    <resultMap id="BaseResultMap" type="com.springboot.vo.SchoolVo">
        <result column="id" property="id" />
        <result column="school_name" property="schoolName" />
        <result column="school_describe" property="schoolDescribe" />
    </resultMap>

    <sql id="Base_Column_List">
        id, school_name, school_describe
    </sql>

    <select id="findByName" resultMap="BaseResultMap" parameterType="java.lang.String">
        select
            <include refid="Base_Column_List" />
        from
            school
        where
            school_name = #{schoolName}
    </select>

</mapper>

TestController

@Controller
@RequestMapping(value = "/api/v1/test")
public class TestController {

    @Autowired
    private UserService userService;

    @RequestMapping(value = "/getUser")
    @ResponseBody
    public UserVo getUser(@RequestParam(value = "id") Long id) {
        return userService.getUser(id);
    }

}

創(chuàng)建數(shù)據(jù)庫(kù)和表SQL:

CREATE DATABASE springbootdb;

CREATE DATABASE springbootdb_second;

CREATE TABLE `user` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '用戶編號(hào)',
  `user_name` varchar(25) DEFAULT NULL COMMENT '用戶名稱',
  `description` varchar(25) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

CREATE TABLE `school` (
  `id` bigint(20) NOT NULL,
  `school_name` varchar(64) DEFAULT NULL COMMENT '學(xué)校名',
  `school_describe` varchar(128) DEFAULT NULL COMMENT '學(xué)校描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

insert into `springbootdb`.`user` ( `user_name`, `description`) values ( 'shuai', 'so handsome');

insert into `springbootdb_second`.`school` ( `id`, `school_name`, `school_describe`) values ( '1', '清華', '自強(qiáng)不息徙瓶,厚德載物');

創(chuàng)建好數(shù)據(jù)后,整個(gè)工程的機(jī)構(gòu)如下:

啟動(dòng)程序嫉称,在瀏覽器輸入:http://localhost:8080/api/v1/test/getUser?id=1即可返回結(jié)果侦镇。

工程結(jié)構(gòu).png

github地址:Spring Boot 教程、技術(shù)棧织阅、示例代碼

歡迎關(guān)注公眾號(hào):java之旅

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末壳繁,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌闹炉,老刑警劉巖伍派,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異剩胁,居然都是意外死亡诉植,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門昵观,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)晾腔,“玉大人,你說(shuō)我怎么就攤上這事啊犬∽评蓿” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵觉至,是天一觀的道長(zhǎng)剔应。 經(jīng)常有香客問(wèn)我,道長(zhǎng)语御,這世上最難降的妖魔是什么峻贮? 我笑而不...
    開(kāi)封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮应闯,結(jié)果婚禮上纤控,老公的妹妹穿的比我還像新娘。我一直安慰自己碉纺,他們只是感情好船万,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著骨田,像睡著了一般耿导。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上态贤,一...
    開(kāi)封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天舱呻,我揣著相機(jī)與錄音,去河邊找鬼抵卫。 笑死狮荔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的介粘。 我是一名探鬼主播殖氏,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼姻采!你這毒婦竟也來(lái)了雅采?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎婚瓜,沒(méi)想到半個(gè)月后宝鼓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巴刻,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年愚铡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胡陪。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沥寥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出柠座,到底是詐尸還是另有隱情邑雅,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布妈经,位于F島的核電站淮野,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吹泡。R本人自食惡果不足惜骤星,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望荞胡。 院中可真熱鬧妈踊,春花似錦、人聲如沸泪漂。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)萝勤。三九已至,卻和暖如春呐伞,著一層夾襖步出監(jiān)牢的瞬間敌卓,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工伶氢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留趟径,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓癣防,卻偏偏與公主長(zhǎng)得像蜗巧,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蕾盯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理幕屹,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,633評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評(píng)論 6 342
  • 1. 簡(jiǎn)介 1.1 什么是 MyBatis 望拖? MyBatis 是支持定制化 SQL渺尘、存儲(chǔ)過(guò)程以及高級(jí)映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,455評(píng)論 0 4
  • 啟動(dòng)RESTful API應(yīng)用 在啟動(dòng)http server前,還需要完成以下四步: 初始化配置值 載入授權(quán)用的鍵...
    Cyberpunk_ZYM閱讀 2,221評(píng)論 0 2
  • 不知是粽子會(huì)飄香,還是粽葉會(huì)飄香盔沫,反正那一縷清香永遠(yuǎn)留在我心底锌雀,揮不去,抹不掉…… 端午吃粽子迅诬,賽龍舟腋逆,插艾蒿為了...
    虎笨笨閱讀 235評(píng)論 1 4