springboot + mybatis配置多数据源示例
转:http://www.jb51.net/article/107223.htm
在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源。
代码结构:

简要原理:
1)DatabaseType列出所有的数据源的key---key
2)DatabaseContextHolder是一个线程安全的DatabaseType容器,并提供了向其中设置和获取DatabaseType的方法
3)DynamicDataSource继承AbstractRoutingDataSource并重写其中的方法determineCurrentLookupKey(),在该方法中使用DatabaseContextHolder获取当前线程的DatabaseType
4)MyBatisConfig中生成2个数据源DataSource的bean---value
5)MyBatisConfig中将1)和4)组成的key-value对写入到DynamicDataSource动态数据源的targetDataSources属性(当然,同时也会设置2个数据源其中的一个为DynamicDataSource的defaultTargetDataSource属性中)
6)将DynamicDataSource作为primary数据源注入到SqlSessionFactory的dataSource属性中去,并且该dataSource作为transactionManager的入参来构造DataSourceTransactionManager
7)使用的时候,在dao层或service层先使用DatabaseContextHolder设置将要使用的数据源key,然后再调用mapper层进行相应的操作,建议放在dao层去做(当然也可以使用spring aop+自定注解去做)
注意:在mapper层进行操作的时候,会先调用determineCurrentLookupKey()方法获取一个数据源(获取数据源:先根据设置去targetDataSources中去找,若没有,则选择defaultTargetDataSource),之后在进行数据库操作。
1、假设有两个数据库,配置如下
application.properties
|
1
2
3
4
5
6
7
8
9
10
11
|
#the first datasourcejdbc.driverClassName = com.mysql.jdbc.Driverjdbc.url = jdbc:mysql://xxx:3306/mytestdb?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8jdbc.username = rootjdbc.password = 123#the second datasourcejdbc2.driverClassName = com.mysql.jdbc.Driverjdbc2.url = jdbc:mysql://xxx:3306/mytestdb2?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8jdbc2.username = rootjdbc2.password = 123 |
说明:在之前的配置的基础上,只增加了上述的第二个数据源。
2、DatabaseType
|
1
2
3
4
5
6
7
8
9
10
11
|
package com.xxx.firstboot.common.datasource;/** * 列出所有的数据源key(常用数据库名称来命名) * 注意: * 1)这里数据源与数据库是一对一的 * 2)DatabaseType中的变量名称就是数据库的名称 */public enum DatabaseType { mytestdb,mytestdb2} |
作用:列举数据源的key。
3、DatabaseContextHolder
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.xxx.firstboot.common.datasource;/** * 作用: * 1、保存一个线程安全的DatabaseType容器 */public class DatabaseContextHolder { private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>(); public static void setDatabaseType(DatabaseType type){ contextHolder.set(type); } public static DatabaseType getDatabaseType(){ return contextHolder.get(); }} |
作用:构建一个DatabaseType容器,并提供了向其中设置和获取DatabaseType的方法
4、DynamicDataSource
|
1
2
3
4
5
6
7
8
9
10
11
12
|
package com.xxx.firstboot.common.datasource;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * 动态数据源(需要继承AbstractRoutingDataSource) */public class DynamicDataSource extends AbstractRoutingDataSource { protected Object determineCurrentLookupKey() { return DatabaseContextHolder.getDatabaseType(); }} |
作用:使用DatabaseContextHolder获取当前线程的DatabaseType
5、MyBatisConfig
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
package com.xxx.firstboot.common;import java.util.HashMap;import java.util.Map;import java.util.Properties;import javax.sql.DataSource;import org.apache.ibatis.session.SqlSessionFactory;import org.mybatis.spring.SqlSessionFactoryBean;import org.mybatis.spring.annotation.MapperScan;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Primary;import org.springframework.core.env.Environment;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import com.alibaba.druid.pool.DruidDataSourceFactory;import com.xxx.firstboot.common.datasource.DatabaseType;import com.xxx.firstboot.common.datasource.DynamicDataSource;/** * springboot集成mybatis的基本入口 1)创建数据源(如果采用的是默认的tomcat-jdbc数据源,则不需要) * 2)创建SqlSessionFactory 3)配置事务管理器,除非需要使用事务,否则不用配置 */@Configuration // 该注解类似于spring配置文件@MapperScan(basePackages = "com.xxx.firstboot.mapper")public class MyBatisConfig { @Autowired private Environment env; /** * 创建数据源(数据源的名称:方法名可以取为XXXDataSource(),XXX为数据库名称,该名称也就是数据源的名称) */ @Bean public DataSource myTestDbDataSource() throws Exception { Properties props = new Properties(); props.put("driverClassName", env.getProperty("jdbc.driverClassName")); props.put("url", env.getProperty("jdbc.url")); props.put("username", env.getProperty("jdbc.username")); props.put("password", env.getProperty("jdbc.password")); return DruidDataSourceFactory.createDataSource(props); } @Bean public DataSource myTestDb2DataSource() throws Exception { Properties props = new Properties(); props.put("driverClassName", env.getProperty("jdbc2.driverClassName")); props.put("url", env.getProperty("jdbc2.url")); props.put("username", env.getProperty("jdbc2.username")); props.put("password", env.getProperty("jdbc2.password")); return DruidDataSourceFactory.createDataSource(props); } /** * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错 * @Qualifier 根据名称进行注入,通常是在具有相同的多个类型的实例的一个注入(例如有多个DataSource类型的实例) */ @Bean @Primary public DynamicDataSource dataSource(@Qualifier("myTestDbDataSource") DataSource myTestDbDataSource, @Qualifier("myTestDb2DataSource") DataSource myTestDb2DataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DatabaseType.mytestdb, myTestDbDataSource); targetDataSources.put(DatabaseType.mytestdb2, myTestDb2DataSource); DynamicDataSource dataSource = new DynamicDataSource(); dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法 dataSource.setDefaultTargetDataSource(myTestDbDataSource);// 默认的datasource设置为myTestDbDataSource return dataSource; } /** * 根据数据源创建SqlSessionFactory */ @Bean public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception { SqlSessionFactoryBean fb = new SqlSessionFactoryBean(); fb.setDataSource(ds);// 指定数据源(这个必须有,否则报错) // 下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加 fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));// 指定基包 fb.setMapperLocations( new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations")));// return fb.getObject(); } /** * 配置事务管理器 */ @Bean public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception { return new DataSourceTransactionManager(dataSource); }} |
作用:
- 通过读取application.properties文件生成两个数据源(myTestDbDataSource、myTestDb2DataSource)
- 使用以上生成的两个数据源构造动态数据源dataSource
- @Primary:指定在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@Autowire注解报错(一般用于多数据源的情况下)
- @Qualifier:指定名称的注入,当一个接口有多个实现类的时候使用(在本例中,有两个DataSource类型的实例,需要指定名称注入)
- @Bean:生成的bean实例的名称是方法名(例如上边的@Qualifier注解中使用的名称是前边两个数据源的方法名,而这两个数据源也是使用@Bean注解进行注入的)
- 通过动态数据源构造SqlSessionFactory和事务管理器(如果不需要事务,后者可以去掉)
6、使用
ShopMapper:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
package com.xxx.firstboot.mapper;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Result;import org.apache.ibatis.annotations.Results;import org.apache.ibatis.annotations.Select;import com.xxx.firstboot.domain.Shop;public interface ShopMapper { @Select("SELECT * FROM t_shop WHERE id = #{id}") @Results(value = { @Result(id = true, column = "id", property = "id"), @Result(column = "shop_name", property = "shopName") }) public Shop getShop(@Param("id") int id);} |
ShopDao:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.xxx.firstboot.dao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Repository;import com.xxx.firstboot.common.datasource.DatabaseContextHolder;import com.xxx.firstboot.common.datasource.DatabaseType;import com.xxx.firstboot.domain.Shop;import com.xxx.firstboot.mapper.ShopMapper;@Repositorypublic class ShopDao { @Autowired private ShopMapper mapper; /** * 获取shop */ public Shop getShop(int id) { DatabaseContextHolder.setDatabaseType(DatabaseType.mytestdb2); return mapper.getShop(id); }} |
注意:首先设置了数据源的key,然后调用mapper(在mapper中会首先根据该key从动态数据源中查询出相应的数据源,之后取出连接进行数据库操作)
ShopService:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package com.xxx.firstboot.service;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.xxx.firstboot.dao.ShopDao;import com.xxx.firstboot.domain.Shop;@Servicepublic class ShopService { @Autowired private ShopDao dao; public Shop getShop(int id) { return dao.getShop(id); }} |
ShopController:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
package com.xxx.firstboot.web;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;import com.xxx.firstboot.domain.Shop;import com.xxx.firstboot.service.ShopService;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;@RestController@RequestMapping("/shop")@Api("shopController相关api")public class ShopController { @Autowired private ShopService service; @ApiOperation("获取shop信息,测试多数据源") @RequestMapping(value = "/getShop", method = RequestMethod.GET) public Shop getShop(@RequestParam("id") int id) { return service.getShop(id); }} |
补:其实DatabaseContextHolder和DynamicDataSource完全可以合为一个类
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
springboot + mybatis配置多数据源示例的更多相关文章
- SpringBoot+MyBatis配置多数据源
SpringBoot 可以支持多数据源,这是一个非常值得学习的功能,但是从现在主流的微服务的架构模式中,每个应用都具有唯一且准确的功能,多数据源的需求很难用到,考虑到实际情况远远比理论复杂的多,这里还 ...
- SpringBoot MyBatis 配置多数据源 (静态多个)
转载地址:https://www.jianshu.com/p/118ca1d5ecf9?utm_campaign=haruki&utm_content=note&utm_medium= ...
- springboot入门系列(四):SpringBoot和Mybatis配置多数据源连接多个数据库
SpringBoot和Mybatis配置多数据源连接多个数据库 目前业界操作数据库的框架一般是 Mybatis,但在很多业务场景下,我们需要在一个工程里配置多个数据源来实现业务逻辑.在SpringBo ...
- SpringBoot集成Mybatis配置动态数据源
很多人在项目里边都会用到多个数据源,下面记录一次SpringBoot集成Mybatis配置多数据源的过程. pom.xml <?xml version="1.0" encod ...
- springboot和mybatis 配置多数据源
主数据源(由于代码没有办法复制的原因,下面图片和文字不一致) package com.zhianchen.mysqlremark.toword.config;import com.zaxxer.hik ...
- Spring Boot + Mybatis 配置多数据源
Spring Boot + Mybatis 配置多数据源 Mybatis拦截器,字段名大写转小写 package com.sgcc.tysj.s.common.mybatis; import java ...
- spring+myBatis 配置多数据源,切换数据源
注:本文来源于 tianzhiwuqis <spring+myBatis 配置多数据源,切换数据源> 一个项目里一般情况下只会使用到一个数据库,但有的需求是要显示其他数据库的内容,像这样 ...
- SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页
SpringBoot+Mybatis配置Pagehelper分页插件实现自动分页 **SpringBoot+Mybatis使用Pagehelper分页插件自动分页,非常好用,不用在自己去计算和组装了. ...
- springboot+mybatis集成多数据源MySQL/Oracle/SqlServer
日常开发中可能时常会遇到一些这样的需求,业务数据库和第三方数据库,两个或多个数据库属于不同数据库厂商,这时候就需要通过配置来实现对数据库实现多源处理.大致说一下我的业务场景,框架本身是配置的sprin ...
随机推荐
- 设计模式 uml元素
uml的构造包含3种 事物4种:结构,行为,分组,注释事物 关系4种:泛化,实现,依赖,关联, 图10种,用例图,类图,对象,包,组件,部署,状态,活动,序列,协作 事物是对模型中最具代表性的成分的抽 ...
- get****Context各个方法分析
1 getApplicationContext分析 该方法为contextImpl类的方法,返回一个ApplicationContext.方法代码为: public Context getApplic ...
- envsetup.sh 与 choosecombo
choose: 来定义编译选项, choosecombo 将会一步一步提示你输入相应的编译参数 https://blog.csdn.net/kickxxx/article/details/692518 ...
- white-space使用注意事项
今天写移动端的时候有个地方需要横向滚动的功能,自然而然需要用到white-space这个属性了,但是试了一下发现没有效果,反复查找原因后,发现white-space是对inline-block起作用的 ...
- 【07】node 之 Buffer
1.1. Buffer基本概念 JavaScript 语言自身只有字符串数据类型,没有二进制数据类型.二进制可以存储电脑中任何数据(比如:一段文本.一张图片.一个硬盘,应该说电脑中所有的数据都是二进 ...
- Mysql EXISTS NOT EXISTS
SELECT c.CustomerId, CompanyName FROM Customers c WHERE EXISTS( SELECT OrderID FROM Orders o WHERE o ...
- Python操作MySQL[转]
本篇对于Python操作MySQL主要使用两种方式: 1.原生模块pymsql. 2.ORM框架SQLAchemy. pymsql pymsql是Python中操作MySQL的模块,其使用方法和MyS ...
- .NET结束外部进程 C#结束外部进程
原文发布时间为:2011-02-15 -- 来源于本人的百度文章 [由搬家工具导入] using System;namespace ConsoleApplication2{ class Prog ...
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---51
以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:
- Ubuntu FireFox的“后退”按钮与Backspace键
我们都知道,大部分的网页浏览器和窗口管理器的“后退”按钮是和Backspace键关联的,这样会极大的方便并加快我们浏览时的翻页速度(我一直是左手 放在键盘上按快捷键,右手鼠标的姿势找文件和看网页的,省 ...