文章目录
1 背景介绍
在真实开发中,一个项目连接多个数据源是常有的事,比如我想查询一个用户的基本简历信息和该用户的工资数据,但是用户表在mybatis-study数据库里,而工资表却在nrsc-mybatis数据库里。假若不考虑使用一个服务调用另一个服务的解决方式,那就需要进行多数据源的操作了。
本文测试数据库和测试表如下:
(1)mybatis-study数据库里有t_user表 ,表中数据如下:
(2)nrsc-mybatis数据库里有t_salary表 ,表中数据如下:
2 整体代码结构
整体代码结构如下:
(1)红色框内为mybatis-study数据库对应的配置
(2)黄色框内为nrsc-mybatis数据库对应的配置
下面对上面的内容进行一一进行讲解。
3 多数据源配置关键代码
springboot和mybatis的整合和spring和mybatis的整合基本一致,主要区别点有两个:
- springboot下的数据源配置一般都会配置在yml文件里
- springboot下开启AOP或开启事务的注解一般都会标注在启动类上
其他基本一致。感觉应该比较简单,有不懂或有兴趣的可以clone下来代码看一下,一看肯定就都懂了。不过多解释了,直接上代码。
3.1 yml文件 — 主要是数据源的配置
server:
port: 9092
# 打印sql语句
logging:
level:
com.nrsc.study.mapper : debug
# 数据库1对应的数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/mybatis-study?characterEncoding=utf-8&serverTimezone=GMT&useSSL=false
# 配置内容详解可以看Druid对应的github,这里不过多解释
# https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE%E5%B1%9E%E6%80%A7%E5%88%97%E8%A1%A8
filters: stat
maxActive: 30
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
removeAbandoned: true
removeAbandonedTimeout: 180
# 数据库2对应的数据源
nrsc:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/nrsc-mybatis?characterEncoding=utf-8&serverTimezone=GMT&useSSL=false
# 配置内容详解可以看Druid对应的github,这里不过多解释
# https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE%E5%B1%9E%E6%80%A7%E5%88%97%E8%A1%A8
filters: stat
maxActive: 30
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
removeAbandoned: true
removeAbandonedTimeout: 180
3.2 多数据源配置文件
3.2.1 mybatis-study数据库对应的配置文件
package com.nrsc.study.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/***
* mybatis-study数据库对应的配置
*
* 指定Mapper接口的地址,并指定使用的SqlSessionFactory,可以联系上篇文章思考一下这里的sqlSessionFactoryRef的作用
*/
@MapperScan(basePackages = "com.nrsc.study.mapper.study", sqlSessionFactoryRef = "mybatisStudySqlSessionFactory")
//指定Mapper接口的地址
@Configuration
public class MybatisStudyConfig {
//创建数据源
@Bean("mybatisStudyDataSource")
//以spring.datasource开头的属性都会set到new DruidDataSource()中
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
//注册事务管理器
@Bean("mybatisStudyPlatformTransactionManager")
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(dataSource());
}
//配置SqlSession工厂
@Bean("mybatisStudySqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
//指定数据源
factoryBean.setDataSource(dataSource());
//指定所有mapper.xml所在路径
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath*:mapper/mybatis-study/*.xml"));
return factoryBean.getObject();
}
}
3.2.2 nrsc-mybatis数据库对应的配置文件
package com.nrsc.study.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
/***
* nrsc-mybatis数据库对应的配置
*
* 指定Mapper接口的地址,并指定使用的SqlSessionFactory,可以联系上篇文章思考一下这里的sqlSessionFactoryRef的作用
*/
@MapperScan(basePackages = "com.nrsc.study.mapper.nrsc", sqlSessionFactoryRef = "nrscMybatisSqlSessionFactory")
@Configuration
public class NrscMybatisConfig {
//创建数据源
@Bean("nrscMybatisDataSource")
//以nrsc.datasource开头的属性都会set到new DruidDataSource()中
@ConfigurationProperties(prefix = "nrsc.datasource")
public DataSource dataSource() {
return new DruidDataSource();
}
//注册事务管理器
@Bean("nrscMybatisPlatformTransactionManager")
public PlatformTransactionManager platformTransactionManager() {
return new DataSourceTransactionManager(dataSource());
}
//配置SqlSession工厂
@Bean("nrscMybatisSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory() throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
//指定数据源
factoryBean.setDataSource(dataSource());
//指定所有mapper.xml所在路径
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factoryBean.setMapperLocations(resolver.getResources("classpath*:mapper/nrsc-mybatis/*.xml"));
return factoryBean.getObject();
}
}
有兴趣的可以从源码的角度,想一下在@MapperScan注解中加入sqlSessionFactoryRef属性的原因 —
可参考我之前的一篇文章:《【Mybatis+spring整合源码探秘】— 创建Mapper动态代理类核心源码解读》。
当然还应该想一下,为什么mybatis-spring整合源码中在修改Mapper接口的BeanDefinition对象时,为什么将其属性注入方式改完了按照类型注入 ,而不是按照名称注入☺☺☺。
3.3 启动类 — 开启事务往往写在启动类上
package com.nrsc.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication
@EnableTransactionManagement //开启事务功能
//@EnableAspectJAutoProxy //开启AOP功能
public class MybatisSpringbootApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisSpringbootApplication.class, args);
}
}
4 简单测试
4.1 测试关键代码
这里简单贴一下关键的代码。
4.1.1 controller层代码
@RestController
@RequestMapping("/user")
public class TUserController {
@Autowired
private TUserService userService;
@GetMapping(value = "/getUser/{id}", name = "根据id查询用户")
public UserAndSalaryVO selectByPrimaryKey(@PathVariable("id") Integer id) {
return userService.selectByPrimaryKey(id);
}
}
4.1.2 service层代码
@Service
public class TUserServiceImpl implements TUserService {
@Autowired
private TUserMapper userMapper;
@Autowired
private TSalaryServiceImpl salaryService;
@Override
public UserAndSalaryVO selectByPrimaryKey(Integer id) {
//从mybatis-study数据库里获取用户信息
TUser user = userMapper.selectByPrimaryKey(id);
//从nrsc-mybatis数据库里获取用户的工资信息
TSalary salary = salaryService.selectByUserName(user.getUserName());
//封装数据并返回
UserAndSalaryVO VO = new UserAndSalaryVO();
BeanUtils.copyProperties(user,VO);
VO.setSalary(salary);
return VO;
}
}
4.2 测试结果
测试结果如下:
可以看到已经获取到了mybatis-study数据库t_user表里的数据和nrsc-mybatis数据库t_salary表里的数据,证明我的多数据源配置已经成功。