最近在項目開發中,須要爲一個使用 MySQL 數據庫的 SpringBoot 項目,新添加一個 PLSQL 數據庫數據源,那麼就須要進行 SpringBoot 的多數據源開發。代碼很簡單,下面是實現的過程。java
實驗環境:mysql
由於我本地只有 MySQL 數據庫,爲了方便演示,我會在啓動一個本地 MySQL,在 MySQL 建立兩個數據庫,每一個庫中均有一個表,以此進行演示。git
本地 MySQL 端口默認不作改動,端口號 3306。github
建立數據庫 demo1,demo2。在 demo1 數據庫中建立表 book。web
-- create table create table Book ( id int auto_increment primary key, author varchar(64) not null comment '做者信息', name varchar(64) not null comment '書籍名稱', price decimal not null comment '價格', createTime datetime null comment '上架時間', description varchar(128) null comment '書籍描述' ); -- insert data INSERT INTO demo1.Book (id, author, name, price, createTime, description) VALUES (1, '金庸', '笑傲江湖', 13, '2020-12-19 15:26:51', '武俠小說'); INSERT INTO demo1.Book (id, author, name, price, createTime, description) VALUES (2, '羅貫中', '三國演義', 14, '2020-12-19 15:28:36', '歷史小說');
在 demo2 數據庫中建立表 user。spring
-- create table create table User ( id int auto_increment primary key, name varchar(32) null comment '用戶名稱', birthday date null comment '出生日期' ) comment '用戶信息表'; -- insert data INSERT INTO demo2.User (id, name, birthday) VALUES (1, '金庸', '1924-03-10'); INSERT INTO demo2.User (id, name, birthday) VALUES (2, '羅貫中', '1330-01-10');
數據準備完畢,表中都新增了兩條數據。sql
這裏直接從 Spring 官方上初始化一個添加了 web、lombok、mybatis、mysql 依賴的 SpringBoot 項目。shell
若是你手上已經有了一個 SpringBoot 項目,既然你想改形成多數據源,那麼你應該已經有了一個數據源了,若是新增的數據源數據庫和目前的一致,你能夠直接使用你的項目進行改造測試。springboot
SpringBoot 的多數據源開發十分簡單,若是多個數據源的數據庫相同,好比都是 MySQL,那麼依賴是不須要任何改動的,只須要進行多數據源配置便可。
若是你新增的數據庫數據源和目前的數據庫不一樣,記得引入新數據庫的驅動依賴,好比 MySQL 和 PGSQL。
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.2.7</version> </dependency>
既然有多個數據源,由於數據庫用戶名密碼可能不相同,因此是須要配置多個數據源信息的,直接在 properties/yml
中配置便可。這裏要注意根據配置的屬性名進行區分,同時由於數據源要有一個默認使用的數據源,最好在名稱上有所區分(這裏使用 primary 做爲主數據源標識)。
########################## 主數據源 ################################## spring.datasource.primary.jdbc-url=jdbc:mysql://127.0.0.1:3306/demo1?characterEncoding=utf-8&serverTimezone=GMT%2B8 spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver spring.datasource.primary.username=root spring.datasource.primary.password= ########################## 第二個數據源 ############################### spring.datasource.datasource2.jdbc-url=jdbc:mysql://127.0.0.1:3306/demo2?characterEncoding=utf-8&serverTimezone=GMT%2B8 spring.datasource.datasource2.driver-class-name=com.mysql.jdbc.Driver spring.datasource.datasource2.username=root spring.datasource.datasource2.password= # mybatis mybatis.mapper-locations=classpath:mapper/*.xml mybatis.type-aliases-package=com.wdbyte.domain
注意,配置中的數據源鏈接 url 末尾使用的是 jdbc-url
.
由於使用了 Mybatis 框架,因此 Mybatis 框架的配置信息也是少不了的,指定掃描目錄 mapper
下的mapper xml
配置文件。
如何編寫 Mybatis Mapper 或者如何使用工具生成 Mybatis Mapper
不是本文的重點,若是你不知道能夠參考 Mybatis 官方文檔或者我以前的文章。
連接二:使用 Mybatis 集成 pagehelper 分頁插件和 mapper 插件
下面我已經按照上面的兩個庫中的兩個表,Book 和 User 表分別編寫相應的 Mybatis 配置。
建立 BookMapper.xml
和 UserMapper.xml
放到配置文件配置的路徑 mapper 目錄下。建立 UserMapper 和 BookMapper 接口操做類放在不一樣的目錄。這裏注意 Mapper 接口要按數據源分開放在不一樣的目錄中。後續好使用不一樣的數據源配置掃描不一樣的目錄,這樣就能夠實現不一樣的 Mapper 使用不一樣的數據源配置。
Service 層沒有變化,這裏 BookMapper 和 UserMapper 都有一個 selectAll()
方法用於查詢測試。
上面你應該看到了,到目前爲止和 Mybatis 單數據源寫法惟一的區別就是 Mapper 接口使用不一樣的目錄分開了,那麼這個不一樣點必定會在數據源配置中體現。
開始配置兩個數據源信息,先配置主數據源,配置掃描的 MapperScan
目錄爲 com.wdbyte.mapper.primary
/** * 主數據源配置 * * @author niujinpeng * @website: https://www.wdbyte.com * @date 2020/12/19 */ @Configuration @MapperScan(basePackages = {"com.wdbyte.mapper.primary"}, sqlSessionFactoryRef = "sqlSessionFactory") public class PrimaryDataSourceConfig { @Bean(name = "dataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") @Primary public DataSource dataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "sqlSessionFactory") @Primary public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml")); return bean.getObject(); } @Bean(name = "transactionManager") @Primary public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "sqlSessionTemplate") @Primary public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
和單數據源不一樣的是這裏把
dataSource
sqlSessionFactory
transactionManager
sqlSessionTemplate
都單獨進行了配置,簡單的 bean 建立,下面是用到的一些註解說明。
@ConfigurationProperties(prefix = "spring.datasource.primary")
:使用spring.datasource.primary 開頭的配置。@Primary
:聲明這是一個主數據源(默認數據源),多數據源配置時必不可少。@Qualifier
:顯式選擇傳入的 Bean。第二個數據源和主數據源惟一不一樣的只是 MapperScan
掃描路徑和建立的 Bean 名稱,同時沒有 @Primary
主數據源的註解。
/** * 第二個數據源配置 * * @author niujinpeng * @website: https://www.wdbyte.com * @date 2020/12/19 */ @Configuration @MapperScan(basePackages = {"com.wdbyte.mapper.datasource2"}, sqlSessionFactoryRef = "sqlSessionFactory2") public class SecondDataSourceConfig { @Bean(name = "dataSource2") @ConfigurationProperties(prefix = "spring.datasource.datasource2") public DataSource dataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "sqlSessionFactory2") public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource2") DataSource dataSource) throws Exception { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSource); bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml")); return bean.getObject(); } @Bean(name = "transactionManager2") public DataSourceTransactionManager transactionManager(@Qualifier("dataSource2") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } @Bean(name = "sqlSessionTemplate2") public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) { return new SqlSessionTemplate(sqlSessionFactory); } }
注意:由於已經在兩個數據源中分別配置了掃描的 Mapper 路徑,若是你以前在 SpringBoot 啓動類中也使用了 Mapper 掃描註解,須要刪掉。
編寫兩個簡單的查詢 Controller 而後進行訪問測試。
// BookController @RestController public class BookController { @Autowired private BookService bookService; @GetMapping(value = "/books") public Response selectAll() throws Exception { List<Book> books = bookService.selectAll(); return ResponseUtill.success(books); } } // UserController @RestController public class UserController { @Autowired private UserService userService; @ResponseBody @GetMapping(value = "/users") public Response selectAll() { List<User> userList = userService.selectAll(); return ResponseUtill.success(userList); } }
訪問測試,我這裏直接 CURL 請求。
➜ ~ curl localhost:8080/books { "code": "0000", "message": "success", "data": [ { "id": 1, "author": "金庸", "name": "笑傲江湖", "price": 13, "createtime": "2020-12-19T07:26:51.000+00:00", "description": "武俠小說" }, { "id": 2, "author": "羅貫中", "name": "三國演義", "price": 14, "createtime": "2020-12-19T07:28:36.000+00:00", "description": "歷史小說" } ] } ➜ ~ curl localhost:8080/users { "code": "0000", "message": "success", "data": [ { "id": 1, "name": "金庸", "birthday": "1924-03-09T16:00:00.000+00:00" }, { "id": 2, "name": "羅貫中", "birthday": "1330-01-09T16:00:00.000+00:00" } ] } ➜ ~
至此,多數據源配置完成,測試成功。
其實在多數據源改造中,咱們通常狀況下都不會使用默認的 JDBC 鏈接方式,每每都須要引入鏈接池進行鏈接優化,否則你可能會常常遇到數據源鏈接被斷開等報錯日誌。其實數據源切換鏈接池數據源也是十分簡單的,直接引入鏈接池依賴,而後把建立 dataSource 的部分換成鏈接池數據源建立便可。
下面以阿里的 Druid 爲例,先引入鏈接池數據源依賴。
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency>
添加 Druid 的一些配置。
spring.datasource.datasource2.initialSize=3 # 根據本身狀況設置 spring.datasource.datasource2.minIdle=3 spring.datasource.datasource2.maxActive=20
改寫 dataSource Bean 的建立代碼部分。
@Value("${spring.datasource.datasource2.jdbc-url}") private String url; @Value("${spring.datasource.datasource2.driver-class-name}") private String driverClassName; @Value("${spring.datasource.datasource2.username}") private String username; @Value("${spring.datasource.datasource2.password}") private String password; @Value("${spring.datasource.datasource2.initialSize}") private int initialSize; @Value("${spring.datasource.datasource2.minIdle}") private int minIdle; @Value("${spring.datasource.datasource2.maxActive}") private int maxActive; @Bean(name = "dataSource2") public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setUrl(url); dataSource.setDriverClassName(driverClassName); dataSource.setUsername(username); dataSource.setPassword(password); dataSource.setInitialSize(initialSize); dataSource.setMinIdle(minIdle); dataSource.setMaxActive(maxActive); return dataSource; }
這裏只是簡單的提一下使用鏈接池的重要性,Druid 的詳細用法還請參考官方文檔。
文中代碼已經上傳到 Github: https://github.com/niumoo/springboot
最後的話
文章有幫助能夠點個「贊」或「分享」,都是支持!
文章每週持續更新,能夠關注「 未讀代碼 」公衆號或者個人博客。