通过继承spring AbstractRoutingDataSource父类来进行动态的切换数据源,结合注解和spring aop来实现。
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
* 自定义的多数据源路由器.
*
*/
public class CustomerRoutingDataSource extends AbstractRoutingDataSource {
private final transient Logger log = LoggerFactory.getLogger(CustomerRoutingDataSource.class);
@Override
protected Object determineCurrentLookupKey() {
final String dbType = CustomerDBContextHolder.getDataSourceType();
if (log.isInfoEnabled()) {
log.info("获取了KEY={}的数据源", dbType);
}
return dbType;
}
}
/**
* 自定义的上下文储存器
*/
public class CustomerDBContextHolder {
//线程安全的ThreadLocal
private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static void setDataSourceType(String dbType) {
Assert.notNull(dbType, "DBType cannot be null");
contextHolder.set(dbType);
}
public static String getDataSourceType() {
String str = (String) contextHolder.get();
if (StringUtils.isBlank(str))
str = DataSource.master;
return str;
}
public static void clearDataSourceType() {
contextHolder.remove();
}
}
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
*注解
*/
public @interface DataSource {
String name() default DataSource.master;
public static String master = "master";
public static String slave = "slave";
}
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
*切点
*/
@Aspect
@Component
public class DataSourceAspect {
//定义切点
@Pointcut("@annotation(org.pos.manager.data.utils.spring.DataSource)")
public void daoAspect() {
}
@Before("daoAspect()")
public void doBefore(JoinPoint joinPoint){
try {
CustomerDBContextHolder.setDataSourceType(getDataSource(joinPoint));
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("rawtypes")
public static String getDataSource(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class targetClass = Class.forName(targetName);
Method[] methods = targetClass.getMethods();
String name = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class[] clazzs = method.getParameterTypes();
if (clazzs.length == arguments.length) {
name = method.getAnnotation(DataSource.class).name();
break;
}
}
}
return name;
}
}
数据源配置
<bean id="dataSourceWrite" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${master.jdbc.driverClassName}" />
<property name="jdbcUrl" value="${master.jdbc.url}" />
<property name="user" value="${master.jdbc.userDS.username}" />
<property name="password" value="${master.jdbc.userDS.password}" />
<!-- 连接池中保留的最小连接数 -->
<property name="minPoolSize" value="1" />
<!-- 连接池中保留的最大连接数 -->
<property name="maxPoolSize" value="200" />
<!-- 最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0-->
<property name="maxIdleTime" value="1800" />
<!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3-->
<property name="acquireIncrement" value="5" />
<!-- 最大的PreparedStatement的数量 -->
<property name="maxStatements" value="1000" />
<!-- 每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="60" />
<!-- 定义在从数据库获取新连接失败后重复尝试的次数。Default: 30-->
<property name="acquireRetryAttempts" value="30" />
<property name="breakAfterAcquireFailure" value="true" />
<property name="testConnectionOnCheckout" value="false" />
</bean>
<bean id="dataSourceRead" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${slave.jdbc.driverClassName}" />
<property name="jdbcUrl" value="${slave.jdbc.url}" />
<property name="user" value="${slave.jdbc.userDS.username}" />
<property name="password" value="${slave.jdbc.userDS.password}" />
<!-- 连接池中保留的最小连接数 -->
<property name="minPoolSize" value="1" />
<!-- 连接池中保留的最大连接数 -->
<property name="maxPoolSize" value="200" />
<!-- 最大空闲时间,1800秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0-->
<property name="maxIdleTime" value="1800" />
<!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3-->
<property name="acquireIncrement" value="5" />
<!-- 最大的PreparedStatement的数量 -->
<property name="maxStatements" value="1000" />
<!-- 每60秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="60" />
<!-- 定义在从数据库获取新连接失败后重复尝试的次数。Default: 30-->
<property name="acquireRetryAttempts" value="30" />
<property name="breakAfterAcquireFailure" value="true" />
<property name="testConnectionOnCheckout" value="false" />
</bean>
<bean id="dataSource" class="org.pos.manager.data.utils.spring.CustomerRoutingDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="master" value-ref="dataSourceWrite" />
<entry key="slave" value-ref="dataSourceRead" />
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceWrite"/>
</bean>
applicationContext.xml中加入aop代理配置
<aop:aspectj-autoproxy proxy-target-class="true" />
最后在service层实现动态设置
@Component(value = "accountBankService")
public class AccountBankServiceImpl implements AccountBankService {
@Autowired
@Qualifier(value = "accountBankDao")
private AccountBankDao accountBankDao;
@DataSource(name = DataSource.slave)
@Override
public List<AccountBank> getAccountBankList() throws Exception {
return accountBankDao.getAccountBankList();
}
}
分享到:
相关推荐
多数据源动态创建数据源,读写分离到不同的库 运用springboot mybatis mysql
springboot+druid+mybatis多数据源动态切换,基于sql类型完成读写分离操作
spring +springboot+mybatis+maven 读写分离,数据库采用mysql, 采用springboot 采用项目框架搭建,继承spring 中的AbstractRoutingDataSource,实现 determineCurrentLookupKey 进行数据源的动态切换,采用Spring ...
springboot整合mybatis实现多数据源读写分离 整合swagger快速接口开发
Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离Spring AOP + SpringMVC +Mybatis做动态数据源,实现读写分离
spring+mybatis 数据路由JAR包,实现事物级控制,读写库多次分离,非cloud 配置中心。
maven+ssm(spring,springmvc,mybatis)+读写分离的demo,读写分离是动态选取数据源
spring boot 集成 mybatis 并实现多数据源 通过 AOP 方式实现 读写分离,并且在多个主从数据库时,实现轮询访问。
springboot+mybatis结合,多数据源配置,并实现注解aop动态切换,可实现读写分离,maven结构。
支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。支持数据库敏感配置信息 加密(可自定义) ENC()。支持每个数据库独立初始化表结构schema和数据库database。支持无数据源启动,支持懒加载...
读写分离插,多数据源,数据库记录合并,支持事物。spring mybatis
spring 快速开发工具包,读写分离,多数据源,自动集成了mybatis,sharding-jdbc,redis,seata等
基于springboot,mybatis,druid的双数据源整合的starter介绍只需配置数据库连接信息即可实现数据库读写分离,master数据源负责写数据,slave数据源负责读数据。默认为master数据源,使用注解@ReadOnly实现数据源...
基于mybatis,springboot开箱即用的读写分离插件 此插件由以下2部分组成 datasource:读写数据源的代理,支持一写多读,用户只需实现 ...
spring-boot-mybatis-rw基于mybatis,springboot开箱即用的读写分离插件Quick StartMaven dependency<dependency> <groupId>...介绍此插件由以下2部分组成datasource:读写数据源的代理,支持一写多读,用户只需实现 ...
mysql多数据源基础配置,修改配置文件即可,可以此为基础实现数据同步,数据层读写分离等功能,配置dao层实现Spring boot管理,自动切换底层连接.
文件| 文献资料|特性支持数据源分组,适用于多种场景纯粹的多库读写分离一主多从混合模式。支持数据库敏感配置信息加密ENC()。支持每个数据库独立初始化表结构schema和数据库数据库。支持自定义注解,需继承DS...
采用spring mvc,spring+ mybatis,数据库使用的是mysql,只需要配置数据源,动态读取数据库,
spring默认支持多数据源,基于springboot、mybatis、阿里的druid数据库连接池实现mysql主从库读写分离。
当项目中使用到读写分离的时候,我们就会遇到多数据源的问题。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个spring和Mybatis的框架的项目中,我们在spring配置中往往是...