一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術|正則表達式|

服務器之家 - 編程語言 - JAVA教程 - Spring3 整合MyBatis3 配置多數據源動態選擇SqlSessionFactory詳細教程

Spring3 整合MyBatis3 配置多數據源動態選擇SqlSessionFactory詳細教程

2020-09-16 15:18hoojo JAVA教程

這篇文章主要介紹了Spring3 整合MyBatis3 配置多數據源動態選擇SqlSessionFactory詳細教程,需要的朋友可以參考下

一、摘要

這篇文章將介紹Spring整合Mybatis 如何完成SqlSessionFactory的動態切換的。并且會簡單的介紹下MyBatis整合Spring中的官方的相關代碼。

Spring整合MyBatis切換SqlSessionFactory有兩種方法

第一、 繼承SqlSessionDaoSupport,重寫獲取SqlSessionFactory的方法。

第二、繼承SqlSessionTemplate 重寫getSqlSessionFactory、getConfiguration和SqlSessionInterceptor這個攔截器。其中最為關鍵還是繼承SqlSessionTemplate 并重寫里面的方法。

而Spring整合MyBatis也有兩種方式,一種是配置MapperFactoryBean,另一種則是利用MapperScannerConfigurer進行掃描接口或包完成對象的自動創建。相對來說后者更方便些。

MapperFactoryBean繼承了SqlSessionDaoSupport也就是動態切換SqlSessionFactory的第一種方法,我們需要重寫和實現SqlSessionDaoSupport方法,或者是繼承MapperFactoryBean來重寫覆蓋相關方法。如果利用MapperScannerConfigurer的配置整合來切換SqlSessionFactory,那么我們就需要繼承SqlSessionTemplate,重寫上面提到的方法。在整合的配置中很多地方都是可以注入SqlSessionTemplate代替SqlSessionFactory的注入的。因為SqlSessionTemplate的創建也是需要注入SqlSessionFactory的。

二、實現代碼

1、繼承SqlSessionTemplate 重寫getSqlSessionFactory、getConfiguration和SqlSessionInterceptor

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
package com.hoo.framework.mybatis.support;
import static java.lang.reflect.Proxy.newProxyInstance;
import static org.apache.ibatis.reflection.ExceptionUtil.unwrapThrowable;
import static org.mybatis.spring.SqlSessionUtils.closeSqlSession;
import static org.mybatis.spring.SqlSessionUtils.getSqlSession;
import static org.mybatis.spring.SqlSessionUtils.isSqlSessionTransactional;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisExceptionTranslator;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.util.Assert;
/**
 * <b>function:</b> 繼承SqlSessionTemplate 重寫相關方法
 * @author hoojo
 * @createDate 2013-10-18 下午03:07:46
 * @file CustomSqlSessionTemplate.java
 * @package com.hoo.framework.mybatis.support
 * @project SHMB
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email [email protected]
 * @version 1.0
 */
public class CustomSqlSessionTemplate extends SqlSessionTemplate {
 private final SqlSessionFactory sqlSessionFactory;
 private final ExecutorType executorType;
 private final SqlSession sqlSessionProxy;
 private final PersistenceExceptionTranslator exceptionTranslator;
 private Map<Object, SqlSessionFactory> targetSqlSessionFactorys;
 private SqlSessionFactory defaultTargetSqlSessionFactory;
 public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) {
 this.targetSqlSessionFactorys = targetSqlSessionFactorys;
 }
 public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) {
 this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory;
 }
 public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
 this(sqlSessionFactory, sqlSessionFactory.getConfiguration().getDefaultExecutorType());
 }
 public CustomSqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType) {
 this(sqlSessionFactory, executorType, new MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration()
  .getEnvironment().getDataSource(), true));
 }
 public CustomSqlSessionTemplate(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());
 this.defaultTargetSqlSessionFactory = sqlSessionFactory;
 }
 @Override
 public SqlSessionFactory getSqlSessionFactory() {
 SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(CustomerContextHolder.getContextType());
 if (targetSqlSessionFactory != null) {
  return targetSqlSessionFactory;
 } else if (defaultTargetSqlSessionFactory != null) {
  return defaultTargetSqlSessionFactory;
 } else {
  Assert.notNull(targetSqlSessionFactorys, "Property 'targetSqlSessionFactorys' or 'defaultTargetSqlSessionFactory' are required");
  Assert.notNull(defaultTargetSqlSessionFactory, "Property 'defaultTargetSqlSessionFactory' or 'targetSqlSessionFactorys' are required");
 }
 return this.sqlSessionFactory;
 }
 @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(
   CustomSqlSessionTemplate.this.getSqlSessionFactory(),
   CustomSqlSessionTemplate.this.executorType,
   CustomSqlSessionTemplate.this.exceptionTranslator);
  try {
  Object result = method.invoke(sqlSession, args);
  if (!isSqlSessionTransactional(sqlSession, CustomSqlSessionTemplate.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 (CustomSqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
   Throwable translated = CustomSqlSessionTemplate.this.exceptionTranslator
   .translateExceptionIfPossible((PersistenceException) unwrapped);
   if (translated != null) {
   unwrapped = translated;
   }
  }
  throw unwrapped;
  } finally {
  closeSqlSession(sqlSession, CustomSqlSessionTemplate.this.getSqlSessionFactory());
  }
 }
 }
}

重寫后的getSqlSessionFactory方法會從我們配置的SqlSessionFactory集合targetSqlSessionFactorys或默認的defaultTargetSqlSessionFactory中獲取Session對象。而改寫的SqlSessionInterceptor 是這個MyBatis整合Spring的關鍵,所有的SqlSessionFactory對象的session都將在這里完成創建、提交、關閉等操作。所以我們改寫這里的代碼,在這里獲取getSqlSessionFactory的時候,從多個SqlSessionFactory中獲取我們設置的那個即可。

上面添加了targetSqlSessionFactorys、defaultTargetSqlSessionFactory兩個屬性來配置多個SqlSessionFactory對象和默認的SqlSessionFactory對象。

CustomerContextHolder 設置SqlSessionFactory的類型

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.hoo.framework.mybatis.support;
/**
 * <b>function:</b> 多數據源
 * @author hoojo
 * @createDate 2013-9-27 上午11:36:57
 * @file CustomerContextHolder.java
 * @package com.hoo.framework.spring.support
 * @project SHMB
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email [email protected]
 * @version 1.0
 */
public abstract class CustomerContextHolder {
 public final static String SESSION_FACTORY_MYSQL = "mysql";
 public final static String SESSION_FACTORY_ORACLE = "oracle";
 private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
 public static void setContextType(String contextType) {
 contextHolder.set(contextType);
 }
 public static String getContextType() {
 return contextHolder.get();
 }
 public static void clearContextType() {
 contextHolder.remove();
 }
}

2、配置相關的文件applicationContext-session-factory.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
 <!-- 配置c3p0數據源 -->
 <bean id="dataSourceOracle" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
 <property name="driverClass" value="${datasource.driver}"/>
 <property name="jdbcUrl" value="${datasource.url}"/>
 <property name="user" value="${datasource.username}"/>
 <property name="password" value="${datasource.password}"/>
 <property name="acquireIncrement" value="${c3p0.acquireIncrement}"/>
 <property name="initialPoolSize" value="${c3p0.initialPoolSize}"/>
 <property name="minPoolSize" value="${c3p0.minPoolSize}"/>
 <property name="maxPoolSize" value="${c3p0.maxPoolSize}"/>
 <property name="maxIdleTime" value="${c3p0.maxIdleTime}"/>
 <property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}"/>
 <property name="maxStatements" value="${c3p0.maxStatements}"/>
 <property name="numHelperThreads" value="${c3p0.numHelperThreads}"/>
 <property name="preferredTestQuery" value="${c3p0.preferredTestQuery}"/>
 <property name="testConnectionOnCheckout" value="${c3p0.testConnectionOnCheckout}"/>
 </bean>
 <bean id="dataSourceMySQL" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
 <property name="driverClass" value="com.mysql.jdbc.Driver"/>
 <property name="jdbcUrl" value="jdbc:mysql://172.31.108.178:3306/world?useUnicode=true&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull"/>
 <property name="user" value="root"/>
 <property name="password" value="jp2011"/>
 <property name="acquireIncrement" value="${c3p0.acquireIncrement}"/>
 <property name="initialPoolSize" value="${c3p0.initialPoolSize}"/>
 <property name="minPoolSize" value="${c3p0.minPoolSize}"/>
 <property name="maxPoolSize" value="${c3p0.maxPoolSize}"/>
 <property name="maxIdleTime" value="${c3p0.maxIdleTime}"/>
 <property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}"/>
 <property name="maxStatements" value="${c3p0.maxStatements}"/>
 <property name="numHelperThreads" value="${c3p0.numHelperThreads}"/>
 <property name="preferredTestQuery" value="${c3p0.preferredTestQuery}"/>
 <property name="testConnectionOnCheckout" value="${c3p0.testConnectionOnCheckout}"/>
 </bean>
 <!-- 配置SqlSessionFactoryBean -->
 <bean id="oracleSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSourceOracle"/>
 <property name="configLocation" value="classpath:mybatis.xml"/>
 <!-- mapper和resultmap配置路徑 -->
 <property name="mapperLocations">
  <list>
  <!-- 表示在com.hoo目錄下的任意包下的resultmap包目錄中,以-resultmap.xml或-mapper.xml結尾所有文件 -->
  <value>classpath:com/hoo/framework/mybatis/mybatis-common.xml</value>
  <value>classpath:com/hoo/**/resultmap/*-resultmap.xml</value>
  <value>classpath:com/hoo/**/mapper/*-mapper.xml</value>
  <value>classpath:com/hoo/**/mapper/**/*-mapper.xml</value>
  </list>
 </property>
 </bean>
 <!-- 配置SqlSessionFactoryBean -->
 <bean id="mysqlSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSourceMySQL"/>
 <property name="configLocation" value="classpath:mybatis.xml"/>
 <!-- mapper和resultmap配置路徑 -->
 <property name="mapperLocations">
  <list>
  <!-- 表示在com.hoo目錄下的任意包下的resultmap包目錄中,以-resultmap.xml或-mapper.xml結尾所有文件 (oracle和mysql掃描的配置和路徑不一樣,如果是公共的都掃描 這里要區分下,不然就報錯 找不到對應的表、視圖)-->
  <value>classpath:com/hoo/framework/mybatis/mybatis-common.xml</value>
  <value>classpath:com/hoo/**/resultmap/*-mysql-resultmap.xml</value>
  <value>classpath:com/hoo/**/mapper/*-mysql-mapper.xml</value>
  <value>classpath:com/hoo/**/mapper/**/*-mysql-mapper.xml</value>
  <value>classpath:com/hoo/**/mapper/**/multiple-datasource-mapper.xml</value>
  </list>
 </property>
 </bean>
 <!-- 配置自定義的SqlSessionTemplate模板,注入相關配置 -->
 <bean id="sqlSessionTemplate" class="com.hoo.framework.mybatis.support.CustomSqlSessionTemplate">
 <constructor-arg ref="oracleSqlSessionFactory" />
 <property name="targetSqlSessionFactorys">
  <map>
  <entry value-ref="oracleSqlSessionFactory" key="oracle"/>
  <entry value-ref="mysqlSqlSessionFactory" key="mysql"/>
  </map>
 </property>
 </bean>
 <!-- 通過掃描的模式,掃描目錄在com/hoo/任意目錄下的mapper目錄下,所有的mapper都需要繼承SqlMapper接口的接口 -->
 <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
 <property name="basePackage" value="com.hoo.**.mapper"/>
 <!-- 注意注入sqlSessionTemplate -->
 <property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
 <property name="markerInterface" value="com.hoo.framework.mybatis.SqlMapper"/>
 </bean>
</beans>

上面的配置關鍵是在MapperScannerConfigurer中注入sqlSessionTemplate,這個要注意。當我們配置了多個SqlSessionFactoryBean的時候,就需要為MapperScannerConfigurer指定一個sqlSessionFactoryBeanName或是sqlSessionTemplateBeanName。一般情況下注入了sqlSessionTemplateBeanName對象,那sqlSessionFactory也就有值了。如果單獨的注入了sqlSessionFactory那么程序會創建一個sqlSessionTemplate對象。我們可以看看代碼SqlSessionFactoryDaoSupport對象的代碼。如果你不喜歡使用掃描的方式,也可以注入sqlSessionTemplate或繼承sqlSessionTemplate完成數據庫操作。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public abstract class SqlSessionDaoSupport extends DaoSupport {
 private SqlSession sqlSession;
 private boolean externalSqlSession;
 public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
 if (!this.externalSqlSession) {
 this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
 }
 }
 public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
 this.sqlSession = sqlSessionTemplate;
 this.externalSqlSession = true;
 }
......

這段代碼很明顯,如果注入了sqlSessionTemplate上面的注入也就不會執行了。如果沒有注入sqlSessionTemplate,那么會自動new一個sqlSessionTemplate對象。

3、編寫相關測試接口和實現的mapper.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.hoo.server.datasource.mapper;
import java.util.List;
import java.util.Map;
import com.hoo.framework.mybatis.SqlMapper;
/**
 * <b>function:</b> MyBatis 多數據源 測試查詢接口
 * @author hoojo
 * @createDate 2013-10-10 下午04:18:08
 * @file MultipleDataSourceMapper.java
 * @package com.hoo.server.datasource.mapper
 * @project SHMB
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email [email protected]
 * @version 1.0
 */
public interface MultipleDataSourceMapper extends SqlMapper {
 public List<Map<String, Object>> execute4MySQL() throws Exception;
 public List<Map<String, Object>> execute4Oracle() throws Exception;
}
multiple-datasource-mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hoo.server.datasource.mapper.MultipleDataSourceMapper">
 <select id="execute4Oracle" resultType="map">
 <![CDATA[
  SELECT
  *
  FROM
  deviceInfo_tab t where rownum < 10
 ]]>
 </select>
 <select id="execute4MySQL" resultType="map">
 <![CDATA[
  SELECT
  *
  FROM
  city limit 2
 ]]>
 </select>
</mapper>

上面分別查詢oracle和mysql兩個數據庫中的table

4、測試代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Autowired
@Qualifier("multipleDataSourceMapper")
private MultipleDataSourceMapper mapper;
@Test
public void testMapper() {
 CustomerContextHolder.setContextType(CustomerContextHolder.SESSION_FACTORY_MYSQL);
 try {
 trace(mapper.execute4MySQL());
 } catch (Exception e1) {
 e1.printStackTrace();
 }
 CustomerContextHolder.setContextType(CustomerContextHolder.SESSION_FACTORY_ORACLE);
 try {
 trace(mapper.execute4Oracle());
 } catch (Exception e) {
 e.printStackTrace();
 }
}

運行后發現能夠順利查詢出數據。

如果你是重寫SqlSessionDaoSupport,那么方法如下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.hoo.framework.mybatis.support;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
 * <b>function:</b> MyBatis 動態SqlSessionFactory
 * @author hoojo
 * @createDate 2013-10-14 下午02:32:19
 * @file DynamicSqlSessionDaoSupport.java
 * @package com.hoo.framework.mybatis.support
 * @project SHMB
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email [email protected]
 * @version 1.0
 */
public class DynamicSqlSessionDaoSupport extends SqlSessionDaoSupport implements ApplicationContextAware {
 private ApplicationContext applicationContext;
 private Map<Object, SqlSessionFactory> targetSqlSessionFactorys;
 private SqlSessionFactory defaultTargetSqlSessionFactory;
 private SqlSession sqlSession;
 @Override
 public final SqlSession getSqlSession() {
 SqlSessionFactory targetSqlSessionFactory = targetSqlSessionFactorys.get(CustomerContextHolder.getContextType());
 if (targetSqlSessionFactory != null) {
  setSqlSessionFactory(targetSqlSessionFactory);
 } else if (defaultTargetSqlSessionFactory != null) {
  setSqlSessionFactory(defaultTargetSqlSessionFactory);
  targetSqlSessionFactory = defaultTargetSqlSessionFactory;
 } else {
  targetSqlSessionFactory = (SqlSessionFactory) applicationContext.getBean(CustomerContextHolder.getContextType());
  setSqlSessionFactory(targetSqlSessionFactory);
 }
 this.sqlSession = SqlSessionUtils.getSqlSession(targetSqlSessionFactory);
 return this.sqlSession;
 }
 @Override
 protected void checkDaoConfig() {
 //Assert.notNull(getSqlSession(), "Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required");
 }
 public void setTargetSqlSessionFactorys(Map<Object, SqlSessionFactory> targetSqlSessionFactorys) {
 this.targetSqlSessionFactorys = targetSqlSessionFactorys;
 }
 public void setDefaultTargetSqlSessionFactory(SqlSessionFactory defaultTargetSqlSessionFactory) {
 this.defaultTargetSqlSessionFactory = defaultTargetSqlSessionFactory;
 }
 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
 this.applicationContext = applicationContext;
 }
}

主要重寫getSqlSession方法,上面獲取SqlSessionFactory的方法。

重寫好了后就可以配置這個對象,配置代碼如下

?
1
2
3
4
5
6
7
//每一個DAO由繼承SqlSessionDaoSupport全部改為DynamicSqlSessionDaoSupport
public class UserMapperDaoImpl extends DynamicSqlSessionDaoSupport implements UserDao {
 
 public int addUser(User user) { 
 return this.getSqlSession().insert("com.hoo.user.dao.UserDao.addUser", user);
 }
}

在上面的配置文件中加入配置

?
1
2
3
4
5
6
7
8
9
10
<bean id="baseDao" class="com.hoo.framework.mybatis.support.DynamicSqlSessionDaoSupport" abstract="true" lazy-init="true">
 <property name="targetSqlSessionFactorys">
 <map>
  <entry value-ref="oracleSqlSessionFactory" key="oracle"/>
  <entry value-ref="mysqlSqlSessionFactory" key="mysql"/>
 </map>
 </property>
 <property name="defaultTargetSqlSessionFactory" ref="oracleSqlSessionFactory"/>
 </bean>
<bean id="userMapperDao" class="com.hoo.user.dao.impl.UserMapperDaoImpl" parent="baseDao"/>

就這樣也可以利用DynamicSqlSessionDaoSupport來完成動態切換sqlSessionFactory對象,只需用在注入userMapperDao調用方法的時候設置下CustomerContextHolder的contextType即可。

三、總結

為了實現這個功能看了mybatis-spring-1.2.0.jar這個包的部分源代碼,代碼內容不是很多。所以看了下主要的代碼,下面做些簡單的介紹。

MapperScannerConfigurer這個類就是我們要掃描的Mapper接口的類,也就是basePackage中繼承markerInterface配置的接口。可以看看ClassPathBeanDefinitionScanner、ClassPathMapperScanner中的doScan這個方法。它會掃描basePackage這個包下所有接口,在ClassPathScanningCandidateComponentProvider中有這個方法findCandidateComponents,它會找到所有的BeanDefinition。

最重要的一點是ClassPathMapperScanner中的doScan這個方法它會給這些接口創建一個MapperFactoryBean。并且會檢查sqlSessionFactory和sqlSessionTemplate對象的注入情況。

Spring3 整合MyBatis3 配置多數據源動態選擇SqlSessionFactory詳細教程

image 所以我們配置掃描的方式也就相當于我們在配置文件中給每一個Mapper配置一個MapperFactoryBean一樣。而這個MapperFactoryBean又繼承SqlSessionDaoSupport。所以當初我想重寫MapperScannerConfigurer中的postProcessBeanDefinitionRegistry方法,然后重寫方法中的ClassPathMapperScanner中的doScan方法,將definition.setBeanClass(MapperFactoryBean.class);改成自己定義的MapperFactoryBean。最后以失敗告終,因為這里是Spring裝載掃描對象的時候都已經為這些對象創建好了代理、設置好了mapperInterface和注入需要的類。所以在調用相關操作數據庫的API方法的時候,設置對應的SqlSessionFactory也是無效的。

輾轉反側我看到了SqlSessionTemplate這個類,它的功能相當于SqlSessionDaoSupport的實現類MapperFactoryBean。最為關鍵的是SqlSessionTemplate有一個攔截器SqlSessionInterceptor,它復制所有SqlSession的創建、提交、關閉,而且是在每個方法之前。這點在上面也提到過了!所以我們只需要在SqlSessionInterceptor方法中獲取SqlSessionFactory的時候,在這之前調用下CustomerContextHolder.setContextType方法即可完成數據庫的SqlSessionFactory的切換。而在MapperScannerConfigurer提供了注入SqlSessionFactory和sqlSessionTemplate的方法,如果注入了SqlSessionFactory系統將會new一個sqlSessionTemplate,而注入了sqlSessionTemplate就不會創建其他對象(見下面代碼)。所以我們配置一個sqlSessionTemplate并注入到MapperScannerConfigurer中,程序將會使用這個sqlSessionTemplate。本文最后的實現方式就是這樣完成的。

?
1
2
3
4
5
6
7
8
9
public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
 if (!this.externalSqlSession) {
 this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
 }
}
public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
 this.sqlSession = sqlSessionTemplate;
 this.externalSqlSession = true;
}

以上所述是小編給大家介紹的Spring3 整合MyBatis3 配置多數據源動態選擇SqlSessionFactory詳細教程,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:http://www.blogjava.net/hoojo/archive/2013/10/22/405488.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本高清不卡一区久久精品 | 韩国一级淫片特黄特刺激 | 久久久久久久伊人电影 | 国产高清小视频 | 成年男女免费视频 | 成人影院在线看 | 99视频在线免费观看 | 欧美成人一区二区三区 | 五月婷婷丁香色 | 免费看男女做好爽好硬视频 | 2020精品极品国产色在线观看 | 精品无人区一区二区三区 | 百合互慰吃奶互揉漫画 | 特级淫片欧美高清视频蜜桃 | 成年私人影院免费视频网站 | 日本最新伦中文字幕 | 999热这里全都是精品 | 美女翘臀跪床被打屁股作文 | 9966国产精品视频 | 日韩不卡一区二区三区 | 日本中文字幕高清 | 成人精品视频一区二区在线 | 亚洲精品乱码久久久久久蜜桃 | 女人张开腿让男人桶视频免费大全 | 四虎1515hh.com| 日本高清色视影www日本 | 青柠影院在线观看免费完整版1 | 亚欧成人中文字幕一区 | 天天曰| 精品久久久久免费极品大片 | 日本成人免费在线视频 | t66y地址一地址二地址三 | 天天做日日爱 | 猛操美女 | 草逼的视频| 免费在线看 | 日韩一区二区三区四区区区 | 精品推荐国产麻豆剧传媒 | 女人张开腿让男人桶视频免费大全 | 国产精品久久久久a影院 | 亚洲第一区在线观看 |