springboot默认大于配置的特性使得配置数据单常方便,但是配置一个多数据源稍微有点复杂。
源码地址:https://github.com/jinjunzhu/spring-boot-mybatis.git
1.集成mybatis配置一个单数据源,只需要以下几步
1)配置数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/zhujinjun?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=test
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
2)配置mybatis配置文件
3)编写Mapper文件
2.集成mybatis配置多数据源,需要的配置比较多
1)配置数据源
######primary#############
datasource.first.jdbc-url=jdbc:mysql://localhost:3306/jinjunzhu?serverTimezone=UTC&characterEncoding=utf-8
datasource.first.username=root
datasource.first.password=123456
datasource.first.driver-class-name=com.mysql.cj.jdbc.Driver
######secondary#############
datasource.secondary.jdbc-url=jdbc:mysql://localhost:3306/jinjunzhu1?serverTimezone=UTC&characterEncoding=utf-8
datasource.secondary.username=root
datasource.secondary.password=123456
datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
2)配置mybatis文件
针对第一个数据源
@Component("mybatisConfig")
@MapperScan(basePackages={"boot.repository.dao1"}, sqlSessionFactoryRef = "firstSqlSessionFactory")
public class MybatisConfig {
@Bean(name="firstDataSource")
@ConfigurationProperties(prefix="datasource.first")
@Primary
public DataSource firstDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "firstSqlSessionFactory")
public SqlSessionFactory firstSqlSessionFactory(@Qualifier("firstDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mapper/mybatis-config.xml"));
return bean.getObject();
}
@Bean(name = "firstTransactionManager")
@Primary
public DataSourceTransactionManager firstTransactionManager(@Qualifier("firstDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "firstSqlSessionTemplate")
public SqlSessionTemplate firstSqlSessionTemplate(
@Qualifier("firstSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
//@Resource
//@Qualifier("firstSqlSessionTemplate")
//protected SqlSession firstSqlSession;
}
针对第二个数据源
@Component("mybatisConfig1")
@MapperScan(basePackages={"boot.repository.dao2"}, sqlSessionFactoryRef = "secondSqlSessionFactory")
public class MybatisConfig1 {
@Bean(name="secondDataSource")
@ConfigurationProperties(prefix="datasource.secondary")
public DataSource secondDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondSqlSessionFactory")
public SqlSessionFactory secondSqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource("classpath:mybatis/mapper1/mybatis-config.xml"));
return bean.getObject();
}
@Bean(name = "secondTransactionManager")
public DataSourceTransactionManager secondTransactionManager(@Qualifier("secondDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "secondSqlSessionTemplate")
public SqlSessionTemplate secondSqlSessionTemplate(
@Qualifier("secondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
3)编写Mapper文件和dao类
从2)中图片看出,Mapper文件和dao类存放目录不同,目录结构如下:
3.单元测试
1)数据源1测试代码:
@Test
public void testInsertEmployee(){
Employee employee = employeeService.getEmployee("lisi");
Assert.assertNull(employee);
Employee employee1 = new Employee();
employee1.setName("lisi");
employee1.setDepartment("4");
employee1.setNumber(2002950l);
employeeService.insertEmployee(employee1);
employee = employeeService.getEmployee("lisi");
Assert.assertNotNull(employee);
}
启动测试类输出如下日志:
2)数据源2测试代码
@Transactional(value="secondTransactionManager", rollbackFor=Exception.class)
public void testInsert() throws Exception{
Assert.assertNull(departmentService.getDepartment("jinjunzhu"));
Department department = new Department();
department.setLevel(2);
department.setName("jinjunzhu");
department.setId(2l);
departmentService.insertDepartment(department);
Department department1 = departmentService.getDepartment("jinjunzhu");
Assert.assertNotNull(department1);
}
执行测试方法,日志如下:
从上面2个测试方法看出,第二个数据源的测试需要在测试方法上加事务注解才能支持跑完后回滚。因为在数据源1的mybatis配置类中加了@primary。具体细节怎么实现的,还没有研究。
4.代码中有3个controller类支持http请求进行测试,如下:
@Controller
@RequestMapping("/user")
public class UserController {
@Resource
private UserService userService;
@RequestMapping("/{username}")
@ResponseBody
public String getPassword(@PathVariable String username) {
String passwd = userService.getUser(username).getPassword();
return passwd;
}
@RequestMapping("/saveUser/{username}")
@ResponseBody
public String saveUser(@PathVariable String username) {
User user = new User();
user.setUsername(username);
user.setPassword("111111");
try {
userService.insert(user);
return "success!";
} catch (Exception e) {
return "failure!";
}
}
}
@Controller
public class EmployeeController {
@Resource
private EmployeeService employeeService;
@RequestMapping("/employee/{name}")
@ResponseBody
public String getEmployeebyName(@PathVariable String name){
Employee employee = employeeService.getEmployee(name);
return null == employee?null:employee.getDepartment();
}
@RequestMapping("/employee/save/{name}/{department}/{number}")
@ResponseBody
public String saveEmployeebyName(@PathVariable String name,@PathVariable String department,@PathVariable Long number){
Employee employee = new Employee();
employee.setName(name);
employee.setDepartment(department);
employee.setNumber(number);
try{
employeeService.insertEmployee(employee);
return "success!";
}catch(Exception e){
return e.toString();
}
}
}
@Controller
public class DepartmentController {
Logger logger = LoggerFactory.getLogger(getClass());
@Resource
private DepartmentService departmentService;
@RequestMapping("/department/{name}")
@ResponseBody
public String getDepartment(@PathVariable String name){
Department department = departmentService.getDepartment(name);
return null == department?null:department.getName();
}
@RequestMapping("/department/save/{name}/{level}")
@ResponseBody
public void insertDepartment(@PathVariable String name,@PathVariable Integer level){
Department department = new Department();
department.setName(name);
department.setLevel(level);
try {
departmentService.insertDepartment(department);
} catch (Exception e) {
logger.error("保存部门失败:", e);
}
}
}
启动工程后,浏览器输入
http://localhost:8080/employee/jinjunzhu,返回department
http://localhost:8080/employee/save/lisi/department3/3,保存成功
http://localhost:8080/department/department1,返回department1
http://localhost:8080/department/save/department3/3,保存成功
5.这个项目采用的版本:
springboot:2.1.6.RELEASE
org.mybatis:2.0.1
mysql-connector:8.0.16
6.配置中几个注解:
1)@DependOn:等这个注解中的bean初始化完成后再初始化当前bean
2)@MapperScan:注解中的包下面的类作为mybatis的mapper受spring统一bean管理
3)@Primary:默认优先选择的实现
4)@Mapper:指定接口类是mybatis的mapper