-
Notifications
You must be signed in to change notification settings - Fork 26
Dynamic_DataSource
睿驰 edited this page Mar 26, 2021
·
6 revisions
动态数据源使用示例。
完整示例代码:juice-samples
首先,添加juice-dynamic-datasource依赖:
<juice.version>1.0.0</juice.version>
<dependency>
<groupId>io.infinityclub</groupId>
<artifactId>juice-dynamic-datasource</artifactId>
<version>${juice.version}</version>
</dependency>
<dependency>
<groupId>io.infinityclub</groupId>
<artifactId>juice-spring-boot-starter</artifactId>
<version>${juice.version}</version>
</dependency>
application.yml增加如下配置:
spring:
datasource:
member:
master:
driver-class-name: com.mysql.cj.jdbc.Driver
filters: mergeStat
initial-size: 2
max-active: 100
max-wait: 20000
min-evictable-idle-time-millis: 300000
min-idle: 1
name: member_master
username: root2021
password: root2021
test-on-borrow: false
test-on-return: false
test-while-idle: true
time-between-eviction-runs-millis: 60000
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://10.10.175.136:3306/member_master?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
validation-query: SELECT 'x'
slave:
driver-class-name: com.mysql.cj.jdbc.Driver
filters: mergeStat
initial-size: 2
max-active: 100
max-wait: 20000
min-evictable-idle-time-millis: 300000
min-idle: 1
name: member_slave
username: root2021
password: root2021
test-on-borrow: false
test-on-return: false
test-while-idle: true
time-between-eviction-runs-millis: 60000
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://10.10.175.136:3306/member_slave?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
validation-query: SELECT 'x'
product:
master:
driver-class-name: com.mysql.cj.jdbc.Driver
filters: mergeStat
initial-size: 2
max-active: 100
max-wait: 20000
min-evictable-idle-time-millis: 300000
min-idle: 1
name: product_master
username: root2021
password: root2021
test-on-borrow: false
test-on-return: false
test-while-idle: true
time-between-eviction-runs-millis: 60000
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://10.10.175.136:3306/product_master?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
validation-query: SELECT 'x'
slave:
driver-class-name: com.mysql.cj.jdbc.Driver
filters: mergeStat
initial-size: 2
max-active: 100
max-wait: 20000
min-evictable-idle-time-millis: 300000
min-idle: 1
name: product_slave
username: root2021
password: root2021
test-on-borrow: false
test-on-return: false
test-while-idle: true
time-between-eviction-runs-millis: 60000
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://10.10.175.136:3306/product_slave?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
validation-query: SELECT 'x'
# mybatis的相关配置
mybatis:
mapper-locations: classpath*:mapper/**/*Mapper.xml
type-aliases-package: juice.samples.storage.entity
configLocation: classpath:mybatis/mybatis-config.xml
package juice.samples.config;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import juice.datasource.DynamicDataSource;
import juice.samples.constants.DataSourceKey;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
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;
import java.util.HashMap;
import java.util.Map;
/**
* @author Ricky Fung
*/
@Configuration
@MapperScan(value = "juice.samples.storage.**.mapper", sqlSessionFactoryRef = "sqlSessionFactory")
public class DruidDataSourceConfig {
@Value("${mybatis.mapper-locations:}")
private String mapperLocations;
@Value("${mybatis.type-aliases-package:}")
private String typeAliasesPackage;
@Value("${mybatis.configLocation:}")
private String configLocation;
@Bean
public DynamicDataSource dynamicDataSource() {
Map<String,String> pkgDefaultDsKeyMap = new HashMap<>(4);
pkgDefaultDsKeyMap.put("juice.samples.storage.mapper.member", DataSourceKey.MASTER_MEMBER);
pkgDefaultDsKeyMap.put("juice.samples.storage.mapper.product", DataSourceKey.MASTER_PRODUCT);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> tarDsMap = new HashMap<>(8);
tarDsMap.put(DataSourceKey.MASTER_MEMBER, memberMasterDS());
tarDsMap.put(DataSourceKey.SLAVE_MEMBER, memberSlaveDS());
tarDsMap.put(DataSourceKey.MASTER_PRODUCT, productMasterDS());
tarDsMap.put(DataSourceKey.SLAVE_PRODUCT, productSlaveDS());
dynamicDataSource.setTargetDataSources(tarDsMap);
dynamicDataSource.setDefaultTargetDataSource(tarDsMap.get(DataSourceKey.MASTER_MEMBER));
dynamicDataSource.setPkgDefaultDsKeyMap(pkgDefaultDsKeyMap);
return dynamicDataSource;
}
//==========
@Bean
@ConfigurationProperties("spring.datasource.member.master")
public DataSource memberMasterDS(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.member.slave")
public DataSource memberSlaveDS(){
return DruidDataSourceBuilder.create().build();
}
//==========
@Bean
@ConfigurationProperties("spring.datasource.product.master")
public DataSource productMasterDS(){
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties("spring.datasource.product.slave")
public DataSource productSlaveDS(){
return DruidDataSourceBuilder.create().build();
}
//===========
@Bean
public DataSourceTransactionManager transactionManager(DataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dynamicDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dynamicDataSource);
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
bean.setTypeAliasesPackage(typeAliasesPackage);
bean.setConfigLocation(new PathMatchingResourcePatternResolver().getResource(configLocation));
return bean.getObject();
}
}
最后,在 Application类加上 @EnableDynamicDataSource 注解,如下:
package juice.samples;
import juice.datasource.annotation.EnableDynamicDataSource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author Ricky Fung
*/
//开启动态数据源
@EnableDynamicDataSource(basePackages = {"juice.samples.storage.mapper", "juice.samples.storage.manager"})
@SpringBootApplication
public class JuiceApplication {
public static void main(String[] args) {
SpringApplication.run(JuiceApplication.class, args);
}
}
在需要切换数据源的类或者方法上加上 @DSRouting 注解即可,优先级:方法 > 类 > 包配置;
加在类上:
@DSRouting(DataSourceKey.MASTER_MEMBER)
public interface MemberMapper {
}
或者在方法上:
@Component
public class MemberManager {
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
@Resource
private MemberMapper memberMapper;
@DSRouting(DataSourceKey.MASTER_MEMBER)
public Member findById(Long id) {
return memberMapper.selectByPrimaryKey(id);
}
}
结合@Transactional一起使用,如下:
@DSRouting(value = DataSourceKey.MASTER_BYPASS)
@Transactional
public int deleteBill(Long billId) {
int rows = customerOrderBillMapper.updateDelete(billId);
int detailRows = customerOrderBillDetailMapper.updateDelete(billId);
//删除标记
int goodsRows = customerOrderBillGoodsMapper.deleteByBillId(billId);
LOG.info("甲方账单-删除账单, billId:{} 删除账单数量:{}, 账单详情数量:{}, 订单商品数量:{}", billId, rows, detailRows, goodsRows);
return rows;
}
@Copyright Ricky Fung 2012-2021 [但行好事,莫问前程]