FlyHeLanMan 通过本文主要向大家介绍了spring mybatis实例,spring mybatis,spring mybatis整合,spring mybatis配置,spring mybatis事务等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com
项目背景:项目开发中数据库使用了读写分离,所有查询语句走从库,除此之外走主库。
最简单的办法其实就是建两个包,把之前数据源那一套配置copy一份,指向另外的包,但是这样扩展很有限,所有采用下面的办法。
参考了两篇文章如下:
http://www.weikejianghu.com/article/111840.htm
http://www.weikejianghu.com/article/111842.htm
这两篇文章都对原理进行了分析,下面只写自己的实现过程其他不再叙述。
实现思路是:
第一步,实现动态切换数据源:配置两个DataSource,配置两个SqlSessionFactory指向两个不同的DataSource,两个SqlSessionFactory都用一个SqlSessionTemplate,同时重写Mybatis提供的SqlSessionTemplate类,最后配置Mybatis自动扫描。
第二步,利用aop切面,拦截dao层所有方法,因为dao层方法命名的特点,比如所有查询sql都是select开头,或者get开头等等,拦截这些方法,并把当前数据源切换至从库。
spring中配置如下:
主库数据源配置:
<bean id="masterDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">2 <property name="driverClass" value="${master_mysql_jdbc_driver}" /> <property name="jdbcUrl" value="${master_mysql_jdbc_url}" /> <property name="user" value="${master_mysql_jdbc_user}" /> <property name="password" value="${master_mysql_jdbc_password}" /> </bean></div>
从库数据源配置:
<bean id="masterDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${slave_mysql_jdbc_driver}" /> <property name="jdbcUrl" value="${slave_mysql_jdbc_url}" /> <property name="user" value="${slave_mysql_jdbc_user}" /> <property name="password" value="${slave_mysql_jdbc_password}" /> </bean></div>
主库SqlSessionFactory配置:
<bean id="masterSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="masterDataSource" /> <property name="mapperLocations" value="classpath:com/sincetimes/slg/dao/*.xml"/> </bean></div>
从库SqlSessionFactory配置:
<bean id="slaveSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="slaveDataSource" /> <property name="mapperLocations" value="classpath:com/sincetimes/slg/dao/*.xml"/> </bean></div>
两个SqlSessionFactory使用同一个SqlSessionTemplate配置:
<bean id="MasterAndSlaveSqlSessionTemplate" class="com.sincetimes.slg.framework.core.DynamicSqlSessionTemplate"> <constructor-arg index="0" ref="masterSqlSessionFactory" /> <property name="targetSqlSessionFactorys"> <map> <entry value-ref="masterSqlSessionFactory" key="master"/> <entry value-ref="slaveSqlSessionFactory" key="slave"/> </map> </property> </bean></div>
配置Mybatis自动扫描dao
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.sincetimes.slg.dao" /> <property name="sqlSessionTemplateBeanName" value="MasterAndSlaveSqlSessionTemplate" /> </bean></div>
自己重写了SqlSessionTemplate代码如下:
package com.sincetimes.slg.framework.core; import static java.lang.reflect.Proxy.newProxyInstance; import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable; import static org.mybatis.spring.SqlSessionUtils.closeSqlSession; import static org.mybatis.spring.SqlSessionUtils.getSqlSession; import static org.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.sql.Connection; import java.util.List; import java.util.Map; import org.apache.ibatis.exceptions.PersistenceException; import org.apache.ibatis.executor.BatchResult; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.ResultHandler; import org.apache.ibatis.session.RowBounds; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.MyBatisExceptionTranslator; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.util.Assert; import com.sincetimes.slg.framework.util.SqlSessionContentHolder; /** * * TODO 重写SqlSessionTemplate * @author ccg * @version 1.0 * Created 2017年4月21日 下午3:15:15 */ public class DynamicSqlSessionTemplate extends SqlSessionTemplate { private final SqlSessionFactory sqlSessionFactory; private final ExecutorType executorType; private final SqlSession sqlSessionProxy; private final PersistenceExceptionTranslator exceptionTranslator; private Map<Object, SqlSessionFactory> targetSqlSessionFactorys; private SqlSessionFactory defaultTargetSqlSessionFactory; public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) { this.targetSqlSessionFactorys = targetSqlSessionFactorys; } public Map<Object, SqlSessionFactory> getTargetSqlSessionFactorys(){ return targetSqlSessionFactorys; } public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) { this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory; } public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); } public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration() .getEnvironment().getDataSource(), true)); } public DynamicSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { super(sqlSessionFactory, executorType, exceptionTranslator); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession) newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor()); this.defaultTargetSqlSessionFactory = sqlSessionFactory; } @Override public SqlSessionFactory getSqlSessionFactory() { SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(SqlSessionContentHolder.getContextType()); if (targetSqlSessionFactory != null) { return targetSqlSessionFactory; } else if (defaultTargetSqlSessionFactory != null) { return defaultTargetSqlSessionFactory; } else { Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required"); Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required"); } return this.sqlSessionFactory; } @Override public Configuration getConfiguration() { return this.getSqlSessionFactory().getConfiguration(); } public ExecutorType getExecutorType() { retur