ssm实现mysql读写分离
用于以后方便查看,借用:https://blog.csdn.net/weixin_43882034/article/details/84996443
1.创建 DyncmicDataSourceHolder 类
package cn.ljs.dyncmic; import com.alibaba.dubbo.common.utils.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 在读写分离的实现上, * Spring为我们提供了路由数据源的AbstractRoutingDataSource抽象类, * 我们只需编写一个新的类继承它, * 即可在不改变原有的代码的基础上实现读写分离 */ public class DyncmicDataSourceHolder { private static Logger logger= LoggerFactory.getLogger(DyncmicDataSourceHolder.class); /** * 保证线程安全,使用线程threadlocal */ private static ThreadLocalcontextHolder=new ThreadLocal (); public static final String DB_MASTER="master"; public static final String DB_SLAVE="slave"; /** * @return java.lang.String * @description 获取连接类型 */ public static String getDbType(){ String db=contextHolder.get(); if (StringUtils.isBlank(db)) { db=DB_MASTER; } return db; } /** * 设置数据源类型 * @param str */ public static void setDbType(String str){ logger.debug("使用数据源类型---"+str); System.err.println("使用数据源类型---"+str); contextHolder.set(str); } /** * 清理连接类型 */ public static void clearDaType(){ contextHolder.remove(); } }
2.创建 DynamicDataSource,继承AbstractRoutingDataSource
package cn.ljs.dyncmic; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DyncmicDataSourceHolder.getDbType(); } }
3 创建DyncmicDataSourceInterceptor,mybatis拦截器
package cn.ljs.dyncmic; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.executor.keygen.SelectKeyGenerator; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.plugin.*; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.support.TransactionSynchronizationManager; import java.util.Locale; import java.util.Properties; /** * 创建DyncmicDataSourceInterceptor,mybatis拦截器 */ @Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) public class DyncmicDataSourceInterceptor implements Interceptor { private static Logger logger = LoggerFactory.getLogger(DyncmicDataSourceInterceptor.class); // 写操作的正则表达式 private static final String REGEX = ".*insert\\u0020.*||.*delete\\u0020|.*update\\u0020.*"; @Override public Object intercept(Invocation invocation) throws Throwable { // 判断方法是否是被事务管理的 boolean synchronizationAction = TransactionSynchronizationManager.isActualTransactionActive(); //获取sql 中的参数 Object[] objects = invocation.getArgs(); MappedStatement mappedStatement = (MappedStatement) objects[0]; //数据源key String lookupKey = DyncmicDataSourceHolder.DB_MASTER; if (!synchronizationAction) { // 读方法 if (mappedStatement.getSqlCommandType().equals(SqlCommandType.SELECT)) { //selectKey为自增id查询主键(SELECT LAST_INSERT_ID)方法 if (mappedStatement.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)) { lookupKey = DyncmicDataSourceHolder.DB_MASTER; } else { //获取sql 语句 BoundSql boundSql = mappedStatement.getSqlSource().getBoundSql(objects[1]); String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replace("\\t\\n\\r", " "); if (sql.matches(REGEX)) {//insert、update、delete lookupKey = DyncmicDataSourceHolder.DB_MASTER; } else {//select lookupKey = DyncmicDataSourceHolder.DB_SLAVE; } } } } else { lookupKey = DyncmicDataSourceHolder.DB_MASTER; } logger.debug("设置方法[{}] use [{}] Strategy,SqlCommandType [{}]...", mappedStatement.getId(), lookupKey, mappedStatement.getSqlCommandType().name()); DyncmicDataSourceHolder.setDbType(lookupKey); return invocation.proceed(); } @Override public Object plugin(Object target) { //Executor表示含有增删改查的操作 的对象 if (target instanceof Executor) { //有增删改查的操作,就调用拦截方法 return Plugin.wrap(target, this); } else { //无增删改查的操作。不做处理 return target; } } @Override public void setProperties(Properties properties) { } }
4.修改mybatis-config,引入拦截器
<?xml version="1.0" encoding="UTF-8"?> DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><package name="cn.ljs.entity" />
5,修改mybatis配置文件,
<?xml version="1.0" encoding="UTF-8"?>xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> class="cn.ljs.dyncmic.DynamicDataSource"> class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"> class="org.mybatis.spring.SqlSessionFactoryBean"> class="org.mybatis.spring.mapper.MapperScannerConfigurer">