在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离
注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html
mysql主从同步: http://www.cnblogs.com/xiaochangwei/p/4824355.html
如果项目所有读操作和写操作操作不同的数据库,完全读写分离,那么可以简单的通过mybaits的plugins来实现
读写分离的实现数据源切换部分,完全依靠 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource,这是spring提供的抽象数据源方法
1.首先定义数据源切换方法
package net.zicp.xiaochangwei.web.multipeDataSource; /** * @author 肖昌伟 E-mail:317409898@qq.com * @version 创建时间:2016年6月23日 下午2:04:33 * */ public class DataSourceSwith { private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); public static final String UPDATE = "UPDATE"; public static final String QUERY = "QUERY"; public static void setDataSource(String dataSource) { contextHolder.set(dataSource); } public static String getDataSource() { return (String) contextHolder.get(); } public static void clearDataSource() { contextHolder.remove(); } }
2.继承抽象数据源接口并重写方法确定用哪一个数据源
package net.zicp.xiaochangwei.web.multipeDataSource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * @author 肖昌伟 E-mail:317409898@qq.com * @version 创建时间:2016年6月23日 下午2:04:01 * */ public class DataSources extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceSwith.getDataSource(); } }
3.配置数据源并指明数据源对应的key
<bean id="dataSource" class="net.zicp.xiaochangwei.web.multipeDataSource.DataSources">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="dataSourceUpdate" key="UPDATE"></entry>
<entry value-ref="dataSourceQuery" key="QUERY"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceUpdate"></property>
</bean>
4.配置mybatis plugins(只看红色部分,除mybatis常规配置外,其它部分配置是分表用的)
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:mybatis/Configuration.xml" /> <!-- mapper配置路径 --> <property name="mapperLocations"> <list> <value>classpath:mybatis/*Mapper.xml</value> </list> </property> <property name="plugins"> <array> <bean class="net.zicp.xiaochangwei.web.interceptors.MybatisInterceptor"> <property name="shardTableName" value="t_feed_back"/> </bean> </array> </property> </bean>
5.实现mybatisInterceptor
package net.zicp.xiaochangwei.web.interceptors; import java.lang.reflect.Method; import java.util.Date; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.zicp.xiaochangwei.web.multipeDataSource.DataSourceSwith; import net.zicp.xiaochangwei.web.utils.DateUtils; import org.apache.ibatis.cache.CacheKey; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.BoundSql; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.MappedStatement.Builder; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.plugin.Intercepts; import org.apache.ibatis.plugin.Invocation; import org.apache.ibatis.plugin.Plugin; import org.apache.ibatis.plugin.Signature; import org.apache.ibatis.reflection.DefaultReflectorFactory; import org.apache.ibatis.reflection.MetaObject; import org.apache.ibatis.reflection.ReflectorFactory; import org.apache.ibatis.reflection.factory.DefaultObjectFactory; import org.apache.ibatis.reflection.factory.ObjectFactory; import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory; import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; /** * @author 肖昌伟 E-mail:317409898@qq.com * @version 创建时间:2016年6月23日 上午9:04:47 * */ @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, CacheKey.class, BoundSql.class }), @Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }) }) public class MybatisInterceptor implements Interceptor, InitializingBean { @Override public Object intercept(Invocation invocation) throws Throwable { Method method = invocation.getMethod(); Object[] arguments = invocation.getArgs(); MappedStatement ms = (MappedStatement) arguments[MAPPED_STATEMENT_INDEX]; BoundSql boundSql = ms.getBoundSql(arguments[PARAMETER_INDEX]); log.info("对数据库执行:" + method.getName() + " 操作, sql为: "+ boundSql.getSql()); // 切换数据源 if ("query".equals(method.getName())) { DataSourceSwith.setDataSource(DataSourceSwith.QUERY); } else { DataSourceSwith.setDataSource(DataSourceSwith.UPDATE); }
配置两个不同的数据源试试看吧