1.applicationContext.xml
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<!-- 自动扫描注入(controller在spring-mvc子容器中加载 ) -->
<context:component-scan base-package="com.wpao.shop.service" />
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 主数据源 -->
<bean id="masterDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbcDriver}" />
<property name="url" value="${jdbcUrl}" />
<property name="username" value="${jdbcUsername}" />
<property name="password" value="${jdbcPassword}" />
<property name="maxActive" value="${maxActive}" /><!-- 最大数据库连接数 -->
<property name="maxIdle" value="${maxIdle}" /><!-- 最大空闲连接数量 -->
<property name="maxWait" value="${maxWait}" /><!-- 超时等待时间,毫秒 -->
<property name="testWhileIdle" value="true" /><!-- 连接是否被回收器进行检验 -->
<property name="testOnBorrow" value="true" /><!-- 是否在从池中取出连接前进行检验 -->
<property name="validationQuery" value="select 1" />
<property name="timeBetweenEvictionRunsMillis" value="3600000" /><!-- 每隔多少时间检测一次,毫秒 -->
<property name="removeAbandoned" value="true" /><!-- 是否自动回收超时连接 -->
<property name="removeAbandonedTimeout" value="3600" /><!-- 超时时间,单位秒 -->
</bean>
<!-- 从数据源 -->
<bean id="slaveDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${slave_jdbcDriver}" />
<property name="url" value="${slave_jdbcUrl}" />
<property name="username" value="${slave_jdbcUsername}" />
<property name="password" value="${slave_jdbcPassword}" />
<property name="maxActive" value="${slave_maxActive}" />
<property name="maxIdle" value="${slave_maxIdle}" />
<property name="maxWait" value="${slave_maxWait}" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="true" />
<property name="validationQuery" value="select 1" />
<property name="timeBetweenEvictionRunsMillis" value="3600000" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="3600" />
</bean>
<!-- 动态数据源切换80914 -->
<bean id="dynamicDataSource" class="com.wpao.shop.util.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="master" value-ref="masterDataSource" />
<entry key="slave" value-ref="slaveDataSource" />
</map>
</property>
<property name="defaultTargetDataSource" ref="masterDataSource" />
</bean>
<!-- 配置事务管理器对象依赖的数据源 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dynamicDataSource" />
</bean>
<!-- 开启事务注解驱动 -->
<tx:annotation-driven />
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource"/>
<property name="configLocation" value="classpath:myconf.xml" />
<property name="mapperLocations" value="classpath:com/wpao/shop/mapper/*.xml" />
</bean>
<!-- 使用AOP进行切入操作 -->
<bean id="dataSourceAdvice" class="com.wpao.shop.util.DataSourceAdvice" />
<aop:config>
<aop:advisor pointcut="execution(* com.wpao.shop.dao.*.*(..))" advice-ref="dataSourceAdvice" />
</aop:config>
<!-- 配置扫描器(接口及对应的mapper.xml文件) -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.wpao.shop.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
2.DataSourceAdvice AOP切面根据传入的方法名选择数据源
//AOP切面类:
public class DataSourceAdvice implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice {
Logger logger = Logger.getLogger(this.getClass());
//service方法执行之前被调用:
public void before(Method method, Object[] args, Object target) {
try {
String inMethdName = (method != null && method.getName() != null) ? method.getName().trim() : "";
String methodName = inMethdName.toLowerCase();
if(methodName.startsWith("query")) {
DataSourceSwitcher.setSlave();
logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]方法已切换到:slave!");
}else if(methodName.startsWith("trans")) { //nei
//方法的内部方法,不做切换!
logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]内部方法不切换!");
}else {
DataSourceSwitcher.setMaster();
logger.info("***[shopmm]DataSource-切换:["+inMethdName+"]方法已切换回:master!");
}
}catch(Exception e) {
DataSourceSwitcher.setMaster();
logger.info("***[shopmm]DataSource-切换:出现异常,已切换回:master!Err:"+e.toString());
}
}
//service方法执行完之后被调用:
public void afterReturning(Object arg0, Method method, Object[] args, Object target) {try {
DataSourceSwitcher.clearDataSource();
}catch(Exception e) {
logger.info("***[shopmm]Aop-Service执行完成:出现异常("+method.getName()+")!Err:"+e.toString());
}
}
//抛出Exception之后被调用:
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {try {
DataSourceSwitcher.clearDataSource();}catch(Exception e) {
logger.info("***[shopmm]Aop-AfterThrowing:出现异常"+e.toString());
}
}
}
3.DataSourceSwitcher 设置当前线程上下文中的数据源对象
//数据源选择类:
public class DataSourceSwitcher {
@SuppressWarnings("rawtypes")
private static final ThreadLocal contextHolder = new ThreadLocal();
@SuppressWarnings("unchecked")
public static void setDataSource(String dataSource) {
//Assert.notNull(dataSource, "dataSource cannot be null");
contextHolder.set(dataSource);
}
public static void setMaster() {
setDataSource("master");
}
public static void setSlave() {
setDataSource("slave");
}public static String getDataSource() {
return (String)contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
4.DynamicDataSource 用于在产生事务之前,在线程上下文获取数据源
//数据源动态切换类:
public class DynamicDataSource extends AbstractRoutingDataSource {
Logger logger = Logger.getLogger(this.getClass());
@Override
protected Object determineCurrentLookupKey() {
String dtSoce = DataSourceSwitcher.getDataSource();
//logger.info("***[shopmm]nowLookupKey:"+dtSoce);
return dtSoce;
}}
5.调用:service配置@Transactional注解,在切入之前会自动装配对应的事务管理器
@Transactional
@Override
public String JoinPaim(String pmNo,BigDecimal chuMon,String logUser,String ipStr) throws Exception {}