目录
6.4 SpringBoot中配置多个数据源
- 就是操作多个数据库所要进行的配置
第一步:准备2个数据库
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 80013
Source Host : localhost:3306
Source Database : test
Target Server Type : MYSQL
Target Server Version : 80013
File Encoding : 65001
Date: 2020-10-26 21:14:40
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`username` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL,
`password` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'zhangsan', '1234');
INSERT INTO `user` VALUES ('2', 'lisi', '1234');
INSERT INTO `user` VALUES ('4', 'shu', '123');
INSERT INTO `user` VALUES ('5', 'shu1', '123');
/*
Navicat MySQL Data Transfer
Source Server : localhost
Source Server Version : 80013
Source Host : localhost:3306
Source Database : test1
Target Server Type : MYSQL
Target Server Version : 80013
File Encoding : 65001
Date: 2020-10-26 21:14:50
*/
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
`sex` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', 'shu', '男');
第二步:pom中添加依赖
<repositories>
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<parent>
<!--SpringBoot的父依赖-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
<dependencies>
<!--SpringBoot配置web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入freeMarker的依赖包-->
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>-->
<!--JDBC-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
第三步:application.properties配置文件中添加两个数据源
spring.datasource.test.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
spring.datasource.test.username=root
spring.datasource.test.password=root
spring.datasource.test.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.test1.url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC
spring.datasource.test1.username=root
spring.datasource.test1.password=root
spring.datasource.test1.driverClassName=com.mysql.cj.jdbc.Driver
可能有用:
springboot1.x 版本用url、driverClassName
springboot2.x 版本用jdbc-url、driver-class-name
第四步:写2个数据源配置
- 数据源1
package com.it.datasource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
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.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
/**
* @ClassName DataSource1
* @Author shuyy
* @Date 2020/10/26
**/
@Configuration//注解到springboot容器中
@MapperScan(basePackages="com.it.test.mapper",sqlSessionFactoryRef="testSqlSessionFactory")
public class DataSource1 {
/**
* @return 返回test数据库的数据源
*/
@Bean(name="testDataSource")
@Primary//主数据源,一个应用只能配置一个(一山不容二虎),且必须配置,这里不配置报错!
@ConfigurationProperties(prefix="spring.datasource.test")
public DataSource dateSource(){
return DataSourceBuilder.create()//如果失败了可以使用下面这种方法
/*.driverClassName("com.mysql.cj.jdbc.Driver")
.url("jdbc:mysql://localhost:3306/test?serverTimezone=UTC")
.username("root")
.password("root")*/
.build();
}
/**
* @return 返回test数据库的会话工厂
*/
@Bean(name = "testSqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("testDataSource") DataSource ds) throws Exception{
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(ds);
//这里使用的是注解+接口sql无需配置,如果是xml中写sql,记得配置
//bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:test/mapper/*.xml"));
return bean.getObject();
}
/**
* @return 返回test数据库的事务
*/
@Bean(name = "testTransactionManager")
@Primary
public DataSourceTransactionManager transactionManager(@Qualifier("testDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* @return 返回test数据库的会话模版
*/
@Bean(name = "testSqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate(
@Qualifier("testSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
- 数据源2
package com.it.datasource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration//注解到springboot容器中
@MapperScan(basePackages="com.it.test1.mapper",sqlSessionFactoryRef="test1SqlSessionFactory")
public class DataSource2 {
/**
* @return 返回test1数据库的数据源
*/
@Bean(name="test1DataSource")
@ConfigurationProperties(prefix="spring.datasource.test1")
public DataSource dateSource(){
return DataSourceBuilder.create()
/*.driverClassName("com.mysql.cj.jdbc.Driver")
.url("jdbc:mysql://localhost:3306/test1?serverTimezone=UTC")
.username("root")
.password("root")*/
.build();
}
/**
* @return 返回test1数据库的会话工厂
*/
@Bean(name = "test1SqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("test1DataSource") DataSource ds) throws Exception{
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(ds);
//bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:test1/mapper/*.xml"));
return bean.getObject();
}
/**
* @return 返回test1数据库的事务
*/
@Bean(name = "test1TransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("test1DataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**
* @return 返回test1数据库的会话模版
*/
@Bean(name = "test1SqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(
@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
第五步:实体类编写
- User,【对应数据库字段】为属性提供无参、有参构造、get/set、toString
- Student,为属性提供无参、有参构造、get/set、toString
第六步:test的Mapper&service
- UserMapper
package com.it.test.mapper;
import com.it.test.model.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
public interface UserMapper {
@Insert("insert into user(username,password) values(#{username},#{password})")
void save(@Param("username") String username, @Param("password") String password);
@Select("select * from user where id = #{id}")
User findUserById(@Param("id") Integer id);
/*void save(String username,String password);
User findUserById(Integer id);*/
}
-
UserService
-
UserServiceImpl
package com.it.test.service.impl;
import com.it.test.mapper.UserMapper;
import com.it.test.model.User;
import com.it.test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @ClassName UserServiceImpl
* @Author shuyy
* @Date 2020/10/26
**/
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;//这里如果报错,正常不影响运行,是springBean扫描所致,它是在运行时自动创建
/*private JdbcTemplate jdbcTemplate;*///本来这里需要配置数据源,现在在SpringBoot中配置好了无需配置
@Override
public void register(String username, String password) {
/*String sql = "insert into user(username,password) values(?,?)";*/
/*jdbcTemplate.update(sql,username,password);*/
userMapper.save(username,password);
}
@Override
public User findUserById(Integer id) {
return userMapper.findUserById(id);
}
}
第七步:test1的Mapper&service
- StudentMapper
package com.it.test1.mapper;
import com.it.test1.model.Student;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/**
* @author ShuYY
* @date 2020/10/26
*/
public interface StudentMapper {
@Insert("insert into student(username,sex) values(#{username},#{sex})")
void save(@Param("username") String username, @Param("sex") String sex);
@Select("select * from student where id = #{id}")
Student findStuById(@Param("id") Integer id);
/*void save(String username,String sex);
Student findStuById(Integer id);*/
}
- StudentService
- StudentServiceImpl
package com.it.test1.service.impl;/**
* @author ShuYangyang
* @date 2020/10/26 21:46
*/
import com.it.test1.mapper.StudentMapper;
import com.it.test1.model.Student;
import com.it.test1.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @ClassName StudentServiceImpl
* @Author shuyy
* @Date 2020/10/26
**/
@Service
@Transactional
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Override
public void save(String username, String sex) {
studentMapper.save(username,sex);
}
@Override
public Student findStuById(Integer id) {
return studentMapper.findStuById(id);
}
}
第八步:写个Controller
- UserController
package com.it.web.controller;
import com.it.test.model.User;
import com.it.test.service.UserService;
import com.it.test1.model.Student;
import com.it.test1.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @ClassName HelloController
* @Author shuyy
* @Date 2020/10/25
**/
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@Autowired
private StudentService studentService;
@RequestMapping("register")
@ResponseBody
public String register(String username,String password){
userService.register(username,password);
studentService.save(username,"男");
return "success";
}
@RequestMapping("findUser")
@ResponseBody
public User findUser(Integer id){
return userService.findUserById(id);
}
@RequestMapping("findStu")
@ResponseBody
public Student findStu(Integer id){
return studentService.findStuById(id);
}
}
第九步:App中
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
/**
* @ClassName App
* @Author shuyy
* @Date 2020/10/25
**/
@EnableAutoConfiguration/*(exclude={DataSourceAutoConfiguration.class})*///写一个,这里配置了,其它Controller无需写了
@ComponentScan(basePackages = {
"com.it.datasource","com.it.web.controller","com.it.test","com.it.test1"})//配置扫描包
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class,args);
}
}
效果
6.5 多数据源存在的问题
- 修改UserController
- 修改对应的方法
- 注意这里调换一下方法的顺序!
- 显然上面这样是不符合事务的要求的,要么全部成功要么全部失败,我们要把它当成一个事务看待处理,就要使用到springboot+jta+atomikos 分布式事务管理来解决这样的现象。(详见下一天)