javascript
Spring集成Mybatis多数据源配置
既然在整理Mybatis那就把經(jīng)常用的這個多數(shù)據(jù)源的筆記也整一下吧。
Spring集成Mybatis在之前就已經(jīng)提到了。Spring集成Mybatis
集成Mybatis多數(shù)據(jù)源有兩種方式:
1、創(chuàng)建多個SqlSessionFactory,掃描每個SqlSessionFactoryBean對應(yīng)的包,形成了每個Factory對應(yīng)一個數(shù)據(jù)源。
2、創(chuàng)建一個SqlSessionFactory,通過動態(tài)切換數(shù)據(jù)源對象,達到多數(shù)據(jù)源操作功能。
第一種方式
通過在Spring的配置文件中配置多個SqlSessionFactoryBean對象,每個對應(yīng)不同的MapperScannerConfigurer,每個MapperScannerConfigurer掃描不同的包路徑接口;
另外一個數(shù)據(jù)源也如上配置,只需替換對應(yīng)的掃描包即可,這樣調(diào)用指定包下的接口就能訪問指定的數(shù)據(jù)庫了。
第二種方式
創(chuàng)建單個SqlSessionFactory,指定默認(rèn)數(shù)據(jù)源,后期查詢不同的數(shù)據(jù)庫切換SqlSessionFactory中數(shù)據(jù)源,如果訪問次數(shù)過多,頻繁切換的話,就會導(dǎo)致一個并發(fā)問題。
解決這個問題就應(yīng)該使用并發(fā)中一些機制:如果使用鎖機制的話,那么查詢的效率就會降低,同時只有當(dāng)線程去執(zhí)行;采用ThreadLocal的話就能解決這個效率以及線程安全的問題了。
由于需切換數(shù)據(jù)源,所以在創(chuàng)建SqlSessionFactory時需要有幾個注意的點:
1、設(shè)置數(shù)據(jù)源對象應(yīng)該為一個支持切換的一個DataSource對象,我們先定義為RouteDataSource對象,由于是DataSource所以這個RouteDataSource就必須實現(xiàn)DataSource接口,但是又不能侵入原本數(shù)據(jù)庫鏈接池的對象,所以這個采用裝飾器模式進行裝飾這個類;
2、支持動態(tài)切換,即需要一個暴露的靜態(tài)方法進行切換,由于數(shù)據(jù)源對象都在這個Spring容器當(dāng)中,所以這個類需拿到Spring的容器使用權(quán)(實現(xiàn)ApplicationContextAware接口);
3、需指定切換那個數(shù)據(jù)源,可以采用ENUM枚舉進行指定,也可以通過String,都可以。
創(chuàng)建一個枚舉類:
public enum DataSourceEnum {DATASOURCE1(null),DATASOURCE2(null);DataSource dataSource;private DataSourceEnum(DataSource dataSource) {this.dataSource = dataSource;}public DataSource getValue() {return dataSource;}public DataSourceEnum setDataSource(DataSource dataSource) {this.dataSource = dataSource;return this;}}RouteDataSource類如下:
@Component("routeDataSource") public class RouteDataSource implements DataSource,InitializingBean,ApplicationContextAware {private static final Map<DataSourceEnum,DataSource> targetDataSources = new HashMap<DataSourceEnum,DataSource>(2); //避免并發(fā)問題ThreadLocal<DataSource> targetDataSource = new ThreadLocal<DataSource>();//裝時器模式進行數(shù)據(jù)源增強private static RouteDataSource route = null;public void setDataSource(DataSource targetDataSource) {this.targetDataSource.set(targetDataSource);}@Overridepublic PrintWriter getLogWriter() throws SQLException {return targetDataSource.get().getLogWriter();}@Overridepublic void setLogWriter(PrintWriter out) throws SQLException {targetDataSource.get().setLogWriter(out);}@Overridepublic void setLoginTimeout(int seconds) throws SQLException {targetDataSource.get().setLoginTimeout(seconds);}@Overridepublic int getLoginTimeout() throws SQLException {return targetDataSource.get().getLoginTimeout();}@Overridepublic Logger getParentLogger() throws SQLFeatureNotSupportedException {return targetDataSource.get().getParentLogger();}@Overridepublic <T> T unwrap(Class<T> iface) throws SQLException {return targetDataSource.get().unwrap(iface);}@Overridepublic boolean isWrapperFor(Class<?> iface) throws SQLException {return targetDataSource.get().isWrapperFor(iface);}@Overridepublic Connection getConnection() throws SQLException {return targetDataSource.get().getConnection();}@Overridepublic Connection getConnection(String username, String password) throws SQLException {return targetDataSource.get().getConnection(username, password);}//初始化枚舉數(shù)據(jù),已經(jīng)默認(rèn)數(shù)據(jù)源@Overridepublic void afterPropertiesSet() throws Exception {targetDataSources.put(DataSourceEnum.DATASOURCE1.setDataSource((DataSource) applicationContext.getBean("dataSource")), (DataSource) applicationContext.getBean("dataSource"));targetDataSources.put(DataSourceEnum.DATASOURCE2.setDataSource((DataSource) applicationContext.getBean("dataSource1")), (DataSource) applicationContext.getBean("dataSource1"));targetDataSource.set(targetDataSources.get(DataSourceEnum.DATASOURCE1));route = (RouteDataSource) applicationContext.getBean("routeDataSource");}private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}/*** @description 更改數(shù)據(jù)源方法* @param enumDataSource*/public static void setDataSource(DataSourceEnum enumDataSource) {route.setDataSource(targetDataSources.get(enumDataSource));}}所以在調(diào)用Mybatis的接口之前,調(diào)用RouteDataSource.setDataSource(DataSourceEnum.DATASOURCE);即可切換成對應(yīng)的數(shù)據(jù)源進行查詢啦。
上面是一個自定義的數(shù)據(jù)源路由類,后來才發(fā)現(xiàn)在Spring的jdbc包下有個支持?jǐn)?shù)據(jù)源切換的動態(tài)數(shù)據(jù)源類AbstractRoutingDataSource。
如果使用這個類做數(shù)據(jù)源切換,也是可以的,實現(xiàn)的思想以及模式都和自定義的那個是一致的;
示例:
public class ThreadLocalRountingDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {// TODO Auto-generated method stub//在這里做數(shù)據(jù)源切換return DataSourceTypeManager.get();}} //管理數(shù)據(jù)源類 public class DataSourceTypeManager {//數(shù)據(jù)源保存private static final ThreadLocal<MybatisDataSource> dataSourceTypes = new ThreadLocal<MybatisDataSource>() {@Overrideprotected MybatisDataSource initialValue() {return MybatisDataSource.JKDSJ;}};public static MybatisDataSource get() {return dataSourceTypes.get();}public static void set(MybatisDataSource dataSourceType) {dataSourceTypes.set(dataSourceType);}public static void reset() {dataSourceTypes.set(MybatisDataSource.JKDSJ);}}這個類還是挺好用的
總結(jié)
以上是生活随笔為你收集整理的Spring集成Mybatis多数据源配置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 16.char类型
- 下一篇: 一年Java经验应该会些什么
