Spring Boot 配合 Mybatis 实现多数据源
2020-11-13 本文已影响0人
MrDcheng
1 环境
plugins {
id 'org.springframework.boot' version '2.3.5.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.3'
runtimeOnly 'mysql:mysql-connector-java'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
// https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter
compile group: 'com.alibaba', name: 'druid-spring-boot-starter', version: '1.2.3'
}
test {
useJUnitPlatform()
}
2 Spring Boot 读取 yml
2.1 yml 文件注意事项
- 可在小写字母前增加
-
或_
表示其大写形式,如userName
与user-name
,user_name
含义是一样的 - 字符串默认不用加上单引号或者双引号
- 值使用双引号不会转义字符串里面的特殊字符,例如
name: "zhangsan \n lisi"
,对应的结果会换行 - 值使用单引号会转义特殊字符,特殊字符最终只是一个普通的字符串,例如
name: ‘zhangsan \n lisi’
对应的结果为zhangsan \n lisi
2.2 @Value
注解
读取第一个数据源的 url
@Value("${spring.datasource.first.url}")
private String url;
如果是静态变量,无法使用上述方式注入,需要:
- 所在类添加
@Component
注解 - 定义一个任意名称和任意参数名的方法,如下
private static String url;
@Value("${spring.datasource.first.url}")
public void setUrl(String param){
url=param;
}
2.3 @ConfigurationProperties
注解
需要一个 JavaBean 来专门映射配置,精简案例如下,以此类推:
@Component
@ConfigurationProperties(prefix = "spring.datasource.first")
public class Student {
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
注:prefix 仅描述到配置参数的上一级
2.4 @Environment
注解
@Autowired
private Environment env
public String test() {
System.out.println(env.getProperty("spring.datasource.first.url"));
}
3 案例项目
3.1 主要项目结构
├── src/
│ └── main/
│ ├── java/
│ │ ├── config/
│ │ │ ├── FirstDataSourceConfig.java # 第一个数据源配置
│ │ │ └── SecondDataSourceConfig.java # 第二个数据源配置
│ │ ├── action/
│ │ │ └── Controller.java # 请求处理
│ │ ├── dao/
│ │ │ ├── first/
│ │ │ │ └── FirstDataSourceMapping.java
│ │ │ └── second/
│ │ │ └── SecondDataSourceConfig.java
│ │ ├── service/
│ │ │ └── DataService.java
│ │ └── Application.java # 应用入口
│ └── resources/
│ ├── mapper/
│ │ ├── FirstDataSourceMapping.xml
│ │ └── SecondDataSourceMapping.xml
│ └── application.yml
└── (其他)
application.yml
spring:
profiles:
active: product
datasource:
first:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/onlytest
username: root
password: 123456
second:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/onlytest
username: temp
password: temp
server:
port: 3005
mybatis:
configuration:
call-setters-on-nulls: true
Application.java
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
config/FirstDataSourceConfig.java
@Configuration
@MapperScan(basePackages = {"com.dao.first"}, sqlSessionFactoryRef = "firstSqlSessionFactory")
public class FirstDataSourceConfig {
@Value("${spring.datasource.first.url}")
private String url;
@Value("${spring.datasource.first.username}")
private String user;
@Value("${spring.datasource.first.password}")
private String password;
@Value("${spring.datasource.first.driverClassName}")
private String driverClassName;
@Bean(name = "firstDataSource")
@Primary
public DataSource dataSource() {
DataSourceBuilder dataSourceBuilder=DataSourceBuilder.create();
dataSourceBuilder.driverClassName(driverClassName);
dataSourceBuilder.url(url);
dataSourceBuilder.password(password);
dataSourceBuilder.username(user);
return dataSourceBuilder.build();
}
@Bean(name = "firstTransactionManager")
@Primary
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean(name = "firstSqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("firstDataSource") DataSource masterDataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(masterDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/FirstDataSourceMapping.xml"));
return sessionFactory.getObject();
}
}
config/SecondDataSourceConfig.java
@Configuration
@MapperScan(basePackages = {"com.dao.second"}, sqlSessionFactoryRef = "secondSqlSessionFactory")
public class SecondDataSourceConfig {
@Value("${spring.datasource.second.url}")
private String url;
@Value("${spring.datasource.second.username}")
private String user;
@Value("${spring.datasource.second.password}")
private String password;
@Value("${spring.datasource.second.driverClassName}")
private String driverClassName;
@Bean(name = "secondDataSource")
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driverClassName);
druidDataSource.setUrl(url);
druidDataSource.setUsername(user);
druidDataSource.setPassword(password);
return druidDataSource;
}
@Bean(name = "secondTransactionManager")
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
@Bean(name = "secondSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("secondDataSource") DataSource dataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:mapper/SecondDataSourceMapping.xml"));
return sessionFactory.getObject();
}
}
dao/first/FirstDataSourceMapping.java
@Repository
public interface FirstDataSourceMapping {
List<LinkedHashMap<String, Object>> GetAllRoot();
}
dao/second/SecondDataSourceMapping.java
@Repository
public interface SecondDataSourceMapping {
List<LinkedHashMap<String, Object>> GetAllTemp();
}
service/DataService.java
@Service
public class DataService {
@Autowired
private FirstDataSourceMapping firstDataSourceMapping;
@Autowired
private SecondDataSourceMapping secondDataSourceMapping;
public List<LinkedHashMap<String, Object>> GetAllRoot() {
return firstDataSourceMapping.GetAllRoot();
}
public List<LinkedHashMap<String, Object>> GetAllTemp() {
return secondDataSourceMapping.GetAllTemp();
}
}
resources/mapper/FirstDataSourceMapping.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.dao.first.FirstDataSourceMapping">
<select id="GetAllRoot" resultType="java.util.LinkedHashMap">
<![CDATA[
select * from tableroot
]]>
</select>
</mapper>
resources/mapper/SecondDataSourceMapping.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.dao.second.SecondDataSourceMapping">
<select id="GetAllTemp" resultType="java.util.LinkedHashMap">
<![CDATA[
select * from tabletemp
]]>
</select>
</mapper>
action/Controller.java
@RestController
public class Controller {
@Autowired
private DataService dataService;
@RequestMapping(value = "/searchroot", method = RequestMethod.GET)
public void searchRequstHandler1(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<LinkedHashMap<String, Object>> result;
result = dataService.GetAllRoot();
System.out.println(result);
}
@RequestMapping(value = "/searchtemp", method = RequestMethod.GET)
public void searchRequstHandler2(HttpServletRequest request, HttpServletResponse response) throws Exception {
List<LinkedHashMap<String, Object>> result;
result = dataService.GetAllTemp();
System.out.println(result);
}
}