SpringBoot+TkMybatis+Druid單數(shù)據(jù)源與多數(shù)據(jù)源配置
環(huán)境與工具
開發(fā)工具:Intellij Idea
包管理工具:maven
JDK版本:1.8.0_201
SpringBoot版本:2.1.0.RELEASE
Druid版本:1.1.12
TkMybatis版本:1.0.5
第一步:使用idea創(chuàng)建springboot項目





第二步:先配置下pom,添加所有用到的依賴
<!--依賴配置-添加下面的依賴-->
<!--日志依賴-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
<version>2.10.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<!--數(shù)據(jù)庫依賴-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<!--tk mybatis-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
<!--分頁-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
第三步:先配置下log4j日志(^_?)☆
在resource文件夾下創(chuàng)建log4j.properties
#日志文件路徑
log.path.base=/data/log/demo
#log4j.rootLogger=等級,[appender名稱],[appender名稱]...
log4j.rootLogger=DALI_ROLLING_FILE,CONSOLE
#控制臺輸出日志:ConsoleAppender
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.Encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%l][%t]: %m%n
#文件按日回滾日志:DailyRollingFileAppender
log4j.appender.DALI_ROLLING_FILE=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DALI_ROLLING_FILE.Threshold=DEBUG
log4j.appender.DALI_ROLLING_FILE.ImmediateFlush=true
log4j.appender.DALI_ROLLING_FILE.Append=true
log4j.appender.DALI_ROLLING_FILE.File=${log.path.base}/log.log
log4j.appender.DALI_ROLLING_FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.DALI_ROLLING_FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%l][%t]: %m%n
第四步:TkMybatis+Druid單數(shù)據(jù)源配置
1.修改resource/application.properties,添加數(shù)據(jù)源配置信息
demo.datasource.type=com.alibaba.druid.pool.DruidDataSource
demo.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
demo.datasource.url=jdbc:mysql://localhost:3306/demo
demo.datasource.username=root
demo.datasource.password=root
demo.datasource.maxActive:20
demo.datasource.initialSize:1
demo.datasource.maxWait:60000
demo.datasource.minIdle:1
demo.datasource.timeBetweenEvictionRunsMillis:60000
demo.datasource.minEvictableIdleTimeMillis:300000
demo.datasource.validationQuery:select 'x'
demo.datasource.testWhileIdle:true
demo.datasource.testOnBorrow:false
demo.datasource.testOnReturn:false
#如果是oracle 則可以設(shè)置為true 如果是mysql則設(shè)置false 分庫分表較多的數(shù)據(jù)庫,建議配置為false。
demo.datasource.poolPreparedStatements:false
demo.datasource.maxOpenPreparedStatements:20
2.新建config/datasource包,并創(chuàng)建DemoDataSourceConfig類
package com.superychen.demo.config.datasource;
?
import com.alibaba.druid.pool.DruidDataSource;
?
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
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 lombok.extern.slf4j.Slf4j;
import tk.mybatis.spring.annotation.MapperScan;
?
@Slf4j
@Configuration
//配置mapper掃描的包路徑,注意MapperScan來源 tk.mybatis.spring.annotation.MapperScan
@MapperScan(basePackages = DemoDataSourceConfig.MAPPER_PACKAGE, sqlSessionFactoryRef = DemoDataSourceConfig.SESSION_FACTORY)
public class DemoDataSourceConfig {
?
static final String SESSION_FACTORY = "demoSqlSessionFactory";
private static final String DATASOURCE_NAME = "demoDataSource";
?
//mapper類的包路徑
static final String MAPPER_PACKAGE = "com.superychen.demo.mybatis.mapper.demo";
//自定義mapper的xml文件路徑
private static final String MAPPER_XML_PATH = "classpath:/mapper_diy/DemoMapper.xml";
//數(shù)據(jù)源配置的前綴,必須與application.properties中配置的對應(yīng)數(shù)據(jù)源的前綴一致
private static final String DATASOURCE_PREFIX = "demo.datasource";
?
@Primary
@Bean(name = DATASOURCE_NAME)
@ConfigurationProperties(prefix = DATASOURCE_PREFIX)
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
?
@Primary
@Bean(name = SESSION_FACTORY)
public SqlSessionFactory sqlSessionFactory() {
final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(druidDataSource());
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//自定義mapper的xml文件地址,當(dāng)通用mapper提供的默認(rèn)功能無法滿足我們的需求時,可以自己添加實現(xiàn),與mybatis寫mapper一樣
sessionFactoryBean.setMapperLocations(resolver.getResources(MAPPER_XML_PATH));
return sessionFactoryBean.getObject();
} catch (Exception e) {
log.error("配置demo的SqlSessionFactory失敗,error:{}", e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
}
3.在resource文件夾下創(chuàng)建mapper_diy文件夾,用于存放自定義*Mapper.xml文件,創(chuàng)建DemoMapper.xml文件,同時在mybatis.mapper.demo包下創(chuàng)建DemoMapper類
DemoMapper.xml路徑與
DemoDataSourceConfig中MAPPER_XML_PATH的值要一致
<?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對應(yīng)一個數(shù)據(jù)源-->
<mapper namespace="com.superychen.demo.mybatis.mapper.demo.DemoMapper">
<!--自定義方法在這里添加,與普通mybatis書寫方式完全一樣-->
</mapper>
DemoMapper.java所在包與
DemoDataSourceConfig中MAPPER_PACKAGE的值要一致所在位置與
DemoMapper.xml中mapper的namespace值一致
package com.superychen.demo.mybatis.mapper.demo;
?
import org.springframework.stereotype.Component;
?
@Component
public interface DemoMapper {
//自定義方法在這里添加,與普通mybatis書寫方式完全一樣
}
到這里,其實已經(jīng)可以使用了,在本地創(chuàng)建
demo數(shù)據(jù)庫,并添加user表如下
-- 創(chuàng)建數(shù)據(jù)庫
CREATE DATABASE IF NOT EXISTS `demo`;
-- 創(chuàng)建user表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
在
src/test/java/com/superychen/demo下創(chuàng)建如下測試類
package com.superychen.demo;
import com.superychen.demo.mybatis.mapper.demo.DemoMapper;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Test1 {
@Autowired
private DemoMapper demoMapper;
@Test
public void contextLoads() {
demoMapper.insert();
assert "superychen".equals(demoMapper.select());
}
}
執(zhí)行測試,測試通過

查看數(shù)據(jù)庫

4. 實際使用
使用
TkMybatis的最主要目的是簡化我們書寫mapper的流程,我們只需要定義數(shù)據(jù)庫表對應(yīng)的實體類,并定義一個*Mapper接口繼承其提供的Mapper<T>接口,將實體類作為泛型類型,即可使用通用的Mapper操作數(shù)據(jù)庫表方法,如增刪改查等
以前一步創(chuàng)建的user表為例,在
com.superychen.demo.mybatis.entity.demo包下創(chuàng)建User類
package com.superychen.demo.mybatis.entity.demo;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Table(name = "user")
public class User {
@Id
private Integer id;
private String name;
private Integer age;
}
在
com.superychen.demo.mybatis.mapper.demo包下創(chuàng)建UserMapper接口
package com.superychen.demo.mybatis.mapper.demo;
import com.superychen.demo.mybatis.entity.demo.User;
import org.springframework.stereotype.Repository;
import tk.mybatis.mapper.common.Mapper;
@Repository
public interface UserMapper extends Mapper<User> {
}
查看
UserMapper的結(jié)構(gòu),發(fā)現(xiàn)有以下方法,具體方法使用請參考官網(wǎng)

在
src/test/java/com/superychen/demo下創(chuàng)建如下測試類
package com.superychen.demo;
import com.superychen.demo.mybatis.entity.demo.User;
import com.superychen.demo.mybatis.mapper.demo.UserMapper;
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 java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void contextLoads() {
//所有
List<User> users = userMapper.selectAll();
assert 1 == users.size();
//插入
User user = new User();
user.setName("test2");
user.setAge(18);
userMapper.insert(user);
//數(shù)量
int count = userMapper.selectCountByExample(null);
assert 2 == count;
//刪除
userMapper.delete(user);
//數(shù)量
count = userMapper.selectCountByExample(null);
assert 1 == count;
}
}
執(zhí)行測試,測試通過

該數(shù)據(jù)庫下所有表都可以按
UserMapper的方式進(jìn)行配置與使用
如果需要在插入后獲取自增的主鍵
id,只需在id字段上添加@GeneratedValue(strategy = GenerationType.IDENTITY)注解,如下
package com.superychen.demo.mybatis.entity.demo;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
@Data
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer age;
}
在
src/test/java/com/superychen/demo下創(chuàng)建如下測試類
package com.superychen.demo;
import com.superychen.demo.mybatis.entity.demo.User;
import com.superychen.demo.mybatis.mapper.demo.UserMapper;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperAutoGenerateIdTest {
@Autowired
private UserMapper userMapper;
@Test
public void contextLoads() {
//插入
User user = new User();
user.setName("test2");
user.setAge(18);
userMapper.insert(user);
assert 2 == user.getId();
}
}
執(zhí)行測試,測試通過

查看數(shù)據(jù)庫

第五步:多數(shù)據(jù)源配置
多數(shù)據(jù)源配置只需仿照第一個數(shù)據(jù)源的方式同樣配置即可,此處以新增
Second數(shù)據(jù)庫的數(shù)據(jù)源為例
1.修改resource/application.propertie,添加數(shù)據(jù)源配置信息
second.datasource.type=com.alibaba.druid.pool.DruidDataSource
second.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
second.datasource.url=jdbc:mysql://localhost:3306/second
second.datasource.username=root
second.datasource.password=root
second.datasource.maxActive:20
second.datasource.initialSize:1
second.datasource.maxWait:60000
second.datasource.minIdle:1
second.datasource.timeBetweenEvictionRunsMillis:60000
second.datasource.minEvictableIdleTimeMillis:300000
second.datasource.validationQuery:select 'x'
second.datasource.testWhileIdle:true
second.datasource.testOnBorrow:false
second.datasource.testOnReturn:false
#如果是oracle 則可以設(shè)置為true 如果是mysql則設(shè)置false 分庫分表較多的數(shù)據(jù)庫,建議配置為false。
second.datasource.poolPreparedStatements:false
second.datasource.maxOpenPreparedStatements:20
2.在config/datasource包下創(chuàng)建SecondDataSourceConfig類
去掉
druidDataSource與sqlSessionFactory上的@Primary注解
package com.superychen.demo.config.datasource;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
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 lombok.extern.slf4j.Slf4j;
import tk.mybatis.spring.annotation.MapperScan;
@Slf4j
@Configuration
@MapperScan(basePackages = SecondDataSourceConfig.MAPPER_PACKAGE, sqlSessionFactoryRef = SecondDataSourceConfig.SESSION_FACTORY)
public class SecondDataSourceConfig {
static final String SESSION_FACTORY = "secondSqlSessionFactory";
private static final String DATASOURCE_NAME = "secondDataSource";
//mapper類的包路徑
static final String MAPPER_PACKAGE = "com.superychen.demo.mybatis.mapper.second";
//自定義mapper的xml文件路徑
private static final String MAPPER_XML_PATH = "classpath:/mapper_diy/SecondMapper.xml";
//數(shù)據(jù)源配置的前綴,必須與application.properties中配置的對應(yīng)數(shù)據(jù)源的前綴一致
private static final String DATASOURCE_PREFIX = "second.datasource";
@Bean(name = DATASOURCE_NAME)
@ConfigurationProperties(prefix = DATASOURCE_PREFIX)
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Bean(name = SESSION_FACTORY)
public SqlSessionFactory sqlSessionFactory() {
final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(druidDataSource());
try {
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//自定義mapper的xml文件地址,當(dāng)通用mapper提供的默認(rèn)功能無法滿足我們的需求時,可以自己添加實現(xiàn),與mybatis寫mapper一樣
sessionFactoryBean.setMapperLocations(resolver.getResources(MAPPER_XML_PATH));
return sessionFactoryBean.getObject();
} catch (Exception e) {
log.error("配置second的SqlSessionFactory失敗,error:{}", e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
}
3.在resource/mapper_diy文件夾下創(chuàng)建SecondMapper.xml文件,同時在mybatis.mapper.second包下創(chuàng)建SecondMapper類
SecondMapper.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對應(yīng)一個數(shù)據(jù)庫-->
<mapper namespace="com.superychen.demo.mybatis.mapper.second.SecondMapper">
</mapper>
SecondMapper類
package com.superychen.demo.mybatis.mapper.second;
import org.springframework.stereotype.Component;
@Component
public interface SecondMapper {
@Insert("INSERT INTO test(name,age) VALUES('superychen',22)")
int insert();
@Select("SELECT name FROM test LIMIT 1")
String select();
}
4.測試
創(chuàng)建
second數(shù)據(jù)庫,并創(chuàng)建test表
-- 創(chuàng)建數(shù)據(jù)庫
CREATE DATABASE IF NOT EXISTS `second`;
-- 創(chuàng)建user表
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(30) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
在
src/test/java/com/superychen/demo下創(chuàng)建如下測試類
package com.superychen.demo;
import com.superychen.demo.mybatis.mapper.demo.DemoMapper;
import com.superychen.demo.mybatis.mapper.second.SecondMapper;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class Test2 {
@Autowired
private SecondMapper secondMapper;
@Test
public void contextLoads() {
secondMapper.insert();
assert "superychen".equals(secondMapper.select());
}
}
執(zhí)行測試,測試通過

查看數(shù)據(jù)庫

第六步:配置分布式事務(wù)支持
1.修改pom.xml文件,引入maven依賴
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
2.在數(shù)據(jù)源配置類中添加如下代碼
//DataSourceTransactionManager的名稱,建議按照數(shù)據(jù)庫的名稱+TransactionManager駝峰命名的方式賦值
//如demo數(shù)據(jù)庫,命名如下
private static final String TRANSACTION_MANAGER_NAME = "demoTransactionManager";
//主數(shù)據(jù)源添加@Primary注解,其它數(shù)據(jù)源不能添加
@Primary
@Bean(name = TRANSACTION_MANAGER_NAME)
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(druidDataSource());
}
3.在config/datasource包下創(chuàng)建DataSourcesAutoConfiguration類
package com.superychen.demo.config.datasource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import javax.annotation.Resource;
/**
* 配置分布式事務(wù)管理
*/
@Configuration
@EnableTransactionManagement
@ConditionalOnBean({
DemoDataSourceConfig.class,
SecondDataSourceConfig.class,
//新增數(shù)據(jù)源在這里添加
//XxxDataSourceConfig.class
})
public class DataSourcesAutoConfiguration implements TransactionManagementConfigurer {
@Resource
private DemoDataSourceConfig demoDataSourceConfig;
@Resource
private SecondDataSourceConfig secondDataSourceConfig;
//新增數(shù)據(jù)源在這里添加
//@Resource
//private XxxDataSourceConfig xxxDataSourceConfig;
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new ChainedTransactionManager(
demoDataSourceConfig.transactionManager(),
secondDataSourceConfig.transactionManager()
//新增數(shù)據(jù)源在這里添加
//xxxDataSourceConfig.xxxTransactionManager()
);
}
}
第七步:集成PageHelper
PageHelper的集成十分簡單,示例代碼
1.在數(shù)據(jù)庫表(demo.user)中插入幾條測試數(shù)據(jù)
INSERT INTO `user`(name,age) VALUES ('test3', '20');
INSERT INTO `user`(name,age) VALUES ('test4', '22');
INSERT INTO `user`(name,age) VALUES ('test5', '31');
INSERT INTO `user`(name,age) VALUES ('test6', '12');
INSERT INTO `user`(name,age) VALUES ('test7', '18');
INSERT INTO `user`(name,age) VALUES ('test8', '21');
INSERT INTO `user`(name,age) VALUES ('test9', '29');
INSERT INTO `user`(name,age) VALUES ('test10', '20');
INSERT INTO `user`(name,age) VALUES ('test11', '18');
數(shù)據(jù)庫表中當(dāng)前數(shù)據(jù)如下

2.在src/test/java/com/superychen/demo下創(chuàng)建如下測試類
package com.superychen.demo;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.superychen.demo.mybatis.entity.demo.User;
import com.superychen.demo.mybatis.mapper.demo.UserMapper;
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;
@RunWith(SpringRunner.class)
@SpringBootTest
public class PageHelperTest {
@Autowired
private UserMapper userMapper;
@Test
public void contextLoads() {
PageHelper.startPage(1, 10);
Page<User> users = (Page<User>) userMapper.selectAll();
assert 11 == users.getTotal();
assert 1 == users.getPageNum();
assert 10 == users.getPageSize();
assert 2 == users.getPages();
assert 10 == users.getResult().size();
PageHelper.startPage(2, 10);
Page<User> users2 = (Page<User>) userMapper.selectAll();
assert 11 == users2.getTotal();
assert 2 == users2.getPageNum();
assert 10 == users2.getPageSize();
assert 2 == users2.getPages();
assert 1 == users2.getResult().size();
}
}
3.執(zhí)行測試,測試通過

總結(jié)
本篇文章所有代碼見Github