javascript
Spring集成Mybatis多数据源配置
既然在整理Mybatis那就把經(jīng)常用的這個(gè)多數(shù)據(jù)源的筆記也整一下吧。
Spring集成Mybatis在之前就已經(jīng)提到了。Spring集成Mybatis
集成Mybatis多數(shù)據(jù)源有兩種方式:
1、創(chuàng)建多個(gè)SqlSessionFactory,掃描每個(gè)SqlSessionFactoryBean對(duì)應(yīng)的包,形成了每個(gè)Factory對(duì)應(yīng)一個(gè)數(shù)據(jù)源。
2、創(chuàng)建一個(gè)SqlSessionFactory,通過動(dòng)態(tài)切換數(shù)據(jù)源對(duì)象,達(dá)到多數(shù)據(jù)源操作功能。
第一種方式
通過在Spring的配置文件中配置多個(gè)SqlSessionFactoryBean對(duì)象,每個(gè)對(duì)應(yīng)不同的MapperScannerConfigurer,每個(gè)MapperScannerConfigurer掃描不同的包路徑接口;
另外一個(gè)數(shù)據(jù)源也如上配置,只需替換對(duì)應(yīng)的掃描包即可,這樣調(diào)用指定包下的接口就能訪問指定的數(shù)據(jù)庫了。
第二種方式
創(chuàng)建單個(gè)SqlSessionFactory,指定默認(rèn)數(shù)據(jù)源,后期查詢不同的數(shù)據(jù)庫切換SqlSessionFactory中數(shù)據(jù)源,如果訪問次數(shù)過多,頻繁切換的話,就會(huì)導(dǎo)致一個(gè)并發(fā)問題。
解決這個(gè)問題就應(yīng)該使用并發(fā)中一些機(jī)制:如果使用鎖機(jī)制的話,那么查詢的效率就會(huì)降低,同時(shí)只有當(dāng)線程去執(zhí)行;采用ThreadLocal的話就能解決這個(gè)效率以及線程安全的問題了。
由于需切換數(shù)據(jù)源,所以在創(chuàng)建SqlSessionFactory時(shí)需要有幾個(gè)注意的點(diǎn):
1、設(shè)置數(shù)據(jù)源對(duì)象應(yīng)該為一個(gè)支持切換的一個(gè)DataSource對(duì)象,我們先定義為RouteDataSource對(duì)象,由于是DataSource所以這個(gè)RouteDataSource就必須實(shí)現(xiàn)DataSource接口,但是又不能侵入原本數(shù)據(jù)庫鏈接池的對(duì)象,所以這個(gè)采用裝飾器模式進(jìn)行裝飾這個(gè)類;
2、支持動(dòng)態(tài)切換,即需要一個(gè)暴露的靜態(tài)方法進(jìn)行切換,由于數(shù)據(jù)源對(duì)象都在這個(gè)Spring容器當(dāng)中,所以這個(gè)類需拿到Spring的容器使用權(quán)(實(shí)現(xiàn)ApplicationContextAware接口);
3、需指定切換那個(gè)數(shù)據(jù)源,可以采用ENUM枚舉進(jìn)行指定,也可以通過String,都可以。
創(chuàng)建一個(gè)枚舉類:
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ìn)行數(shù)據(jù)源增強(qiáng)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);即可切換成對(duì)應(yīng)的數(shù)據(jù)源進(jìn)行查詢啦。
上面是一個(gè)自定義的數(shù)據(jù)源路由類,后來才發(fā)現(xiàn)在Spring的jdbc包下有個(gè)支持?jǐn)?shù)據(jù)源切換的動(dòng)態(tài)數(shù)據(jù)源類AbstractRoutingDataSource。
如果使用這個(gè)類做數(shù)據(jù)源切換,也是可以的,實(shí)現(xiàn)的思想以及模式都和自定義的那個(gè)是一致的;
示例:
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);}}這個(gè)類還是挺好用的
總結(jié)
以上是生活随笔為你收集整理的Spring集成Mybatis多数据源配置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 16.char类型
- 下一篇: SpringMvc异步请求的使用及部分原