Spring and druid can realize the functions of dynamic data source, library query, read-write separation and so on. Now let's talk about the configuration:
1. You need to configure multiple spring data sources
spring-data.xml
<!-- Dynamic data source --> <bean id="dynamicDataSource" class="com.myproject.common.db.util.DynamicDataSource"> <!-- Associate the data source by key-value--> <property name="targetDataSources"> <map> <entry value-ref="dataSourceWrite" key="dataSourceWrite"></entry> <entry value-ref="dataSourceRead" key="dataSourceRead"></entry> </map> </property> <property name="defaultTargetDataSource" ref="dataSourceWrite" /> </bean> <!--mybatis integration with Spring --> <bean id="sqlSessionFactory" name="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:mybatis.xml"></property> <property name="mapperLocations" value="classpath*:mapper/*.xml" /> <property name="dataSource" ref="dynamicDataSource" /> </bean> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory" /> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dynamicDataSource" /> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- DruidDataSource --> <bean id="dataSourceWrite" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${urlOracle}" /> <property name="username" value="${usernameOracle}" /> <property name="password" value="${passwordOracle}" /> <!-- Initialize connection size --> <property name="initialSize" value="5" /> <!-- The maximum number of connections used in the connection pool--> <property name="maxActive" value="200" /> <!-- Connection pool minimum idle--> <property name="minIdle" value="5" /> <!-- Get the maximum wait time for connection--> <property name="maxWait" value="60000" /> <!-- <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="33" /> --> <!-- <property name="validationQuery" value="${jdbc.validationQuery}" /> --> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="testWhileIdle" value="true" /> <!-- How long is the configuration interval to perform detection, and detect idle connections that need to be closed, in milliseconds--> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- Configure the minimum lifetime of a connection in the pool, in milliseconds--> <property name="minEvictableIdleTimeMillis" value="25200000" /> <!-- Open the removeAbandoned function--> <property name="removeAbandoned" value="true" /> <!-- 1800 seconds, or 30 minutes --> <property name="removeAbandonedTimeout" value="1800" /> <!-- Output the error log when closing the abandoned connection--> <property name="logAbandoned" value="true" /> <!-- Monitoring database --> <!-- <property name="filters" value="mergeStat" /> --> <property name="filters" value="stat" /> <property name="defaultAutoCommit" value="true" /> </bean> <bean id="dataSourceRead" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${urlMysql}" /> <property name="username" value="${usernameMysql}" /> <property name="password" value="${passwordMysql}" /> <!-- Initialize connection size --> <property name="initialSize" value="5" /> <!-- The maximum number of connections used in the connection pool--> <property name="maxActive" value="200" /> <!-- Connection pool minimum idle--> <property name="minIdle" value="5" /> <!-- Get the maximum wait time for connection--> <property name="maxWait" value="60000" /> <!-- <property name="poolPreparedStatements" value="true" /> <property name="maxPoolPreparedStatementPerConnectionSize" value="33" /> --> <!-- <property name="validationQuery" value="${jdbc.validationQuery}" /> --> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="testWhileIdle" value="true" /> <!-- How long is the configuration interval to perform detection, and detect idle connections that need to be closed, in milliseconds--> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- Configure the minimum lifetime of a connection in the pool, in milliseconds--> <property name="minEvictableIdleTimeMillis" value="25200000" /> <!-- Open the removeAbandoned function--> <property name="removeAbandoned" value="true" /> <!-- 1800 seconds, or 30 minutes --> <property name="removeAbandonedTimeout" value="1800" /> <!-- Output the error log when closing the abandoned connection--> <property name="logAbandoned" value="true" /> <!-- Monitoring database --> <!-- <property name="filters" value="mergeStat" /> --> <property name="filters" value="stat" /> <property name="defaultAutoCommit" value="true" /> </bean>
2. You need to write a DynamicDataSource class to inherit AbstractRoutingDataSource and implement the determineCurrentLookupKey method
public class DynamicDataSource extends AbstractRoutingDataSource { /** * * override determineCurrentLookupKey * <p> * Title: determineCurrentLookupKey * </p> * <p> * Description: Automatically find datasource * </p> * * @return */ @Override protected Object determineCurrentLookupKey() { return DBContextHolder.getDSType(); } }
3. Referring to spring transaction management, use thread variables to switch data sources
public class DBContextHolder { /** * thread threadlocal */ private static ThreadLocal<String> contextHolder = new ThreadLocal<>(); private static Logger logger = LoggerFactory .getLogger(DBContextHolder.class); public static String getDSType() { try { } catch (Exception e) { e.printStackTrace (); logger.error("get DBTYPE faild with error:[" + e.getMessage() + "]"); } String db = contextHolder.get(); if (db == null) { db =UrlConnect.getKey(ConfigHelper.getToWriteKey());// The default is the read and write library } return db; } /** * * Set the dbtype of this thread * * @param str * @see [related class/method] (optional) * @since [product/module version] (optional) */ public static boolean setDSType(String str) { try { clearDBType(); if (str != null&&!str.equals("")) { contextHolder.set(str); logger.info("change thread[" + str + "] success!"); return true; } else { logger.info("change thread[" + str + "] faild!"); return false; } } catch (Exception e) { e.printStackTrace (); logger.error("change thread[" + str + "] faild!"); return false; } } /** * clearDBType * * @Title: clearDBType * @Description: clean up the connection type */ public static void clearDSType() { contextHolder.remove(); } }
4. Switch data sources in dao
@Repository public class BaseDAO extends SqlSessionDaoSupport { @Resource private SqlSessionTemplate sqlSessionTemplate; @Resource public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) { super.setSqlSessionTemplate(sqlSessionTemplate); } public <T> PageList<T> selectPublicListPage(String countSqlID,String sqlID, PageList<T> page, Object obj) { DBContextHolder.setDbType("dataSourceRead"); // total number of queries Integer total = this.getSqlSession().selectOne(countSqlID, obj); RowBounds rowBounds=new RowBounds(page.getFirstResult(),page.getPageSize()); // Query list information List<T> list = this.getSqlSession().selectList( sqlID, obj,rowBounds); page.setTotalRecord(total!=null?total:0); page.setDataSource(list); page.setTotalPage((total + page.getPageSize() - 1) / page.getPageSize()); return page; } public int insert(String sqlID, Object paramObj) { DBContextHolder.setDbType("dataSourceWrite"); return this.getSqlSession().insert(sqlID, paramObj); } }