springboot+mybatis数据源的读写分离(mysql,后期连接设置,前期项目没做好的忽入会蒙的)

16 篇文章 0 订阅
10 篇文章 0 订阅

参考https://github.com/cmlbeliever/SpringBootLearning/tree/master/DynamicDataSource 

以上是github的网址


用到了这里说明springboot的项目已经结尾开始加数据源了~

1.多数据源的类如下


2.配置文件目录如下


3.在配置文件俺application中加入数据源和配置切面拦截的方法

 (1)数据源

 

#read database

read.datasource.driverClassName=com.mysql.jdbc.Driver
read.datasource.url=
read.datasource.username=
read.datasource.password=
read.datasource.maxdle=10
read.datasource.maxWait=10000
read.datasource.minIdle=5
read.datasource.initialSize=5
read.datasource.validation-query=SELECT 1 
read.datasource.testWhileIdle=true 
read.datasource.timeBetweenEvictionRunsMillis=27800
#write database
write.datasource.driverClassName=com.mysql.jdbc.Driver
write.datasource.url=
write.datasource.username=
write.datasource.password=
write.datasource.maxdle=10
write.datasource.maxWait=10000
write.datasource.minIdle=5
write.datasource.initialSize=5
write.datasource.validation-query=SELECT 1 
write.datasource.testWhileIdle=true 
write.datasource.timeBetweenEvictionRunsMillis=27800

#mybatis

#待会mybatis类进行文件配置用的路径
 db.mybatis.mapper-locations=classpath:com/ewe/*/mapping/*.xml
 db.mybatis.configLocation=mybatis/mybatis-config.xml
#aspect 事务切入  
dynamicDatasource.strategy.read=get,find,select,login
  dynamicDatasource.strategy.write=insert,update,delete,add,regist,create
  dynamicDatasource.defaultDataSource=write
以下是mybatis的
<?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">
<configuration>
	<settings>
	    <!-- 使全局的映射器启用或禁用缓存。 -->
		<setting name="cacheEnabled" value="mybatis" />
		<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 -->
		<setting name="lazyLoadingEnabled" value="true" />
		<!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。 -->        
         <setting name="aggressiveLazyLoading" value="true"/>        
         <!-- 是否允许单条sql 返回多个数据集  (取决于驱动的兼容性) default:true -->
		<setting name="multipleResultSetsEnabled" value="true" />
		<!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true -->
		<setting name="useColumnLabel" value="true" />
		<!-- 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。  default:false  -->
		<setting name="useGeneratedKeys" value="false" />
		<!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分  FULL:全部  -->
		<setting name="autoMappingBehavior" value="PARTIAL" />
		<!-- 这是默认的执行类型  (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新)  -->
		<setting name="defaultExecutorType" value="SIMPLE" />
		
		<setting name="defaultStatementTimeout" value="25" />
		
		<setting name="defaultFetchSize" value="100" />
		
		<setting name="safeRowBoundsEnabled" value="false" />
		<!-- 使用驼峰命名法转换字段。 -->
		<setting name="mapUnderscoreToCamelCase" value="true" />
		<!-- 设置本地缓存范围 session:就会有数据的共享  statement:语句范围 (这样就不会有数据的共享 ) defalut:session -->
		<setting name="localCacheScope" value="SESSION" />
		<!-- 默认为OTHER,为了解决oracle插入null报错的问题要设置为NULL -->
		<setting name="jdbcTypeForNull" value="NULL" />
		<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
	</settings>
	
</configuration>


pom依赖

<!-- Aspect -->
		<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

		<!-- dbcp -->
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
		</dependency>
		<!-- StringUtils -->
		<dependency>  
		    <groupId>commons-lang</groupId>  
		    <artifactId>commons-lang</artifactId>  
		    <version>2.6</version>  
		   <!--  <scope>provided</scope>  --> 
	    </dependency>




首先要创建一个mybatis的的配置加载类

DynamicDataSourceAutoConfiguration.java

package com.ewe.core.datasource;



import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.sql.DataSource;


import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

/**
 * 动态数据源自动处理 TransactionProxyFactoryBean
 * 
 * @author Martin
 *
 */
public class DynamicDataSourceAutoConfiguration {

	@Component("dynamicDataSource")
	@Primary
	@ConfigurationProperties(prefix = "dynamicDatasource")
	public static class DynamicDataSource extends AbstractRoutingDataSource implements ApplicationContextAware {

		public static final Map<String, String> DATASOURCE_STRATEGY = new HashMap<>();

		private Map<String, String> strategy = new HashMap<>();
		private ApplicationContext applicationContext;
		private String defaultDataSource;

		@Override
		protected Object determineCurrentLookupKey() {
			return DynamicDataSourceHolder.getDataSource();
		}

		@Override
		protected Object resolveSpecifiedLookupKey(Object lookupKey) {
			return super.resolveSpecifiedLookupKey(lookupKey);
		}

		@Override
		public void afterPropertiesSet() {
			Map<String, DataSource> dataSources = applicationContext.getBeansOfType(DataSource.class);
			if (dataSources.size() == 0) {
				throw new IllegalStateException("Datasource can not found!!!");
			}

			// exclude current datasource
			Map<Object, Object> targetDataSource = excludeCurrentDataSource(dataSources);
			setTargetDataSources(targetDataSource);

			// 多数据源方法设置
			Iterator<String> it = strategy.keySet().iterator();
			while (it.hasNext()) {
				String key = it.next();
				String[] values = strategy.get(key).split(",");
				for (String v : values) {
					if (v!=null&&v!="") {
						DATASOURCE_STRATEGY.put(v, key);
					}
				}
			}

			// 默认数据源设置
			setDefaultTargetDataSource(targetDataSource.get(getDefaultDataSource()));

			super.afterPropertiesSet();
		}

		/***
		 * exclude current Datasource
		 * 
		 * @param dataSources
		 * @return
		 */
		private Map<Object, Object> excludeCurrentDataSource(Map<String, DataSource> dataSources) {
			Map<Object, Object> targetDataSource = new HashMap<>();
			Iterator<String> keys = dataSources.keySet().iterator();
			while (keys.hasNext()) {
				String key = keys.next();
				if (!(dataSources.get(key) instanceof DynamicDataSource)) {
					targetDataSource.put(key, dataSources.get(key));
				}
			}
			return targetDataSource;
		}

		@Override
		public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
			this.applicationContext = applicationContext;
		}

		public Map<String, String> getStrategy() {
			return strategy;
		}

		public void setStrategy(Map<String, String> strategy) {
			this.strategy = strategy;
		}

		public String getDefaultDataSource() {
			return defaultDataSource;
		}

		public void setDefaultDataSource(String defaultDataSource) {
			this.defaultDataSource = defaultDataSource;
		}

	}

}
2.MybatisConfig的数据库加载

package com.ewe.core.datasource;
import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
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.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;
/**
 * 
 * @author Martin
 *
 */
@Configuration
public class MybatisConfig {

	protected static Log log = LogFactory.getLog(MybatisConfig.class);

	@Bean(name = "sqlSessionFactory")
	public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource datasource,
			MybatisConfigurationProperties properties) throws Exception {

		log.info("*************************sqlSessionFactory:begin***********************" + properties);

		VFS.addImplClass(SpringBootVFS.class);

		SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
		sessionFactory.setDataSource(datasource);

		ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
		sessionFactory.setMapperLocations(resolver.getResources(properties.mapperLocations));

		// sessionFactory
		// .setConfigLocation(new
		// PathMatchingResourcePatternResolver().getResource(properties.configLocation));

		SqlSessionFactory resultSessionFactory = sessionFactory.getObject();

		log.info("*************************sqlSessionFactory:successs:" + resultSessionFactory
				+ "***********************" + properties);

		return resultSessionFactory;

	}

	@ConfigurationProperties(prefix = "write.datasource")
	@Bean(destroyMethod = "close", name = "write")
	public DataSource dataSourceWrite() {

		log.info("*************************writedataSource***********************");

		BasicDataSource dataSource = new BasicDataSource();
		// dataSource.setDriverClassName(properties.driverClassName);
		// dataSource.setUrl(properties.url);
		// dataSource.setUsername(properties.username);
		// dataSource.setPassword(properties.password);
		// dataSource.setMaxIdle(properties.maxIdle);
		// dataSource.setMaxActive(properties.maxActive);
		// dataSource.setMaxWait(properties.maxWait);
		// dataSource.setInitialSize(properties.initialSize);
		// dataSource.setValidationQuery(properties.validationQuery);
		/*dataSource.setRemoveAbandoned(true);
		dataSource.setTestWhileIdle(true);
		dataSource.setTimeBetweenEvictionRunsMillis(30000);
		dataSource.setNumTestsPerEvictionRun(30);
		dataSource.setMinEvictableIdleTimeMillis(1800000);*/
		return dataSource;
		
	}

	@ConfigurationProperties(prefix = "read.datasource")
	@Bean(destroyMethod = "close", name = "read")
	public DataSource dataSourceRead() {
		log.info("*************************readdataSource***********************");
		BasicDataSource dataSource = new BasicDataSource();
		return dataSource;
	}

	/**
	 * 加载mybatis的配置文件
	 * @author Administrator
	 *
	 */
	@ConfigurationProperties(prefix = "db.mybatis")
	@Component
	public static class MybatisConfigurationProperties {
		private String mapperLocations;
		private String configLocation;
		
		public String getConfigLocation() {
			return configLocation;
		}

		public void setConfigLocation(String configLocation) {
			this.configLocation = configLocation;
		}

		public String getMapperLocations() {
			return mapperLocations;
		}

		public void setMapperLocations(String mapperLocations) {
			this.mapperLocations = mapperLocations;
		}
		@Override
		public String toString() {
			return "MybatisConfigurationProperties [typeAliasesPackage=" + "" + ", typeHandlerPackage="
					+ "" + ", mapperLocations=" + mapperLocations + ", configLocation=" + configLocation
					+ "]";
		}

	}

}
3.DynamicDataSourceHolder 动态数据源处理

package com.ewe.core.datasource;



/**
 * 动态数据源处理
 * 
 * @author Martin
 *
 */
public class DynamicDataSourceHolder {
	private static ThreadLocal<String> holderDataSource = new ThreadLocal<>();

	public static void setDataSource(String dataSource) {
		holderDataSource.set(dataSource);
	}

	public static String getDataSource() {
		return holderDataSource.get();
	}

	public static void clear() {
		holderDataSource.remove();
	}

}

4.事务代理 TransactionAspect

package com.ewe.core.datasource;



import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import com.ewe.core.datasource.DynamicDataSourceAutoConfiguration.DynamicDataSource;


/**
 * 事务自动代理
 * 如果一个services执行多条语句,那么尽管是查询语句也会从主库查询,因为是以service为事务而不是,而是不是dao
 * @author Martin
 *
 */
@Order(1)
@Aspect()
@EnableAspectJAutoProxy
@Component
public class TransactionAspect {

	protected static Log logger = LogFactory.getLog(TransactionAspect.class);
	

	@Pointcut("execution(* com.ewe.*.service.impl.*.*(..))")
	public void aspect() {
	}

	/**
	 * 配置前置通知,使用在方法aspect()上注册的切入点
	 * 
	 */
	@Before("aspect()")
	public void before(JoinPoint point) {
		String className = point.getTarget().getClass().getName();
		String method = point.getSignature().getName();
		logger.info(className + "." + method + "(" + StringUtils.join(point.getArgs(), ",") + ")");
		try {
			// 根据方法获取对应的数据源
			for (String key : DynamicDataSource.DATASOURCE_STRATEGY.keySet()) {
				if (StringUtils.startsWith(method, key)) {
					DynamicDataSourceHolder.setDataSource(DynamicDataSource.DATASOURCE_STRATEGY.get(key));
					logger.info("---------find datasource ==>" + key + ",datasource:" + DynamicDataSourceHolder.getDataSource()+"-------------");
					break;
				}
			}
		} catch (Exception e) {
			logger.error(e.toString());
			// DynamicDataSourceHolder.setDataSource("write");
		}
	}

	@After("aspect()")
	public void after(JoinPoint point) {
		DynamicDataSourceHolder.clear();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值