Spring boot实现多数据源的一种方式
参考博客,感谢作者!
之所以说是一种方式,因为还有一种方式是通过继承AbstractRoutingDataSource来动态选择DataSource路由,通过AOP的方式进行切换。
该程序Dao层实现使用mybatis框架。
该方式实现的思路是:有多少个数据源就写多少个数据源的配置类,mybatis的Mapper接口分别对应放在不同的包下,Mapper.xml文件根据数据源的不同放在不同的目录下。不同的数据源扫描不同的Mapper接口和Mapper.xml文件。
项目结构:
application.properties配置文件:
spring.datasource.cluster.driverClassName = com.mysql.jdbc.Driver
spring.datasource.cluster.url = jdbc:mysql://localhost:3306/std1?useUnicode=true&characterEncoding=utf-8
spring.datasource.cluster.username = root
spring.datasource.cluster.password = root
spring.datasource.master.driverClassName = com.mysql.jdbc.Driver
spring.datasource.master.url = jdbc:mysql://localhost:3306/std2?useUnicode=true&characterEncoding=utf-8
spring.datasource.master.username = root
spring.datasource.master.password = root
配置了两个数据源,一个是master,一个是cluster。有多少的数据源,就可以配置多少个数据源。
需要注意的是,Spring boot 2.0以后,数据源url和driveClassName的写法发生了变化,具体可以查找资料。
master数据源配置类:
/**
* mybaits Master库配置类
* com.wanlihong.multi_mybatis.mapper.master 为Master数据源对应的Mapper接口类
*/
@Configuration
@MapperScan(basePackages = "com.wanlihong.multi_mybatis.mapper.master",sqlSessionTemplateRef = "masterSqlSessionTemplate")
public class MasterDataSourceConfig {
/**
* 创建数据源
*@return DataSource
*/
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
@Primary
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
/**
* 创建工厂
*@param dataSource
*@throws Exception
*@return SqlSessionFactory
*/
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//master 数据源对应的mapper.xml
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/master/*.xml"));
return bean.getObject();
}
/**
* 创建事务
*@param dataSource
*@return DataSourceTransactionManager
*/
@Bean(name = "masterTransactionManager")
@Primary
public DataSourceTransactionManager masterDataSourceTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* 创建模板
*@param sqlSessionFactory
*@return SqlSessionTemplate
*/
@Bean(name = "masterSqlSessionTemplate")
@Primary
public SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
cluster数据源配置文件
/**
* mybatis cluster数据源配置类
* com.wanlihong.multi_mybatis.mapper.cluster 是cluster数据源扫描的Mapper接口类
*/
@Configuration
@MapperScan(basePackages = "com.wanlihong.multi_mybatis.mapper.cluster",sqlSessionTemplateRef = "clusterSqlSessionTemplate")
public class ClusterDataSourceConfig {
/**
* 创建数据源
*@return DataSource
*/
@Bean(name = "clusterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.cluster")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
/**
* 创建工厂
*@param dataSource
*@throws Exception
*@return SqlSessionFactory
*/
@Bean(name = "clusterSqlSessionFactory")
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("clusterDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
//cluster 数据源对应的mapper.xml文件
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/cluster/*.xml"));
return bean.getObject();
}
/**
* 创建事务
*@param dataSource
*@return DataSourceTransactionManager
*/
@Bean(name = "clusterTransactionManager")
public DataSourceTransactionManager masterDataSourceTransactionManager(@Qualifier("clusterDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* 创建模板
*@param sqlSessionFactory
*@return SqlSessionTemplate
*/
@Bean(name = "clusterSqlSessionTemplate")
public SqlSessionTemplate masterSqlSessionTemplate(@Qualifier("clusterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
两个Mapper接口类:
package com.wanlihong.multi_mybatis.mapper.cluster;
import com.wanlihong.multi_mybatis.model.Stu;
import java.util.List;
import java.util.Map;
public interface ClusterStuMapper {
void clusterrInsert(Stu stu);
List<Stu> clusterrList(Map<String,Object> map);
}
package com.wanlihong.multi_mybatis.mapper.master;
import com.wanlihong.multi_mybatis.model.Stu;
import java.util.List;
import java.util.Map;
public interface MasterStuMapper {
void masterInsert(Stu stu);
List<Stu> masterList(Map<String,Object> map);
}
注意,这两个接口在不同的包下面。
两个mapper.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.wanlihong.multi_mybatis.mapper.cluster.ClusterStuMapper">
<resultMap id="clusterrStuMap" type="com.wanlihong.multi_mybatis.model.Stu">
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="age" property="age" jdbcType="INTEGER" />
<result column="sex" property="sex" jdbcType="VARCHAR" />
</resultMap>
<insert id="clusterrInsert" parameterType="com.wanlihong.multi_mybatis.model.Stu">
insert into student (
<trim prefixOverrides=",">
<if test="name != null">,name</if>
<if test="age != null">,age</if>
<if test="sex != null">,sex</if>
</trim>
) values (
<trim prefixOverrides=",">
<if test="name != null">,#{name}</if>
<if test="age != null">,#{age}</if>
<if test="sex != null">,#{sex}</if>
</trim>
)
</insert>
<select id="clusterrList" parameterType="java.util.Map" resultMap="clusterrStuMap">
select
name,age,sex
from student
<where>
<if test="name != null">and name = #{name}</if>
<if test="age != null">and age = #{age}</if>
<if test="sex != null">and sex = #{sex}</if>
</where>
</select>
</mapper>
<?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.wanlihong.multi_mybatis.mapper.master.MasterStuMapper">
<resultMap id="masterStuMap" type="com.wanlihong.multi_mybatis.model.Stu">
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="age" property="age" jdbcType="INTEGER" />
<result column="sex" property="sex" jdbcType="VARCHAR" />
</resultMap>
<insert id="masterInsert" parameterType="com.wanlihong.multi_mybatis.model.Stu">
insert into student (
<trim prefixOverrides=",">
<if test="name != null">,name</if>
<if test="age != null">,age</if>
<if test="sex != null">,sex</if>
</trim>
) values (
<trim prefixOverrides=",">
<if test="name != null">,#{name}</if>
<if test="age != null">,#{age}</if>
<if test="sex != null">,#{sex}</if>
</trim>
)
</insert>
<select id="masterList" parameterType="java.util.Map" resultMap="masterStuMap">
select
name,age,sex
from student
<where>
<if test="name != null">and name = #{name}</if>
<if test="age != null">and age = #{age}</if>
<if test="sex != null">and sex = #{sex}</if>
</where>
</select>
</mapper>
注意,这两个mapper.xml文件也在不同的目录下面,和不同数据源的配置类要对应起来。
两个数据库的表结构和表名称都是相同的,实际开发中可能不同。
CREATE TABLE `student` (
`name` varchar(100) character set latin1 default NULL,
`age` int(11) default NULL,
`sex` varchar(255) character set latin1 default NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Service:
public interface MyService {
public void clusterrInsert(Stu stu);
public List<Stu> clusterList(Map<String,Object> map);
public void masterInsert(Stu stu);
public List<Stu> masterList(Map<String,Object> map);
}
@Service
public class MyServiceImpl implements MyService {
@Resource
private MasterStuMapper masterStuMapper;
@Resource
private ClusterStuMapper clusterStuMapper;
@Override
public void clusterrInsert(Stu stu) {
clusterStuMapper.clusterrInsert(stu);
}
@Override
public List<Stu> clusterList(Map<String, Object> map) {
return clusterStuMapper.clusterrList(map);
}
@Override
public void masterInsert(Stu stu) {
masterStuMapper.masterInsert(stu);
}
@Override
public List<Stu> masterList(Map<String, Object> map) {
return masterStuMapper.masterList(map);
}
}
Controller:
@RestController
public class FirstController {
@Resource
private MyService myService;
@RequestMapping("/save/master")
public String testMaster(Stu stu){
myService.masterInsert(stu);
return "success_master";
}
@RequestMapping("/save/cluster")
public String testCluster(Stu stu){
myService.clusterrInsert(stu);
return "success_cluster";
}
@RequestMapping("/masterList")
public List<Stu> getMasterList(){
return myService.masterList(null);
}
@RequestMapping("/clusterList")
public List<Stu> getClusterList(){
return myService.clusterList(null);
}
}
启动类:
@SpringBootApplication
@MapperScan("com.wanlihong.multi_mybatis.mapper")
public class MultiMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(MultiMybatisApplication.class, args);
}
}
使用Postman进行测试:
这只是Springboot 配置多数据源的方式之一,优点是简单易懂,缺点是缺少灵活性。