mybatisAOP多数据源配置(使用阿里数据库连接池)
由于项目中需要使用数据源,用的网上开源的项目,之前使用网上通用的多数据源配置,没有切换成功,于是采用了AOP来切换数据源。
(此处只贴出关于多数据源和其他部分的一些配置)
spring-context.xml
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:context="http://www.springframework.org/schema/context" 5 xmlns:jdbc="http://www.springframework.org/schema/jdbc" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xmlns:jee="http://www.springframework.org/schema/jee" 8 xmlns:tx="http://www.springframework.org/schema/tx" 9 xmlns:util="http://www.springframework.org/schema/util" 10 xmlns:task="http://www.springframework.org/schema/task" 11 xsi:schemaLocation=" 12 http://www.springframework.org/schema/beans 13 http://www.springframework.org/schema/beans/spring-beans-4.1.xsd 14 http://www.springframework.org/schema/context 15 http://www.springframework.org/schema/context/spring-context-4.1.xsd 16 http://www.springframework.org/schema/jdbc 17 http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd 18 http://www.springframework.org/schema/aop 19 http://www.springframework.org/schema/aop/spring-aop.xsd 20 http://www.springframework.org/schema/jee 21 http://www.springframework.org/schema/jee/spring-jee-4.1.xsd 22 http://www.springframework.org/schema/lang 23 http://www.springframework.org/schema/lang/spring-lang.xsd 24 http://www.springframework.org/schema/tx 25 http://www.springframework.org/schema/tx/spring-tx-4.1.xsd 26 http://www.springframework.org/schema/util 27 http://www.springframework.org/schema/util/spring-util-4.1.xsd 28 http://www.springframework.org/schema/task 29 http://www.springframework.org/schema/task/spring-task-4.1.xsd" 30 default-lazy-init="true"> 31 32 <description>Spring Configuration</description> 33 34 <!-- 加载配置属性文件 --> 35 <context:property-placeholder ignore-unresolvable="true" location="classpath:jeesite.properties" /> 36 37 <!-- 加载应用属性实例,可通过 @Value("#{APP_PROP['jdbc.driver']}") String jdbcDriver 方式引用 --> 38 <util:properties id="APP_PROP" location="classpath:jeesite.properties" local-override="true"/> 39 40 <!-- 使用Annotation自动注册Bean,解决事物失效问题:在主容器中不扫描@Controller注解,在SpringMvc中只扫描@Controller注解。 --> 41 <context:component-scan base-package="com.vcard"><!-- base-package 如果多个,用“,”分隔 --> 42 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 43 </context:component-scan> 44 45 <bean id="jedisUtil" class="h2o.common.thirdparty.redis.JedisUtil"> 46 <constructor-arg> 47 <list> 48 <value>localhost:6379</value> 49 <value>localhost:6379</value> 50 </list> 51 </constructor-arg> 52 </bean> 53 54 <!-- MyBatis begin --> 55 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 56 <!-- <property name="dataSource" ref="dataSource"/> --> 57 <property name="dataSource" ref="dynamicDataSource"/> 58 <property name="typeAliasesPackage" value="com.vcard"/> 59 <property name="typeAliasesSuperType" value="com.vcard.common.persistence.BaseEntity"/> 60 <property name="mapperLocations" value="classpath:/mappings/**/*.xml"/> 61 <property name="configLocation" value="classpath:/mybatis-config.xml"></property> 62 </bean> 63 64 <!-- 扫描basePackage下所有以@MyBatisDao注解的接口 --> 65 <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 66 <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /> 67 <property name="basePackage" value="com.vcard"/> 68 <property name="annotationClass" value="com.vcard.common.persistence.annotation.MyBatisDao"/> 69 </bean> 70 71 <!-- 动态数据源 --> 72 <bean id="dynamicDataSource" class="com.vcard.common.db.DynamicDataSource"> 73 <property name="defaultTargetDataSource" ref="dataSource"/> 74 <property name="targetDataSources"> 75 <map key-type="java.lang.String"> 76 <!-- <entry key="dataSource" value-ref="dataSource"/> --> 77 <entry key="dataSource2" value-ref="dataSource2"/> 78 </map> 79 </property> 80 </bean> 81 82 <!-- 定义事务 --> 83 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 84 <property name="dataSource" ref="dynamicDataSource" /> 85 </bean> 86 87 <!-- 配置 Annotation 驱动,扫描@Transactional注解的类定义事务 --> 88 <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/> 89 90 <!-- 拦截器方式配置事务 --> 91 <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> 92 <tx:attributes> 93 <tx:method name="get*" propagation="REQUIRED" read-only="true"/> 94 <tx:method name="find*" propagation="REQUIRED" read-only="true"/> 95 <tx:method name="list*" propagation="REQUIRED" read-only="true"/> 96 <tx:method name="insert*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/> 97 <tx:method name="create*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/> 98 <tx:method name="update*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/> 99 <tx:method name="save*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/> 100 <tx:method name="delete*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/> 101 <tx:method name="upd*" rollback-for="java.lang.Exception" propagation="REQUIRED" read-only="false"/> 102 </tx:attributes> 103 </tx:advice> 104 105 <bean id="transactionAdvice" class="com.vcard.common.db.DataSourceAspect"></bean> 106 107 <aop:config> 108 <aop:pointcut id="transactionPointcut" expression="execution(* com.vcard.second.modules.order.web.*.*(..))" /> 109 <aop:advisor advice-ref="transactionAdvice" pointcut-ref="transactionPointcut"/> 110 </aop:config> 111 112 <!-- 定义事务 --> 113 <!-- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 114 <property name="dataSource" ref="dataSource" /> 115 </bean> --> 116 <!-- MyBatis end --> 117 118 <!-- 配置 JSR303 Bean Validator 定义 --> 119 <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /> 120 121 <!-- 缓存配置 --> 122 <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> 123 <property name="configLocation" value="classpath:${ehcache.configFile}" /> 124 </bean> 125 126 <!-- 计划任务配置,用 @Service @Lazy(false)标注类,用@Scheduled(cron = "0 0 2 * * ?")标注方法 --> 127 <task:executor id="executor" pool-size="10"/> <task:scheduler id="scheduler" pool-size="10"/> 128 <task:annotation-driven scheduler="scheduler" executor="executor" proxy-target-class="true"/> 129 130 <!-- 数据源配置, 使用 BoneCP 数据库连接池 --> 131 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 132 <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> 133 <property name="driverClassName" value="${jdbc.driver}" /> 134 135 <!-- 基本属性 url、user、password --> 136 <property name="url" value="${jdbc.url}" /> 137 <property name="username" value="${jdbc.username}" /> 138 <property name="password" value="${jdbc.password}" /> 139 140 <!-- 配置初始化大小、最小、最大 --> 141 <property name="initialSize" value="${jdbc.pool.init}" /> 142 <property name="minIdle" value="${jdbc.pool.minIdle}" /> 143 <property name="maxActive" value="${jdbc.pool.maxActive}" /> 144 145 <!-- 配置获取连接等待超时的时间 --> 146 <property name="maxWait" value="60000" /> 147 148 <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> 149 <property name="timeBetweenEvictionRunsMillis" value="60000" /> 150 151 <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> 152 <property name="minEvictableIdleTimeMillis" value="300000" /> 153 154 <property name="validationQuery" value="${jdbc.testSql}" /> 155 <property name="testWhileIdle" value="true" /> 156 <property name="testOnBorrow" value="false" /> 157 <property name="testOnReturn" value="false" /> 158 159 <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用) 160 <property name="poolPreparedStatements" value="true" /> 161 <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> --> 162 163 <!-- 配置监控统计拦截的filters --> 164 <property name="filters" value="stat" /> 165 </bean> 166 167 <!-- 数据源配置, 使用 BoneCP 数据库连接池 --> 168 <bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 169 <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> 170 <property name="driverClassName" value="${jdbc2.driver}" /> 171 172 <!-- 基本属性 url、user、password --> 173 <property name="url" value="${jdbc2.url}" /> 174 <property name="username" value="${jdbc2.username}" /> 175 <property name="password" value="${jdbc2.password}" /> 176 177 <!-- 配置初始化大小、最小、最大 --> 178 <property name="initialSize" value="${jdbc2.pool.init}" /> 179 <property name="minIdle" value="${jdbc2.pool.minIdle}" /> 180 <property name="maxActive" value="${jdbc2.pool.maxActive}" /> 181 182 <!-- 配置获取连接等待超时的时间 --> 183 <property name="maxWait" value="60000" /> 184 185 <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> 186 <property name="timeBetweenEvictionRunsMillis" value="60000" /> 187 188 <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> 189 <property name="minEvictableIdleTimeMillis" value="300000" /> 190 191 <property name="validationQuery" value="${jdbc.testSql}" /> 192 <property name="testWhileIdle" value="true" /> 193 <property name="testOnBorrow" value="false" /> 194 <property name="testOnReturn" value="false" /> 195 196 <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用) 197 <property name="poolPreparedStatements" value="true" /> 198 <property name="maxPoolPreparedStatementPerConnectionSize" value="20" /> --> 199 200 <!-- 配置监控统计拦截的filters --> 201 <property name="filters" value="stat" /> 202 </bean> 203 204 <!-- 数据源配置, 使用应用服务器的数据库连接池 205 <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/jeesite" />--> 206 207 <!-- 数据源配置, 不使用连接池 208 <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 209 <property name="driverClassName" value="${jdbc.driver}" /> 210 <property name="url" value="${jdbc.url}" /> 211 <property name="username" value="${jdbc.username}"/> 212 <property name="password" value="${jdbc.password}"/> 213 </bean>--> 214 215 </beans>
jeesite.properties
1 #============================# 2 #===== Database sttings =====# 3 #============================# 4 5 #oracle database settings 6 #jdbc.type=oracle 7 #jdbc.driver=oracle.jdbc.driver.OracleDriver 8 #jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl 9 #jdbc.username=jeesite 10 #jdbc.password=123456 11 12 #mysql database setting 13 jdbc.type=mysql 14 jdbc.driver=com.mysql.jdbc.Driver 15 #jdbc.url=jdbc:mysql://localhost:3306/vcardjeesite?useUnicode=true&characterEncoding=utf-8 16 #jdbc.username=root 17 #jdbc.password=123456 18 jdbc.url=jdbc:mysql://localhost:3306/vcardjeesite?useUnicode=true&characterEncoding=utf-8 19 jdbc.username=changyue 20 jdbc.password=cykjdev164123 21 22 jdbc2.type=mysql 23 jdbc2.driver=com.mysql.jdbc.Driver 24 jdbc2.url=jdbc:mysql://localhost:3306/newmall?useUnicode=true&characterEncoding=utf-8 25 jdbc2.username=changyue 26 jdbc2.password=cykjdev164123 27 #jdbc2.url=jdbc:mysql://localhost:3306/newmalljeesite?useUnicode=true&characterEncoding=utf-8 28 #jdbc2.username=root 29 #jdbc2.password=123456 30 31 #mssql database settings 32 #jdbc.type=mssql 33 #jdbc.driver=net.sourceforge.jtds.jdbc.Driver 34 #jdbc.url=jdbc:jtds:sqlserver://localhost:1433/jeesite 35 #jdbc.username=sa 36 #jdbc.password=sa 37 38 #pool settings 39 jdbc.pool.init=1 40 jdbc.pool.minIdle=3 41 jdbc.pool.maxActive=20 42 43 jdbc2.pool.init=1 44 jdbc2.pool.minIdle=3 45 jdbc2.pool.maxActive=20 46 47 #jdbc.testSql=SELECT 'x' 48 jdbc.testSql=SELECT 'x' FROM DUAL 49 50 #redis settings 51 redis.keyPrefix=vcard 52 redis.host=localhost 53 redis.port=6379 54 55 #============================# 56 #===== System settings ======# 57 #============================# 58 59 #\u4ea7\u54c1\u4fe1\u606f\u8bbe\u7f6e 60 productName=\u5546\u6237\u5F00\u653E\u5E73\u53F0 61 copyrightYear=2017 62 version=V1.2.7 63 64 #\u6f14\u793a\u6a21\u5f0f: \u4e0d\u80fd\u64cd\u4f5c\u548c\u4fdd\u5b58\u7684\u6a21\u5757\uff1a sys: area/office/user/role/menu/dict, cms: site/category 65 demoMode=false 66 67 #\u7ba1\u7406\u57fa\u7840\u8def\u5f84, \u9700\u540c\u6b65\u4fee\u6539\uff1aweb.xml 68 adminPath=/a 69 70 #\u524d\u7aef\u57fa\u7840\u8def\u5f84 71 frontPath=/f 72 73 #\u7f51\u7ad9URL\u540e\u7f00 74 urlSuffix=.html 75 76 #\u662f\u5426\u4e0d\u5141\u8bb8\u5237\u65b0\u4e3b\u9875\uff0c\u4e0d\u5141\u8bb8\u60c5\u51b5\u4e0b\uff0c\u5237\u65b0\u4e3b\u9875\u4f1a\u5bfc\u81f4\u91cd\u65b0\u767b\u5f55 77 notAllowRefreshIndex=false 78 79 #\u662f\u5426\u5141\u8bb8\u591a\u8d26\u53f7\u540c\u65f6\u767b\u5f55 80 user.multiAccountLogin=true 81 82 #\u5206\u9875\u914d\u7f6e 83 page.pageSize=10 84 85 #\u7855\u6b63\u7ec4\u4ef6\u662f\u5426\u4f7f\u7528\u7f13\u5b58 86 supcan.useCache=false 87 88 #\u901a\u77e5\u95f4\u9694\u65f6\u95f4\u8bbe\u7f6e, \u5355\u4f4d\uff1a\u6beb\u79d2, 30s=30000ms, 60s=60000ms 89 oa.notify.remind.interval=60000 90 91 #============================# 92 #==== Framework settings ====# 93 #============================# 94 95 #\u4f1a\u8bdd\u8d85\u65f6\uff0c \u5355\u4f4d\uff1a\u6beb\u79d2\uff0c 20m=1200000ms, 30m=1800000ms, 60m=3600000ms 96 session.sessionTimeout=1800000 97 #\u4f1a\u8bdd\u6e05\u7406\u95f4\u9694\u65f6\u95f4\uff0c \u5355\u4f4d\uff1a\u6beb\u79d2\uff0c2m=120000ms\u3002 98 session.sessionTimeoutClean=120000 99 100 #\u7f13\u5b58\u8bbe\u7f6e 101 ehcache.configFile=cache/ehcache-local.xml 102 #ehcache.configFile=cache/ehcache-rmi.xml 103 104 #\u7d22\u5f15\u9875\u8def\u5f84 105 web.view.index=/a 106 107 #\u89c6\u56fe\u6587\u4ef6\u5b58\u653e\u8def\u5f84 108 web.view.prefix=/WEB-INF/views/ 109 web.view.suffix=.jsp 110 111 #\u6700\u5927\u6587\u4ef6\u4e0a\u4f20\u9650\u5236\uff0c\u5355\u4f4d\u5b57\u8282. 10M=10*1024*1024(B)=10485760 bytes\uff0c\u9700\u540c\u6b65\u4fee\u6539\uff1ackfinder.xml 112 web.maxUploadSize=10485760 113 114 #\u65e5\u5fd7\u62e6\u622a\u8bbe\u7f6e\uff0c\u6392\u9664\u7684URI\uff1b\u5305\u542b @RequestMapping\u6ce8\u89e3\u7684value\u3002\uff08\u5df2\u4f5c\u5e9f\uff09 115 #web.logInterceptExcludeUri=/, /login, /sys/menu/tree, /sys/menu/treeData, /oa/oaNotify/self/count 116 #web.logInterceptIncludeRequestMapping=save, delete, import, updateSort 117 118 #\u9759\u6001\u6587\u4ef6\u540e\u7f00 119 web.staticFile=.css,.js,.png,.jpg,.gif,.jpeg,.bmp,.ico,.swf,.psd,.htc,.htm,.html,.crx,.xpi,.exe,.ipa,.apk 120 121 #\u5355\u70b9\u767b\u5f55CAS\u8bbe\u7f6e 122 cas.server.url=http://127.0.0.1:8080/cas 123 cas.project.url=http://127.0.0.1:8080/vcard 124 125 #\u5de5\u4f5c\u6d41\u8bbe\u7f6e 126 activiti.isSynActivitiIndetity=false 127 activiti.export.diagram.path=c:/activiti_diagram 128 #activiti font (windows font: \u5b8b\u4f53 linux font: simsun) 129 activiti.diagram.activityFontName=\u5b8b\u4f53 130 activiti.diagram.labelFontName=\u5b8b\u4f53 131 #5.21.0 \u65b0\u589e\u53c2\u6570 ,2016.06.23 \u8f66\u6811\u708e add 132 activiti.diagram.annotationFontName=\u5b8b\u4f53 133 #activiti\u5916\u90e8\u8868\u5355\u6839\u5730\u5740\u914d\u7f6e 134 activiti.form.server.url= 135 136 #\u4e0a\u4f20\u6587\u4ef6\u7edd\u5bf9\u8def\u5f84, \u8def\u5f84\u4e2d\u4e0d\u5141\u8bb8\u5305\u542b\u201cuserfiles\u201d 137 #userfiles.basedir=D:/jeesite 138 139 #\u5de5\u7a0b\u8def\u5f84\uff0c\u5728\u4ee3\u7801\u751f\u6210\u65f6\u83b7\u53d6\u4e0d\u5230\u5de5\u7a0b\u8def\u5f84\u65f6\uff0c\u53ef\u518d\u6b64\u6307\u5b9a\u7edd\u5bf9\u8def\u5f84\u3002 140 #projectPath=D\:\\workspace\\jeesite
DynamicDataSource.java
1 import org.aspectj.lang.annotation.Aspect; 2 import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 3 import org.springframework.stereotype.Component; 4 5 /** 6 * 多数据源配置 7 */ 8 @Component 9 @Aspect 10 public class DynamicDataSource extends AbstractRoutingDataSource { 11 12 public DynamicDataSource() { 13 } 14 15 @Override 16 protected Object determineCurrentLookupKey() { 17 return DBContextHolder.getDbType(); 18 } 19 20 public java.util.logging.Logger getParentLogger() { 21 return null; 22 } 23 }
DBContextHolder.java
1 public class DBContextHolder { 2 private static ThreadLocal<String> contextHolder = new ThreadLocal<String>(); 3 public static String Master = "dataSource"; 4 public static String Slave = "dataSource2"; 5 6 public DBContextHolder() { 7 } 8 9 public static String getDbType() { 10 String db = contextHolder.get(); 11 if (db == null) { 12 db = Master; 13 } 14 return db; 15 } 16 17 public static void setDbType(String str) { 18 contextHolder.set(str); 19 } 20 21 public static void setMater() { 22 contextHolder.set(Master); 23 } 24 25 public static void serSlave() { 26 contextHolder.set(Slave); 27 } 28 29 public static void clearDBType() { 30 contextHolder.remove(); 31 } 32 }
DataSourceAspect.java
1 import java.lang.reflect.Method; 2 3 import org.apache.logging.log4j.LogManager; 4 import org.apache.logging.log4j.Logger; 5 import org.aspectj.lang.JoinPoint; 6 import org.springframework.aop.AfterReturningAdvice; 7 import org.springframework.aop.MethodBeforeAdvice; 8 import org.springframework.aop.ThrowsAdvice; 9 10 public class DataSourceAspect implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice { 11 private static final Logger log = LogManager.getLogger(DataSourceAspect.class); 12 13 public DataSourceAspect() { 14 } 15 16 public void before(Method m, Object[] args, Object target) throws Throwable { 17 try { 18 if (m != null) { 19 // 拦截ImsShopOrderController中的方法,切换数据源 20 if ((m.getName().equals("listImsShopOrder") 21 || m.getName().equals("sendGoods") 22 || m.getName().equals("cancleSend")) 23 && !m.getName().contains("FromMaster")) { 24 DBContextHolder.setDbType(DBContextHolder.Slave); 25 } else { 26 DBContextHolder.setDbType(DBContextHolder.Master); 27 } 28 } 29 } catch (Exception var5) { 30 log.error("data source aspect error.", var5); 31 } 32 33 } 34 35 public void after(JoinPoint point) { 36 log.info("clear db type after method.current id {}", 37 new Object[] { Long.valueOf(Thread.currentThread().getId()) }); 38 DBContextHolder.clearDBType(); 39 } 40 41 public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { 42 } 43 44 public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable { 45 log.info("current db type {} when exception", new Object[] { DBContextHolder.getDbType() }); 46 DBContextHolder.setDbType(DBContextHolder.Master); 47 } 48 }