91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

關于Spring3 + Mybatis3整合時多數據源動態切換的問題

發布時間:2020-10-18 13:32:39 來源:腳本之家 閱讀:175 作者:兔子黨-大胡子 欄目:編程語言

以前的項目經歷中,基本上都是spring + hibernate + Spring JDBC這種組合用的多。至于MyBatis,也就這個項目才開始試用,閑話不多說,進入正題。

以前的這種框架組合中,動態數據源切換可謂已經非常成熟了,網上也有非常多的博客介紹,都是繼承AbstractRoutingDataSource,重寫determineCurrentLookupKey()方法。具體做法就不在此廢話了。

所以當項目中碰到這個問題,我幾乎想都沒有想,就采用了這種做法,但是一測試,一點反應都沒有。當時覺得不可能,于是斷點,加log調試,發現determineCurrentLookupKey()根本沒有調用。 

為什么列? 這不可能啊。靜下心來,仔細想想,才想到一個關鍵的問題: Mybatis整合Spring,而不是Spring整合的Mybatis! 直覺告訴我,問題就出在這里。

于是花時間去研究一下mybatis-spring.jar 這個包,發現有SqlSession這東西,很本能的就注意到了這一塊,然后大致看一下他的一些實現類。于是就發現了他的實現類里面有一個內部類SqlSessionInterceptor(研究過程就不多說了,畢竟是個痛苦的過程)

好吧,這個類的作用列,就是產生sessionProxy。關鍵代碼如下

final SqlSession sqlSession = getSqlSession( 
 SqlSessionTemplate.this.sqlSessionFactory, 
 SqlSessionTemplate.this.executorType, 
 SqlSessionTemplate.this.exceptionTranslator); 

這個sqlSessionFactory 我們就很眼熟啦,是我們在spring配置文件中配了的,是吧,也就是說這東西是直接從我們配置文件中讀進來,但這東西,就關聯了Datasource。所以就想到,如果能把這東西,做到動態,那么數據源切換,也就動態了。

于是第一反應就是寫了一個類,然后在里面定義一個Map,用來存放多個SqlSessionFactory,并采用Setter方法進行屬性注入。

public class EjsSqlSessionTemplate extends SqlSessionTemplate { 
 
 private Map<String, SqlSessionFactory> targetSqlSessionFactory = new HashMap<String, SqlSessionFactory>(); 
 public void setTargetSqlSessionFactory(Map<String, SqlSessionFactory> targetSqlSessionFactory) { 
  this.targetSqlSessionFactory = targetSqlSessionFactory; 
 } 

所以Spring的配置文件就變成了這樣:

<bean id="sqlSessionTemplate" class="com.ejushang.spider.datasource.EjsSqlSessionTemplate"> 
  <constructor-arg ref="sqlSessionFactory" /> 
  <property name="targetSqlSessionFactory"> 
   <map> 
    <entry value-ref="sqlSessionFactory" key="spider"/> 
    <entry value-ref="sqlSessionFactoryTb" key="sysinfo"/> 
   </map> 
  </property> 
 </bean> 
 <bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
  <property name="basePackage" value="com.foo.bar.**.mapper*" /> 
  <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/> 
 </bean> 

那么這個思想是那里來的列? 當然就是借鑒了Spring的動態數據源的思想啦,對比一下Spring動態數據源的配置,看看是不是差不多?

然后重寫了個關鍵的方法:

/** 
  * 重寫得到SqlSessionFactory的方法 
  * @return 
  */ 
 @Override 
 public SqlSessionFactory getSqlSessionFactory() { 
 
  SqlSessionFactory targetSqlSessionFactory = this.targetSqlSessionFactory.get(SqlSessionContextHolder.getDataSourceKey()); 
  if (targetSqlSessionFactory != null) { 
   return targetSqlSessionFactory; 
  } else if ( this.getSqlSessionFactory() != null) { 
   return this.getSqlSessionFactory(); 
  } 
  throw new IllegalArgumentException("sqlSessionFactory or targetSqlSessionFactory must set one at least"); 
 } 

而SqlSessionContextHolder就很簡單,就是一個ThreadLocal的思想

public class SqlSessionContextHolder { 
 private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); 
 private static Logger logger = LoggerFactory.getLogger(SqlSessionContextHolder.class); 
 public static void setSessionFactoryKey(String dataSourceKey) { 
  contextHolder.set(dataSourceKey); 
 } 
 public static String getDataSourceKey() { 
  String key = contextHolder.get(); 
  logger.info("當前線程Thread:"+Thread.currentThread().getName()+" 當前的數據源 key is "+ key); 
  return key; 
 } 
} 

博主信心滿滿就開始測試了。。結果發現不行,切換不過來,始終都是綁定的是構造函數中的那個默認的sqlSessionFactory,當時因為看了一天源碼,頭也有點暈。其實為什么列?

看看我們產生sessionProxy的地方代碼,他的sqlSessionFactory是直接從構造函數來拿的。而構造函數中的sqlSessionFactory在spring容器啟動時,就已經初始化好了,這點也可以從我們Spring配置文件中得到證實。

那這個問題,怎么解決列? 于是博主便想重寫那個sqlSessionInterceptor。 擦,問題就來了,這個類是private的,沒辦法重寫啊。于是博主又只能在自己的EjsSqlSessionTemplate類中,也定義了一個內部類,把源碼中的代碼都copy過來,唯一不同的就是我不是讀取構造函數中的sqlSessionFactory.而是每次都去調用 getSqlSessionFactory()方法。代碼如下:

final SqlSession sqlSession = getSqlSession(    
EjsSqlSessionTemplate.this.getSqlSessionFactory(),    
EjsSqlSessionTemplate.this.getExecutorType(),     
EjsSqlSessionTemplate.this.getPersistenceExceptionTranslator()); 

再試,發現還是不行,再找原因,又回歸到了剛才那個問題。因為我沒有重寫SqlSessionTemplate的構造函數,而sqlSessionProxy是在構函數中初始化的,代碼如下:

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, 
 PersistenceExceptionTranslator exceptionTranslator) { 
 notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required"); 
 notNull(executorType, "Property 'executorType' is required"); 
 this.sqlSessionFactory = sqlSessionFactory; 
 this.executorType = executorType; 
 this.exceptionTranslator = exceptionTranslator; 
 this.sqlSessionProxy = (SqlSession) newProxyInstance( 
  SqlSessionFactory.class.getClassLoader(), 
  new Class[] { SqlSession.class }, 
  new SqlSessionInterceptor()); 
} 

而SqlSessionInterceptor()這東西都是private。 所以父類壓根就不會加載我寫的那個SqlSessionInterceptor()。所以問題就出在這,那好吧,博主又重寫構函數

public EjsSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { 
  super(getSqlSessionFactory(), executorType, exceptionTranslator); 
 } 

很明顯這段代碼是編譯不通過的,構造函數中,怎么可能調用類實例方法列?  那怎么辦列? 又只有把父類的構造函數copy過來,那問題又有了,這些成員屬性又沒有。那又只得把他們也搬過來。。  后來,這個動態數據數據源的功能,終于完成了。

--------------------------------------------------------------------------------------------------------------------分割線-----------------------------------------------------------------------------------------------------------整個完整的代碼如下:

1、重寫SqlSessionTemplate (重寫的過程已經在上面分析過了)

public class EjsSqlSessionTemplate extends SqlSessionTemplate { 
 private final SqlSessionFactory sqlSessionFactory; 
 private final ExecutorType executorType; 
 private final SqlSession sqlSessionProxy; 
 private final PersistenceExceptionTranslator exceptionTranslator; 
 private Map<Object, SqlSessionFactory> targetSqlSessionFactory; 
 public void setTargetSqlSessionFactory(Map<Object, SqlSessionFactory> targetSqlSessionFactory) { 
  this.targetSqlSessionFactory = targetSqlSessionFactory; 
 } 
 public EjsSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { 
  this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType()); 
 } 
 public EjsSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) { 
  this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration() 
    .getEnvironment().getDataSource(), true)); 
 } 
 public EjsSqlSessionTemplate(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()); 
 } 
 @Override 
 public SqlSessionFactory getSqlSessionFactory() { 
  SqlSessionFactory targetSqlSessionFactory = this.targetSqlSessionFactory.get(SqlSessionContextHolder.getDataSourceKey()); 
  if (targetSqlSessionFactory != null) { 
   return targetSqlSessionFactory; 
  } else if ( this.sqlSessionFactory != null) { 
   return this.sqlSessionFactory; 
  } 
  throw new IllegalArgumentException("sqlSessionFactory or targetSqlSessionFactory must set one at least"); 
 } 
 @Override 
 public Configuration getConfiguration() { 
  return this.getSqlSessionFactory().getConfiguration(); 
 } 
 public ExecutorType getExecutorType() { 
  return this.executorType; 
 } 
 public PersistenceExceptionTranslator getPersistenceExceptionTranslator() { 
  return this.exceptionTranslator; 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <T> T selectOne(String statement) { 
  return this.sqlSessionProxy.<T> selectOne(statement); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <T> T selectOne(String statement, Object parameter) { 
  return this.sqlSessionProxy.<T> selectOne(statement, parameter); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <K, V> Map<K, V> selectMap(String statement, String mapKey) { 
  return this.sqlSessionProxy.<K, V> selectMap(statement, mapKey); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) { 
  return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) { 
  return this.sqlSessionProxy.<K, V> selectMap(statement, parameter, mapKey, rowBounds); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <E> List<E> selectList(String statement) { 
  return this.sqlSessionProxy.<E> selectList(statement); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <E> List<E> selectList(String statement, Object parameter) { 
  return this.sqlSessionProxy.<E> selectList(statement, parameter); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { 
  return this.sqlSessionProxy.<E> selectList(statement, parameter, rowBounds); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void select(String statement, ResultHandler handler) { 
  this.sqlSessionProxy.select(statement, handler); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void select(String statement, Object parameter, ResultHandler handler) { 
  this.sqlSessionProxy.select(statement, parameter, handler); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { 
  this.sqlSessionProxy.select(statement, parameter, rowBounds, handler); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public int insert(String statement) { 
  return this.sqlSessionProxy.insert(statement); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public int insert(String statement, Object parameter) { 
  return this.sqlSessionProxy.insert(statement, parameter); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public int update(String statement) { 
  return this.sqlSessionProxy.update(statement); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public int update(String statement, Object parameter) { 
  return this.sqlSessionProxy.update(statement, parameter); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public int delete(String statement) { 
  return this.sqlSessionProxy.delete(statement); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public int delete(String statement, Object parameter) { 
  return this.sqlSessionProxy.delete(statement, parameter); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public <T> T getMapper(Class<T> type) { 
  return getConfiguration().getMapper(type, this); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void commit() { 
  throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void commit(boolean force) { 
  throw new UnsupportedOperationException("Manual commit is not allowed over a Spring managed SqlSession"); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void rollback() { 
  throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void rollback(boolean force) { 
  throw new UnsupportedOperationException("Manual rollback is not allowed over a Spring managed SqlSession"); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void close() { 
  throw new UnsupportedOperationException("Manual close is not allowed over a Spring managed SqlSession"); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public void clearCache() { 
  this.sqlSessionProxy.clearCache(); 
 } 
 /** 
  * {@inheritDoc} 
  */ 
 public Connection getConnection() { 
  return this.sqlSessionProxy.getConnection(); 
 } 
 /** 
  * {@inheritDoc} 
  * @since 1.0.2 
  */ 
 public List<BatchResult> flushStatements() { 
  return this.sqlSessionProxy.flushStatements(); 
 } 
 /** 
  * Proxy needed to route MyBatis method calls to the proper SqlSession got from Spring's Transaction Manager It also 
  * unwraps exceptions thrown by {@code Method#invoke(Object, Object...)} to pass a {@code PersistenceException} to 
  * the {@code PersistenceExceptionTranslator}. 
  */ 
 private class SqlSessionInterceptor implements InvocationHandler { 
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
   final SqlSession sqlSession = getSqlSession( 
     EjsSqlSessionTemplate.this.getSqlSessionFactory(), 
     EjsSqlSessionTemplate.this.executorType, 
     EjsSqlSessionTemplate.this.exceptionTranslator); 
   try { 
    Object result = method.invoke(sqlSession, args); 
    if (!isSqlSessionTransactional(sqlSession, EjsSqlSessionTemplate.this.getSqlSessionFactory())) { 
     // force commit even on non-dirty sessions because some databases require 
     // a commit/rollback before calling close() 
     sqlSession.commit(true); 
    } 
    return result; 
   } catch (Throwable t) { 
    Throwable unwrapped = unwrapThrowable(t); 
    if (EjsSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) { 
     Throwable translated = EjsSqlSessionTemplate.this.exceptionTranslator 
       .translateExceptionIfPossible((PersistenceException) unwrapped); 
     if (translated != null) { 
      unwrapped = translated; 
     } 
    } 
    throw unwrapped; 
   } finally { 
    closeSqlSession(sqlSession, EjsSqlSessionTemplate.this.getSqlSessionFactory()); 
   } 
  } 
 } 
} 

2。自定義了一個注解

/** 
 * 注解式數據源,用來進行數據源切換 
 * User:Amos.zhou 
 * Date: 14-2-27 
 * Time: 下午2:34 
 */ 
@Target({ElementType.METHOD, ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
public @interface ChooseDataSource { 
 String value() default ""; 
} 

3.定義一個AspectJ的切面(我習慣用AspectJ,因為spring AOP不支持cflow()這些語法),所以在編譯,打包的時候一定要用aspectJ的編譯器,不能直接用原生的JDK。有些方法就是我基于以前Hibernate,JDBC動態數據源的時候改動的。

/** 
 * <li>類描述:完成數據源的切換,抽類切面,具體項目繼承一下,不需要重寫即可使用</li> 
 * 
 * @author: amos.zhou 
 * 2013-8-1 上午11:51:40 
 * @since v1.0 
 */ 
@Aspect 
public abstract class ChooseDataSourceAspect { 
 protected static final ThreadLocal<String> preDatasourceHolder = new ThreadLocal<String>(); 
 @Pointcut("execution(public * *.*(..))") 
 public void allMethodPoint() { 
 } 
 @Pointcut("@within(com.ejushang.spider.annotation.ChooseDataSource) && allMethodPoint()") 
 public void allServiceMethod() { 
 } 
 /** 
  * 對所有注解有ChooseDataSource的類進行攔截 
  */ 
 @Pointcut("cflow(allServiceMethod()) && allServiceMethod()") 
 public void changeDatasourcePoint() { 
 } 
 /** 
  * 根據@ChooseDataSource的屬性值設置不同的dataSourceKey,以供DynamicDataSource 
  */ 
 @Before("changeDatasourcePoint()") 
 public void changeDataSourceBeforeMethodExecution(JoinPoint jp) { 
  //拿到anotation中配置的數據源 
  String resultDS = determineDatasource(jp); 
  //沒有配置實用默認數據源 
  if (resultDS == null) { 
   SqlSessionContextHolder.setSessionFactoryKey(null); 
   return; 
  } 
  preDatasourceHolder.set(SqlSessionContextHolder.getDataSourceKey()); 
  //將數據源設置到數據源持有者 
  SqlSessionContextHolder.setSessionFactoryKey(resultDS); 
 } 
 /** 
  * <p>創建時間: 2013-8-20 上午9:48:44</p> 
  * 如果需要修改獲取數據源的邏輯,請重寫此方法 
  * 
  * @param jp 
  * @return 
  */ 
 @SuppressWarnings("rawtypes") 
 protected String determineDatasource(JoinPoint jp) { 
  String methodName = jp.getSignature().getName(); 
  Class targetClass = jp.getSignature().getDeclaringType(); 
  String dataSourceForTargetClass = resolveDataSourceFromClass(targetClass); 
  String dataSourceForTargetMethod = resolveDataSourceFromMethod( 
    targetClass, methodName); 
  String resultDS = determinateDataSource(dataSourceForTargetClass, 
    dataSourceForTargetMethod); 
  return resultDS; 
 } 
 /** 
  * 方法執行完畢以后,數據源切換回之前的數據源。 
  * 比如foo()方法里面調用bar(),但是bar()另外一個數據源, 
  * bar()執行時,切換到自己數據源,執行完以后,要切換到foo()所需要的數據源,以供 
  * foo()繼續執行。 
  * <p>創建時間: 2013-8-16 下午4:27:06</p> 
  */ 
 @After("changeDatasourcePoint()") 
 public void restoreDataSourceAfterMethodExecution() { 
  SqlSessionContextHolder.setSessionFactoryKey(preDatasourceHolder.get()); 
  preDatasourceHolder.remove(); 
 } 
 /** 
  * <li>創建時間: 2013-6-17 下午5:34:13</li> <li>創建人:amos.zhou</li> <li>方法描述 :</li> 
  * 
  * @param targetClass 
  * @param methodName 
  * @return 
  */ 
 @SuppressWarnings("rawtypes") 
 private String resolveDataSourceFromMethod(Class targetClass, 
            String methodName) { 
  Method m = ReflectUtil.findUniqueMethod(targetClass, methodName); 
  if (m != null) { 
   ChooseDataSource choDs = m.getAnnotation(ChooseDataSource.class); 
   return resolveDataSourcename(choDs); 
  } 
  return null; 
 } 
 /** 
  * <li>創建時間: 2013-6-17 下午5:06:02</li> 
  * <li>創建人:amos.zhou</li> 
  * <li>方法描述 : 確定 
  * 最終數據源,如果方法上設置有數據源,則以方法上的為準,如果方法上沒有設置,則以類上的為準,如果類上沒有設置,則使用默認數據源</li> 
  * 
  * @param classDS 
  * @param methodDS 
  * @return 
  */ 
 private String determinateDataSource(String classDS, String methodDS) { 
//  if (null == classDS && null == methodDS) { 
//   return null; 
//  } 
  // 兩者必有一個不為null,如果兩者都為Null,也會返回Null 
  return methodDS == null ? classDS : methodDS; 
 } 
 /** 
  * <li>創建時間: 2013-6-17 下午4:33:03</li> <li>創建人:amos.zhou</li> <li>方法描述 : 類級別的 @ChooseDataSource 
  * 的解析</li> 
  * 
  * @param targetClass 
  * @return 
  */ 
 @SuppressWarnings({"unchecked", "rawtypes"}) 
 private String resolveDataSourceFromClass(Class targetClass) { 
  ChooseDataSource classAnnotation = (ChooseDataSource) targetClass 
    .getAnnotation(ChooseDataSource.class); 
  // 直接為整個類進行設置 
  return null != classAnnotation ? resolveDataSourcename(classAnnotation) 
    : null; 
 } 
 /** 
  * <li>創建時間: 2013-6-17 下午4:31:42</li> <li>創建人:amos.zhou</li> <li>方法描述 : 
  * 組裝DataSource的名字</li> 
  * 
  * @param ds 
  * @return 
  */ 
 private String resolveDataSourcename(ChooseDataSource ds) { 
  return ds == null ? null : ds.value(); 
 } 
} 

那么以上3個類,就可以作為一個公共的組件打個包了。

那么項目中具體 怎么用列?

4.  在項目中定義一個具體的AspectJ切面

@Aspect 
public class OrderFetchAspect extends ChooseDataSourceAspect { 
}

如果你的根據你的需要重寫方法,我這邊是不需要重寫的,所以空切面就行了。

5.配置spring,在上面的分析過程中已經貼出了,基本上就是每個數據庫,一個dataSource,每個DataSource一個SqlSessionFactory。最后配一個SqlSessionTemplate,也就是我們自己重寫的。再就是MapperScan了,大致如下(數據庫連接信息已去除,包名為杜撰):

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
</bean> 
<bean id="dataSourceTb" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> 
</bean> 
<!-- 事務管理 --> 
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
 <property name="dataSource" ref="dataSource" /> 
</bean> 
<!-- 注解控制事務 --> 
<tx:annotation-driven transaction-manager="transactionManager"/> 
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> 
 <property name="dataSource" ref="dataSource"/> 
 <property name="configLocation" value="classpath:mybatis.xml" /> 
 <property name="mapperLocations" value="classpath*:com/foo/bar/**/config/*mapper.xml" /> 
</bean> 
<bean id="sqlSessionFactoryTb" class="org.mybatis.spring.SqlSessionFactoryBean"> 
 <property name="dataSource" ref="dataSourceTb"/> 
 <property name="configLocation" value="classpath:mybatis.xml" /> 
 <property name="mapperLocations" value="classpath*:<span >com/foo/bar</span><span >/**/configtb/*mapper.xml" /></span> 
</bean> 
<bean id="sqlSessionTemplate" class="com.foo.bar.template.EjsSqlSessionTemplate"> 
 <constructor-arg ref="sqlSessionFactory" /> 
 <property name="targetSqlSessionFactory"> 
  <map> 
   <entry value-ref="sqlSessionFactory" key="spider"/> 
   <entry value-ref="sqlSessionFactoryTb" key="sysinfo"/> 
  </map> 
 </property> 
</bean> 
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> 
 <property name="basePackage" value="com.foo.bar.**.mapper*" /> 
 <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/> 
</bean> 

6.具體應用

@ChooseDataSource("spider") 
public class ShopServiceTest extends ErpTest { 
 private static final Logger log = LoggerFactory.getLogger(ShopServiceTest.class); 
 @Autowired 
 private IShopService shopService; 
 @Autowired 
 private IJdpTbTradeService jdpTbTradeService; 
 @Test 
 @Rollback(false) 
 public void testFindAllShop(){ 
  List<Shop> shopList1 = shopService.findAllShop(); 
  for(Shop shop : shopList1){ 
   System.out.println(shop); 
  } 
  fromTestDB(); 
 } 
 @ChooseDataSource("sysinfo") 
 private void fromTestDB(){ 
  List<Shop> shopList = jdpTbTradeService.findAllShop(); 
  for(Shop shop : shopList){ 
   System.out.println(shop); 
  } 
 } 
} 

測試發現 shopList1是從spider庫查出來的數據,而fromDB則是從sysinfo中查出來的數據。 那么我們就大功告成。
要做到我以上功能,Spring AOP是做不到的,因為他不支持Cflow(),這也就是我為什么要用AspectJ的原因。

-----------------------------------------------------------------------------------------------再次分割線-------------------------------------------------------------------------------------------------------------------

好了,功能我們已經實現了,你有沒有覺得很麻煩,這一點也不Spring的風格,Spring的各個地方擴展都是很方便的。那么我們看看,在SqlSessionTemplate中的什么地方改動一下,我們就可以很輕松的實現這個功能列?大家可以理解了,再回去看一下源碼。

其實,只要將源碼中的那個SqlSessionInterceptor的這句話:

final SqlSession sqlSession = getSqlSession( 
   SqlSessionTemplate.this.sqlSessionFactory, 
   SqlSessionTemplate.this.executorType, 
   SqlSessionTemplate.this.exceptionTranslator); 

改為:

final SqlSession sqlSession = getSqlSession( 
     EjsSqlSessionTemplate.this.getSqlSessionFactory(), 
     EjsSqlSessionTemplate.this.executorType,     
		 EjsSqlSessionTemplate.this.exceptionTranslator); 

保證 每次在產生Session代理的時候,傳進去的參數都是調用getSqlSessionFactory()獲取,那么我們自定義的SqlSessionTemplate,只要重寫getSqlSessionFactory(),加多一個以下2句話:

private Map<Object, SqlSessionFactory> targetSqlSessionFactory; 
 public void setTargetSqlSessionFactory(Map<Object, SqlSessionFactory> targetSqlSessionFactory) { 
  this.targetSqlSessionFactory = targetSqlSessionFactory; 
 } 

那么就完全可以實現動態數據源切換。  那么mybatis-spring的項目團隊會這樣維護么? 我會以mail的方式與他們溝通。至于能否改進,我們不得而知了。

其實這也就引發一個關于面向對象設計時的思想,也是一直爭論得喋喋不休的一個問題:

    在類的方法中,如果要用到類的屬性時,是直接用this.filedName  來操作,還是用  getFiledName() 來進行操作?

其實以前我也是偏向于直接用this.屬性來進行操作的,但是經歷過這次以后,我想我會偏向于后者。

以上所述是小編給大家介紹的關于Spring3 + Mybatis3整合時多數據源動態切換的問題,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

东安县| 中山市| 文山县| 远安县| 柞水县| 卓尼县| 布尔津县| 白水县| 西贡区| 红安县| 安远县| 安庆市| 五峰| 龙山县| 广南县| 辽宁省| 仁怀市| 读书| 漳州市| 蓝山县| 绥江县| 辽宁省| 绍兴市| 蒙山县| 阳江市| 贵州省| 古丈县| 北安市| 梨树县| 东乡族自治县| 高阳县| 舟曲县| 蓝山县| 定远县| 灵寿县| 桐梓县| 泰州市| 洛浦县| 如东县| 浪卡子县| 全州县|