首先在spring下配置多個dataSourcejava
<bean id="masterDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${master.driverClass}" /> <property name="jdbcUrl" value="${master.jdbcUrl}" /> <property name="user" value="${master.user}" /> <property name="password" value="${master.password}" /> <property name="minPoolSize" value="${master.minPoolSize}"></property> <property name="maxPoolSize" value="${master.maxPoolSize}"></property> <property name="maxIdleTime" value="${master.maxIdleTime}"></property> <property name="acquireIncrement" value="${master.acquireIncrement}"></property> <property name="maxStatements" value="${master.maxStatements}"></property> <property name="initialPoolSize" value="${master.initialPoolSize}"></property> <property name="idleConnectionTestPeriod" value="${master.idleConnectionTestPeriod}"></property> <property name="acquireRetryAttempts" value="${master.acquireRetryAttempts}"></property> <property name="breakAfterAcquireFailure" value="${master.breakAfterAcquireFailure}"></property> <property name="testConnectionOnCheckout" value="${master.testConnectionOnCheckout}"></property> <property name="autoCommitOnClose" value="${master.autoCommitOnClose}"></property> </bean> <bean id="slaveDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${slave.driverClass}" /> <property name="jdbcUrl" value="${slave.jdbcUrl}" /> <property name="user" value="${slave.user}" /> <property name="password" value="${slave.password}" /> <property name="minPoolSize" value="${slave.minPoolSize}"></property> <property name="maxPoolSize" value="${slave.maxPoolSize}"></property> <property name="maxIdleTime" value="${slave.maxIdleTime}"></property> <property name="acquireIncrement" value="${slave.acquireIncrement}"></property> <property name="maxStatements" value="${slave.maxStatements}"></property> <property name="initialPoolSize" value="${slave.initialPoolSize}"></property> <property name="idleConnectionTestPeriod" value="${slave.idleConnectionTestPeriod}"></property> <property name="acquireRetryAttempts" value="${slave.acquireRetryAttempts}"></property> <property name="breakAfterAcquireFailure" value="${slave.breakAfterAcquireFailure}"></property> <property name="testConnectionOnCheckout" value="${slave.testConnectionOnCheckout}"></property> <property name="autoCommitOnClose" value="${slave.autoCommitOnClose}"></property> </bean>
以後自定義一個數據源 算法
<bean id="myDynamicDataSource" class="com.up366.lsp.db.datasource.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>
本身寫的自定義數據源 spring
package com.up366.lsp.db.datasource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceHolder.getDataSouce(); } }
以後用線程變量控制sql
package com.up366.lsp.db.datasource; public class DynamicDataSourceHolder { public static final ThreadLocal<String> holder = new ThreadLocal<String>(); public static void setDataSource(String name) { holder.set(name); } public static String getDataSouce() { return holder.get(); } public static void clearDataSouce() { holder.remove(); } public static void setMaster() { DynamicDataSourceHolder.clearDataSouce(); } public static void setSlave() { DynamicDataSourceHolder.setDataSource("slave"); } }
以後配置一個執行前的aop 動態加載數據源express
<aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="manyDataSourceAspect" class="com.up366.lsp.db.datasource.DataSourceAspect" /> <aop:config> <aop:aspect id="c" ref="manyDataSourceAspect"> <aop:pointcut id="tx" expression="execution(* com.up366.lsp.db.dao.*.*(..))"/> <aop:before pointcut-ref="tx" method="before"/> </aop:aspect> </aop:config>
package com.up366.lsp.db.datasource; import java.lang.reflect.Method; import org.apache.ibatis.mapping.SqlCommandType; import org.apache.ibatis.session.SqlSessionFactory; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; import org.mybatis.spring.SqlSessionFactoryBean; import org.springframework.beans.factory.annotation.Autowired; import com.up366.lsp.db.datasource.anno.Master; import com.up366.lsp.db.datasource.anno.Slave; public class DataSourceAspect { @Autowired private SqlSessionFactoryBean sqlSessionFactory; public void before(JoinPoint point) { Object target = point.getTarget(); String method = point.getSignature().getName(); Class<?>[] classz = target.getClass().getInterfaces(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes(); try { Method m = classz[0].getMethod(method, parameterTypes); if (m != null ) { if(m.isAnnotationPresent(Slave.class)){ DynamicDataSourceHolder.setSlave(); return ; } if(m.isAnnotationPresent(Master.class)){ DynamicDataSourceHolder.setMaster(); return ; } //在沒有配置的狀況下走默認 String key = classz[0].getName()+"." + m.getName(); SqlSessionFactory ss = sqlSessionFactory.getObject(); //獲取類型 SqlCommandType type = ss.getConfiguration().getMappedStatement(key,false).getSqlCommandType(); //查詢默認從庫 if(SqlCommandType.SELECT == type){ DynamicDataSourceHolder.setSlave(); return ; } //增刪改默認主庫 if(type == SqlCommandType.DELETE || SqlCommandType.INSERT == type || SqlCommandType.UPDATE == type) DynamicDataSourceHolder.setMaster(); } } catch (Exception e) { } } }
基本上完成了 apache
若是是負載均衡的話 能夠對從庫進行負載多個配置 用算法去肯定session