SpringBoot |
2.4.11 |
Druid |
1.1.17 |
sqljdbc4 |
4.0 |
MyBatis |
2.1.1 |
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.4.11
4.0
1.1.17
2.1.1
com.alibaba
druid-spring-boot-starter
${druid-alibaba.version}
com.microsoft.sqlserver
sqljdbc4
${sqljdbc4.version}
org.mybatis.spring.boot
mybatis-spring-boot-starter
${mybatis.version}
目前有2个数据源,分别是master和slave。
spring:
profiles:
active: dev
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
datasource:
name: druid_ds
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 1
min-idle: 1
max-active: 10
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: false
max-pool-prepared-statement-per-connection-size: 20
filters: stat,slf4j # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filter:
wall:
config:
multi-statement-allow: true
none-base-statement-allow: true
druid的相同配置可以在application.yml中配置,通过active的值激活不同的配置文件,达到“开发环境”,“测试环境”,“生产环境”的差异性。
本文以dev(开发环境)作为配置值。
server:
port: 8305
servlet:
context-path: /
spring:
datasource:
druid:
master:
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc:sqlserver://localhost:1433;DatabaseName=test_01
username: sa
password: 12345678
slave:
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
url: jdbc:sqlserver://localhost:1433;DatabaseName=test_02
username: sa
password: 12345678
master数据库名称为“test_01”,slave数据库名称为“test_02”。
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
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.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = MasterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
protected static final String PACKAGE = "com.test.domain.repository.master";
protected static final String MAPPER_LOCATION = "classpath:orm/*.xml";
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
@Primary
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "masterTransactionManager")
@Primary
public DataSourceTransactionManager masterTransactionManager() {
return new DataSourceTransactionManager(masterDataSource());
}
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource) throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(masterDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MasterDataSourceConfig.MAPPER_LOCATION));
return sessionFactory.getObject();
}
}
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.beans.factory.annotation.Qualifier;
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.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(basePackages = SlaveDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveDataSourceConfig {
public static final String PACKAGE = "com.test.domain.repository.slave";
public static final String MAPPER_LOCATION = "classpath:orm/*.xml";
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.slave")
public DataSource slaveDataSource() {
return new DruidDataSource();
}
@Bean(name = "slaveTransactionManager")
public DataSourceTransactionManager slaveTransactionManager(@Qualifier("slaveDataSource") DataSource slaveDataSource) {
return new DataSourceTransactionManager(slaveDataSource);
}
@Bean(name = "slaveSqlSessionFactory")
public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource slaveDataSource) throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(slaveDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(SlaveDataSourceConfig.MAPPER_LOCATION));
return sessionFactory.getObject();
}
}
@Service
@RequiredArgsConstructor
public class UserInfoService {
private final UserInfoService userInfoService;
@Transactional(value = "masterTransactionManager")
public void insertUserInfo(UserInfo userInfo) {
userInfoService.insertUserInfo(userInfo);
}
}
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@RequiredArgsConstructor
public class ContactService {
private final ContactMapper contactMapper;
@Transactional(value = "slaveTransactionManager")
public Contact getByOpenId(String openId) {
return contactMapper.getByOpenId(openId);
}
}
通过 @Transactional选择相应的数据库
起初,为了方便,我将master/slave对应的mapper放在一个目录下。
经验小结:将master与slave的dao层放在同一个目录时,例如都放在repository目录下。
项目运行时,总是报错Invalid object name 'xxxxxx',slave数据库没有选择成功。
https://blog.csdn.net/alone_in_/article/details/93848044
在mapper.xml文件中添加语句“use test_02”,指定数据库。
问题虽然得以解决,但是之前的配置就似乎没有必要了。进一步研究,得到方案2。
注意:master与slave的dao层是分开的。
将mater/slave对应的mapper层分别放在不同的目录里,运行程序后问题解决。