日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql动态配置数据源_Spring整合Mybatis实现动态数据源切换教程配置

發(fā)布時間:2023/12/15 数据库 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql动态配置数据源_Spring整合Mybatis实现动态数据源切换教程配置 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一.摘要

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

Spring整合MyBatis切換SqlSessionFactory有兩種方法,第一、 繼承SqlSessionDaoSupport,重寫獲取SqlSessionFactory的方法。第二、繼承SqlSessionTemplate 重寫getSqlSessionFactory、getConfiguration和SqlSessionInterceptor這個攔截器。其中最為關(guān)鍵還是繼承SqlSessionTemplate 并重寫里面的方法。

而Spring整合MyBatis也有兩種方式,一種是配置MapperFactoryBean,另一種則是利用MapperScannerConfigurer進(jìn)行掃描接口或包完成對象的自動創(chuàng)建。相對來說后者更方便些。MapperFactoryBean繼承了SqlSessionDaoSupport也就是動態(tài)切換SqlSessionFactory的第一種方法,我們需要重寫和實(shí)現(xiàn)SqlSessionDaoSupport方法,或者是繼承MapperFactoryBean來重寫覆蓋相關(guān)方法。如果利用MapperScannerConfigurer的配置整合來切換SqlSessionFactory,那么我們就需要繼承SqlSessionTemplate,重寫上面提到的方法。在整合的配置中很多地方都是可以注入SqlSessionTemplate代替SqlSessionFactory的注入的。因?yàn)镾qlSessionTemplate的創(chuàng)建也是需要注入SqlSessionFactory的。

二.實(shí)現(xiàn)代碼

1.繼承SqlSessionTemplate 重寫getSqlSessionFactory,getConfiguration和SqlSessionInterceptorpackage 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;

/**

* function: 繼承SqlSessionTemplate 重寫相關(guān)方法

* @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 targetSqlSessionFactorys;

private SqlSessionFactory defaultTargetSqlSessionFactory;

public void setTargetSqlSessionFactorys(Map 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 selectOne(String statement) {

return this.sqlSessionProxy. selectOne(statement);

}

/**

* {@inheritDoc}

*/

public T selectOne(String statement, Object parameter) {

return this.sqlSessionProxy. selectOne(statement, parameter);

}

/**

* {@inheritDoc}

*/

public Map selectMap(String statement, String mapKey) {

return this.sqlSessionProxy. selectMap(statement, mapKey);

}

/**

* {@inheritDoc}

*/

public Map selectMap(String statement, Object parameter, String mapKey) {

return this.sqlSessionProxy. selectMap(statement, parameter, mapKey);

}

/**

* {@inheritDoc}

*/

public Map selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {

return this.sqlSessionProxy. selectMap(statement, parameter, mapKey, rowBounds);

}

/**

* {@inheritDoc}

*/

public List selectList(String statement) {

return this.sqlSessionProxy. selectList(statement);

}

/**

* {@inheritDoc}

*/

public List selectList(String statement, Object parameter) {

return this.sqlSessionProxy. selectList(statement, parameter);

}

/**

* {@inheritDoc}

*/

public List selectList(String statement, Object parameter, RowBounds rowBounds) {

return this.sqlSessionProxy. 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 getMapper(Class 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 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或默認(rèn)的defaultTargetSqlSessionFactory中獲取Session對象。而改寫的SqlSessionInterceptor 是這個MyBatis整合Spring的關(guān)鍵,所有的SqlSessionFactory對象的session都將在這里完成創(chuàng)建、提交、關(guān)閉等操作。所以我們改寫這里的代碼,在這里獲取getSqlSessionFactory的時候,從多個SqlSessionFactory中獲取我們設(shè)置的那個即可。

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

CustomerContextHolder 設(shè)置SqlSessionFactory的類型package com.hoo.framework.mybatis.support;

/*

*多數(shù)據(jù)源

*/

public abstract class CustomerContextHolder {

public final static String SESSION_FACTORY_MYSQL = "mysql";

public final static String SESSION_FACTORY_ORACLE = "oracle";

private static final ThreadLocal contextHolder = new ThreadLocal();

public static void setContextType(String contextType) {

contextHolder.set(contextType);

}

public static String getContextType() {

return contextHolder.get();

}

public static void clearContextType() {

contextHolder.remove();

}

}

2、配置相關(guān)的文件applicationContext-session-factory.xml<?xml version="1.0" encoding="UTF-8"?>

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 ">

classpath:com/hoo/framework/mybatis/mybatis-common.xml

classpath:com/hoo/**/resultmap/*-resultmap.xml

classpath:com/hoo/**/mapper/*-mapper.xml

classpath:com/hoo/**/mapper/**/*-mapper.xml

classpath:com/hoo/framework/mybatis/mybatis-common.xml

classpath:com/hoo/**/resultmap/*-mysql-resultmap.xml

classpath:com/hoo/**/mapper/*-mysql-mapper.xml

classpath:com/hoo/**/mapper/**/*-mysql-mapper.xml

classpath:com/hoo/**/mapper/**/multiple-datasource-mapper.xml

上面的配置關(guān)鍵是在MapperScannerConfigurer中注入sqlSessionTemplate,這個要注意。當(dāng)我們配置了多個SqlSessionFactoryBean的時候,就需要為MapperScannerConfigurer指定一個sqlSessionFactoryBeanName或是sqlSessionTemplateBeanName。一般情況下注入了sqlSessionTemplateBeanName對象,那sqlSessionFactory也就有值了。如果單獨(dú)的注入了sqlSessionFactory那么程序會創(chuàng)建一個sqlSessionTemplate對象。我們可以看看代碼SqlSessionFactoryDaoSupport對象的代碼。如果你不喜歡使用掃描的方式,也可以注入sqlSessionTemplate或繼承sqlSessionTemplate完成數(shù)據(jù)庫操作。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上面的注入也就不會執(zhí)行了,如果沒有注入sqlSessionTemplate,那么會自動new一個sqlSessionTemplate對象。

3、編寫相關(guān)測試接口和實(shí)現(xiàn)的mapper.xmlpackage com.hoo.server.datasource.mapper;

import java.util.List;

import java.util.Map;

import com.hoo.framework.mybatis.SqlMapper;

/*

*MyBatis 多數(shù)據(jù)源 測試查詢接口

*/

public interface MultipleDataSourceMapper extends SqlMapper {

public List> execute4MySQL() throws Exception;

public List> execute4Oracle() throws Exception;

}multiple-datasource-mapper.xml

SELECT

*

FROM

deviceInfo_tab t where rownum < 10

]]>

SELECT

*

FROM

city limit 2

]]>

上面分別查詢oracle和mysql兩個數(shù)據(jù)庫中的table

4、測試代碼@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();

}

}

運(yùn)行后發(fā)現(xiàn)能夠順利查詢出數(shù)據(jù)。

如果你是重寫SqlSessionDaoSupport,那么方法如下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;

/*

*MyBatis 動態(tài)SqlSessionFactory

*/

public class DynamicSqlSessionDaoSupport extends SqlSessionDaoSupport implements ApplicationContextAware {

private ApplicationContext applicationContext;

private Map 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 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的方法。

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

//每一個DAO由繼承SqlSessionDaoSupport全部改為DynamicSqlSessionDaoSupportpublic class UserMapperDaoImpl extends DynamicSqlSessionDaoSupport implements UserDao {

public int addUser(User user) {

return this.getSqlSession().insert("com.hoo.user.dao.UserDao.addUser", user);

}

}

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

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

三.總結(jié)

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

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

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

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

輾轉(zhuǎn)反側(cè)我看到了SqlSessionTemplate這個類,它的功能相當(dāng)于SqlSessionDaoSupport的實(shí)現(xiàn)類MapperFactoryBean。最為關(guān)鍵的是SqlSessionTemplate有一個攔截器SqlSessionInterceptor,它復(fù)制所有SqlSession的創(chuàng)建、提交、關(guān)閉,而且是在每個方法之前。這點(diǎn)在上面也提到過了!所以我們只需要在SqlSessionInterceptor方法中獲取SqlSessionFactory的時候,在這之前調(diào)用下CustomerContextHolder.setContextType方法即可完成數(shù)據(jù)庫的SqlSessionFactory的切換。而在MapperScannerConfigurer提供了注入SqlSessionFactory和sqlSessionTemplate的方法,如果注入了SqlSessionFactory系統(tǒng)將會new一個sqlSessionTemplate,而注入了sqlSessionTemplate就不會創(chuàng)建其他對象(見下面代碼)。所以我們配置一個sqlSessionTemplate并注入到MapperScannerConfigurer中,程序?qū)褂眠@個sqlSessionTemplate。本文最后的實(shí)現(xiàn)方式就是這樣完成的。public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {

if (!this.externalSqlSession) {

this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);

}

}

public void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {

this.sqlSession = sqlSessionTemplate;

this.externalSqlSession = true;

}

歡迎拜訪!

由最代碼官方編輯于2016-7-9 18:10:58

總結(jié)

以上是生活随笔為你收集整理的mysql动态配置数据源_Spring整合Mybatis实现动态数据源切换教程配置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。