Dynamic database and read-write separation based on druid and spring

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);
	}


}

 

 

 

 

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326555880&siteId=291194637