spring-mvc注解切换数据库实现读写分离

  1. 创建四个用到的类

  1. DataSource

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* @author muys

* @Date: 2023/2/27 15:42

*/

@Target({ElementType.METHOD, ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

public @interface DataSource {

String value() default "master";

}

  1. DataSourceAspect

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;

import java.lang.reflect.Method;

/**

* @author muys

* @Date: 2023/2/27 15:42

*/

@Aspect

@Component

public class DataSourceAspect {

/**

* @within匹配类上的注解

* @annotation匹配方法上的注解

*/

@Pointcut("@within(com.ytain.aop.DataSource)||@annotation(com.ytain.aop.DataSource)")

public void pointcut() {

}

@Before(value = "pointcut()")

public void beforeOpt(JoinPoint joinPoint) {

// 反射获取Method 方法一

Object target = joinPoint.getTarget();

Class<?> clazz = target.getClass();

Method[] methods = clazz.getMethods();

DataSource source = null;

for (Method method : methods) {

if (joinPoint.getSignature().getName().equals(method.getName())) {

source = method.getAnnotation(DataSource.class);

if (source == null) {

source = joinPoint.getTarget().getClass().getAnnotation(DataSource.class);

if (source == null) {

System.out.println("切到数据库失败");

return;

}

}

}

}

String dataSourceName = source.value();

DynamicDataSourceHolder.putDataSource(dataSourceName);

System.out.println("切到" + dataSourceName + "数据库");

}

}

  1. DynamicDataSource

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**

* @author muys

* @Date: 2023/2/27 15:40

*/

public class DynamicDataSource extends AbstractRoutingDataSource {

@Override

protected Object determineCurrentLookupKey() {

return DynamicDataSourceHolder.getDataSource();

}

}

  1. DynamicDataSourceHolder

/**

* @author muys

* @Date: 2023/2/27 15:41

*/

public class DynamicDataSourceHolder {

/**

* 设置线程

*/

public static final ThreadLocal<String> holder = new ThreadLocal<String>();

/**

* 设置连接源

*

* @param name

*/

public static void putDataSource(String name) {

holder.set(name);

System.out.println("使用的数据源为:" + name);

}

/**

* 获取连接源

*

* @return

*/

public static String getDataSource() {

return holder.get();

}

}

  1. mybatis.xml配置文件,标红的地方是和原来比较需要修改的地方

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="dataSource" ref="dynamicDataSource"/>

<property name="typeAliasesPackage" value="com.ytain"/>

<property name="typeAliasesSuperType" value="com.ytain.common.persistence.BaseEntity"/>

<property name="mapperLocations" value="classpath:/mappings/**/*.xml"/>

<property name="configLocation" value="classpath:/mybatis-config.xml"></property>

</bean>

<!-- 扫描basePackage下所有以@MyBatisDao注解的接口 -->

<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

<property name="basePackage" value="com.ytain"/>

<property name="annotationClass" value="com.ytain.common.persistence.annotation.MyBatisDao"/>

</bean>

<!-- 定义事务 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dynamicDataSource" />

</bean>

<!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务 -->

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

<!-- MyBatis end -->

<!-- 动态分配数据库连接源 -->

<bean id="dynamicDataSource" class="com.ytain.aop.DynamicDataSource">

<property name="targetDataSources">

<map key-type="java.lang.String">

<entry key="master" value-ref="dataSource"></entry>

<entry key="slave" value-ref="dataSourceRead"></entry>

</map>

</property>

<property name="defaultTargetDataSource" ref="dataSource" />

</bean>

<!-- 数据源配置, 使用 BoneCP 数据库连接池 -->

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">

<!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->

<property name="driverClassName" value="${jdbc.driver}" />

<!-- 基本属性 url、user、password -->

<property name="url" value="${jdbc.url}" />

<property name="username" value="${jdbc.username}" />

<property name="password" value="${jdbc.password}" />

<!-- 配置初始化大小、最小、最大 -->

<property name="initialSize" value="${jdbc.pool.init}" />

<property name="minIdle" value="${jdbc.pool.minIdle}" />

<property name="maxActive" value="${jdbc.pool.maxActive}" />

<!-- 配置获取连接等待超时的时间 -->

<property name="maxWait" value="100000" />

<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->

<property name="timeBetweenEvictionRunsMillis" value="60000" />

<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->

<property name="minEvictableIdleTimeMillis" value="300000" />

<!-- 超过时间限制是否回收 -->

<property name="removeAbandoned" value="true" />

<!-- 超时时间;单位为秒-->

<property name="removeAbandonedTimeout" value="180" />

<!-- 关闭abanded连接时输出错误日志 -->

<property name="logAbandoned" value="true" />

<property name="validationQuery" value="${jdbc.testSql}" />

<property name="testWhileIdle" value="true" />

<property name="testOnBorrow" value="true" />

<property name="testOnReturn" value="false" />

<!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)

<property name="poolPreparedStatements" value="true" />

<property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> -->

<!-- 配置监控统计拦截的filters -->

<property name="filters" value="stat" />

</bean>

<bean id="dataSourceRead" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">

<!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->

<property name="driverClassName" value="${jdbc.driver}" />

<!-- 基本属性 url、user、password -->

<property name="url" value="${jdbc.urlRead}" />

<property name="username" value="${jdbc.usernameRead}" />

<property name="password" value="${jdbc.passwordRead}" />

<!-- 配置初始化大小、最小、最大 -->

<property name="initialSize" value="${jdbc.pool.init}" />

<property name="minIdle" value="${jdbc.pool.minIdle}" />

<property name="maxActive" value="${jdbc.pool.maxActive}" />

<!-- 配置获取连接等待超时的时间 -->

<property name="maxWait" value="100000" />

<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->

<property name="timeBetweenEvictionRunsMillis" value="60000" />

<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->

<property name="minEvictableIdleTimeMillis" value="300000" />

<!-- 超过时间限制是否回收 -->

<property name="removeAbandoned" value="true" />

<!-- 超时时间;单位为秒-->

<property name="removeAbandonedTimeout" value="180" />

<!-- 关闭abanded连接时输出错误日志 -->

<property name="logAbandoned" value="true" />

<property name="validationQuery" value="${jdbc.testSql}" />

<property name="testWhileIdle" value="true" />

<property name="testOnBorrow" value="true" />

<property name="testOnReturn" value="false" />

<!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用)

<property name="poolPreparedStatements" value="true" />

<property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> -->

<!-- 配置监控统计拦截的filters -->

<property name="filters" value="stat" />

</bean>

  1. 检查spring-mvc.xml配置文件有没有如下配置,若没有需加上

<!-- 启动AspectJ支持 -->

<aop:aspectj-autoproxy proxy-target-class="true" />

  1. 使用及测试

默认使用主库,可在controller类上或者某个方法上添加注解@DataSource("slave"),即可使用读库。

@RequestMapping(value = "/testInsert")

@ResponseBody

public AjaxJson testInsert() {

AjaxJson json = new AjaxJson();

CompanyAccountFlow flow = new CompanyAccountFlow();

flow.setId("1");

flow.setRemarks("测试");

companyAccountFlowDao.insert(flow);

return json;

}

@RequestMapping(value = "/testGetSlave")

@ResponseBody

@DataSource("slave")

public AjaxJson testGetSlave() {

AjaxJson json = new AjaxJson();

CompanyAccountFlow flow =companyAccountFlowDao.get("1");

json.put("flow",flow);

return json;

}

@RequestMapping(value = "/testGetMaster")

@ResponseBody

@DataSource("master")

public AjaxJson testGetMaster() {

AjaxJson json = new AjaxJson();

CompanyAccountFlow flow =companyAccountFlowDao.get("1");

json.put("flow",flow);

return json;

}

@RequestMapping(value = "/testGet")

@ResponseBody

public AjaxJson testGet() {

AjaxJson json = new AjaxJson();

CompanyAccountFlow flow =companyAccountFlowDao.get("1");

json.put("flow",flow);

return json;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值