1. 程式人生 > >mybatis如何配置使用多個數據源(environment)?

mybatis如何配置使用多個數據源(environment)?

mybatis如何配置使用多個數據源?

一、資料庫連線properties配置檔案,兩個資料來源的地址:

hd.jdbc.driverClassName=com.mysql.jdbc.Driver
hd.jdbc.url=jdbc:mysql://127.0.0.1::3306/hd?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
hd.jdbc.username=root
hd.jdbc.password=root

ho.jdbc.driverClassName=com.mysql.jdbc.Driver
ho.jdbc
.url=jdbc:mysql://127.0.0.1:3306/ho?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true ho.jdbc.username=root ho.jdbc.password=root

二、mybatis配置檔案,配置兩個environment:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration> <properties resource="mybatis/jdbc.properties"/> <environments default="HO"> <environment id="HD"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${hd.jdbc.driverClassName}"
/>
<property name="url" value="${hd.jdbc.url}" /> <property name="username" value="${hd.jdbc.username}" /> <property name="password" value="${hd.jdbc.password}" /> </dataSource> </environment> <environment id="HO"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${ho.jdbc.driverClassName}" /> <property name="url" value="${ho.jdbc.url}" /> <property name="username" value="${ho.jdbc.username}" /> <property name="password" value="${ho.jdbc.password}" /> </dataSource> </environment> </environments> </configuration>

三、獲取SqlSessionFactory,獲取Mapper代理,便於在執行完Mapper方法後關閉SqlSession。
SqlSessionFactory的獲取

/**
 * 根據mybatis.xml中配置的不同的environment建立對應的SqlSessionFactory
 * @author boyce
 * @version 2014-3-27
 */
public final class DataSourceSqlSessionFactory {
    private static final String CONFIGURATION_PATH = "mybatis/mybatis.xml";

    private static final Map<DataSourceEnvironment, SqlSessionFactory> SQLSESSIONFACTORYS 
        = new HashMap<DataSourceEnvironment, SqlSessionFactory>();

    /**
     * 根據指定的DataSourceEnvironment獲取對應的SqlSessionFactory
     * @param environment 資料來源environment
     * @return SqlSessionFactory
     */
    public static SqlSessionFactory getSqlSessionFactory(DataSourceEnvironment environment) {

        SqlSessionFactory sqlSessionFactory = SQLSESSIONFACTORYS.get(environment);
        if (ObjectUtils.isNotNull(sqlSessionFactory))
            return sqlSessionFactory;
        else {
            InputStream inputStream = null;
            try {
                inputStream = Resources.getResourceAsStream(CONFIGURATION_PATH);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, environment.name());

                logger.info("Get {} SqlSessionFactory successfully.", environment.name());
            } catch (IOException e) {
                logger.warn("Get {} SqlSessionFactory error.", environment.name());
                logger.error(e.getMessage(), e);
            }
            finally {
                IOUtils.closeQuietly(inputStream);
            }

            SQLSESSIONFACTORYS.put(environment, sqlSessionFactory);
            return sqlSessionFactory;
        }
    }

    /**
     * 配置到Configuration.xml檔案中的資料來源的environment的列舉描述
     * @author boyce
     * @version 2014-3-27
     */
    public static enum DataSourceEnvironment {
        HD,
        HO;
    }
}

定義一個統一的Mapper標識介面,每一個具體的Mapper介面繼承該介面:

/**
 * Mapper Interface
 * @author boyce
 * @version 2014-3-28
 */
public interface Mapper {
}

定義一個Mapper代理工廠:

/**
 * Mapper Factory
 * @author boyce
 * @version 2014-3-28
 */
public final class MapperFactory {
    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(MapperFactory.class);
    /**
     * Create a mapper of environment by Mapper class
     * @param clazz Mapper class 
     * @param environment A datasource environment
     * @return a Mapper instance
     */
    @SuppressWarnings("unchecked")
    public static <T> T createMapper(Class<? extends Mapper> clazz, DataSourceEnvironment environment) {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(environment);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        Mapper mapper = sqlSession.getMapper(clazz);
        return (T)MapperProxy.bind(mapper, sqlSession);
    }

    /**
     * Mapper Proxy 
     * executing mapper method and close sqlsession
     * @author boyce
     * @version 2014-4-9
     */
    private static class MapperProxy implements InvocationHandler {
        private Mapper mapper;
        private SqlSession sqlSession;

        private MapperProxy(Mapper mapper, SqlSession sqlSession) {
            this.mapper = mapper;
            this.sqlSession = sqlSession;
        }

        @SuppressWarnings("unchecked")
        private static Mapper bind(Mapper mapper, SqlSession sqlSession) {
            return (Mapper) Proxy.newProxyInstance(mapper.getClass().getClassLoader(),
                    mapper.getClass().getInterfaces(), new MapperProxy(mapper, sqlSession));
        }

        /**
         * execute mapper method and finally close sqlSession
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object object = null;
            try {
                object = method.invoke(mapper, args);
            } catch(Exception e) {
                e.printStackTrace();
                logger.error(e.getMessage(), e);
            } finally {
                sqlSession.close();
            }
            return object;
        }
    }

    //Get a SqlSessionFactory of environment
    private static SqlSessionFactory getSqlSessionFactory(DataSourceEnvironment environment) {
        return DataSourceSqlSessionFactory.getSqlSessionFactory(environment);
    }

大功告成,客戶端使用:

UserMapper mapper = MapperFactory.createMapper(UserMapper.class, DataSourceEnvironment.HD);
User user = mapper.getUserById(162L);
System.out.println(user);

OK,到此基本上所有的工作就完成了,以上的方式就可以支援多個數據源了。
但是程式碼還不夠優雅,以上程式碼我們發現DataSourceEnvironment這個列舉變數在客戶端,MapperFactory以及DataSourceEnvironment
中傳來傳去,我們應該儘量減少一個類對外界類的耦合,也就是不符合Java程式設計原則中的迪米特法則。
好了,那我們來改良一下。
將MapperFactory設計成列舉策略模式:

/**
 * Mapper Creator
 * @author boyce
 * @version 2014-3-28
 */
public enum MapperFactory {

    HD {
        private SqlSessionFactory sqlSessionFactory;

        @Override
        public <T> T createMapper(Class<? extends Mapper> clazz) {
            return createMapper(clazz, this);
        }

        @Override
        protected void createSqlSessionFactory() {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, this.name());
        }

        @Override
        public SqlSessionFactory getSqlSessionFactory() {
            return sqlSessionFactory;
        }

    },
    HO {
        private SqlSessionFactory sqlSessionFactory;
        @Override
        public <T> T createMapper(Class<? extends Mapper> clazz) {
            return createMapper(clazz, this);
        }

        @Override
        protected void createSqlSessionFactory() {
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream, this.name());
        }

        @Override
        public SqlSessionFactory getSqlSessionFactory() {
            return sqlSessionFactory;
        }
    };

    /**
     * Create a mapper of environment by Mapper class
     * @param clazz Mapper class 
     * @param environment A datasource environment
     * @return a Mapper instance
     */
    public abstract <T> T createMapper(Class<? extends Mapper> clazz);

    /**
     * Create SqlSessionFactory of environment
     */
    protected abstract void createSqlSessionFactory();

    /**
     * get SqlSessionFactory
     */
    public abstract SqlSessionFactory getSqlSessionFactory();

    private static InputStream inputStream = null;
    static {
        try {
            inputStream = Resources.getResourceAsStream("mybatis/mybatis.xml");
            HO.createSqlSessionFactory();
            HD.createSqlSessionFactory();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(inputStream);
        }
    }

    @SuppressWarnings("unchecked")
    private static <T> T createMapper(Class<? extends Mapper> clazz, MapperFactory MapperFactory) {
        SqlSession sqlSession = MapperFactory.getSqlSessionFactory().openSession();
        Mapper mapper = sqlSession.getMapper(clazz);
        return (T)MapperProxy.bind(mapper, sqlSession);
    }

    /**
     * Mapper Proxy 
     * executing mapper method and close sqlsession
     * @author boyce
     * @version 2014-4-9
     */
    private static class MapperProxy implements InvocationHandler {
        private Mapper mapper;
        private SqlSession sqlSession;

        private MapperProxy(Mapper mapper, SqlSession sqlSession) {
            this.mapper = mapper;
            this.sqlSession = sqlSession;
        }

        private static Mapper bind(Mapper mapper, SqlSession sqlSession) {
            return (Mapper) Proxy.newProxyInstance(mapper.getClass().getClassLoader(),
                    mapper.getClass().getInterfaces(), new MapperProxy(mapper, sqlSession));
        }

        /**
         * execute mapper method and finally close sqlSession
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object object = null;
            try {
                object = method.invoke(mapper, args);
            } catch(Exception e) {
                e.printStackTrace();
            } finally {
                sqlSession.close();
            }
            return object;
        }
    }

}

客戶端使用場景:

UserMapper mapper = MapperFactory.HO.createMapper(UserMapper.class);
User user = mapper.getUserById(162L);
System.out.println(user);

=============以下非轉摘,個人經驗================

可改進的地方

1、MapperProxy中針對每一次的呼叫都進行close,比較浪費,可以考慮threadlocal來設定
2、對於複雜的事務可以採用如下方法進行控制:

SqlSession sqlSession = MapperFactory.xxxSqlSessionFactory().openSession(false);
//根據業務需要來獲得對應的session,手動控制事務
try{
    //業務操作1
    //業務操作2
    sqlSession.commit();
}catch(Exception ex){
    sqlSession.rollback();
    isSucess = false;
}finally{
    if (sqlSession != null) {
        sqlSession.close();
    }
}

3、每個db都在配置檔案中,如果涉及到分庫和分分表,建議在負載均衡類中啟動,從資料庫彙總獲得對應的分庫策略,然後將SqlSessionFactory()設定完成

相關推薦

mybatis如何配置使用個數environment

mybatis如何配置使用多個數據源? 一、資料庫連線properties配置檔案,兩個資料來源的地址: hd.jdbc.driverClassName=com.mysql.jdbc.Driver hd.jdbc.url=jdbc:mysql:/

mybatis如何配置使用個數environment

mybatis如何配置使用多個數據源? 一、資料庫連線properties配置檔案,兩個資料來源的地址: Java程式碼   hd.jdbc.driverClassName=com.mysql.jdbc.Driver   hd.jdbc.url=jdbc:mysql

Spring Profile和Mybatis進行個數H2和Mysql的切換

sql pda 開箱 https tails val 收集 sqlserver jpetstore 總結: 最近在做WebMagic的後臺,遇到一個問題:後臺用到了數據庫,本來理想情況下是用Mysql,但是為了做到開箱即用,也整合了一個嵌入式數據庫H2。這裏面就有個問題了,

Mybatis配置個數

1.編寫2個以上資料來源 <bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">         <property n

使用Spring Profile和Mybatis進行個數H2和Mysql的切換

轉載自:http://my.oschina.net/flashsword/blog/209872 最近在做WebMagic的後臺,遇到一個問題:後臺用到了資料庫,本來理想情況下是用Mysql,但是為了做到開箱即用,也整合了一個嵌入式資料庫H2。這裡面就有個問題了,如何用

mybatis+druid+springboot 註解方式配置個數

pat nts println service ssp bsp manager 打開 iba 1\數據庫配置 #test數據源 spring.datasource.test.url=jdbc:mysql://*:3306/db?useUnicode=true&ch

hibernate配置個數及事物以兩個資料來源為例

在ssh專案中,需要連線兩個不同ip下的資料庫,所以必須要給hibernate配置兩個或多個數據源 因為我只有一臺電腦,所以我配置的是sqlserver+mysql兩個資料來源 首先hibernate配置是直接從myeclipse中新增的   右鍵----myeclipse

EJB 配置個數

name XML cti kong 添加 local ima 不能 transacti 1.修改jboss-6.simple\server\default\deploy\transaction-jboss-beans.xml 配置文件 <bean name="Co

個數multiple data sources

art multipl spring detail 多個 教程 boot net sdn 參考資料: SpringBoot非官方教程 | 第五篇:springboot整合 beatlsql多個數據源(multiple data sources)

Spring cloud整合Reids 配置個數

首先是連線池的選擇 一般有兩種 lettuce ,jedis Jedis  執行緒不安全,方法同步 Lettuce  基於Netty.nio, 方法非同步 執行緒 安全 letture通過引入spring-boot-starter-redis就可以使用 <

Spring配置個數,並實現資料來源的動態切換

1.首先在config.properties檔案中配置兩個資料庫連線的基本資料。這個省略了 2.在spring配置檔案中配置這兩個資料來源: 資料來源1 <!-- initialSize初始化時建立物理連線的個數0 maxActive最大

Springboot 配置個數(AOP實現分庫)

//因為DynamicDataSource是繼承與AbstractRoutingDataSource,而AbstractRoutingDataSource又是繼承於AbstractDataSource,AbstractDataSource實現了統一的DataSource介面,

一個程式配置個數,並進行資料來源切換

1>.在資料庫連接配置檔案中配置,資料庫連線資訊,資料來源選擇器,多個數據源資訊,sql會話工廠 <!-- 在applicationContext-dao.xml引入資料庫資訊配置檔案db.properties --> <bean id="prope

tomcat配置個數

應用場景:                公司tomcat伺服器中執行著多個工程,工程連結的mysql資料庫不同,所以每個工程的Spring總配置檔案中都配置了資料來源。 需求:   將資料來源統一拿到tomcat中配置。              本來指派給本人,由於開發

Pandas包對個數DataFrame的常用整合功能。

  目錄 merge join concat append combin_first     merge 合併 pandas.merge可根據一個或多個鍵將不同DataFrame中的行合併起來

Message訊息佇列中個數傳遞Bundle

MyHandler handler = new MyHandler(handlerThread.getLooper()); Message msg = handler.obtainMessage(); /** * 將Mes

Tidyverse| XX_join :個數檔案之間的各種連線

本文首發於公眾號:“生信補給站” Tidyverse| XX_join :多個數據表(檔案)之間的各種連線 前面分享了單個檔案中的select列,filter行,列拆分等,實際中經常是多個數據表,綜合使用才能回答你所感興趣的問題。 本次簡單的介紹多個表(檔案)連線的方法。 一 載入資料,R包 librar

單個工程中Spring+Mybatis連線個數庫的配置個人分享版本

上一篇部落格說到同一個問題,經過和朋友的研究已經參考網上的資料,現在給出一份更簡潔的配置。 情景:現在單個工程中需要連線兩個庫,這兩個庫在同一個mysql中,兩個庫都需要進行讀寫。 解決: 第一步:將spring和mybatis整合,這個過程就不具體演示了,在這個過程中建立

AngularJS $q 和 $q.all 單個數個數合並promise的說明

獲取 lar debug let index 被拒 可用 第一個 brush 這篇文章講的不錯, angular $q 和 promise!! -------------------------------------------------------------- 通

Spring Boot實現個數教程收集待實踐

get shu 多個 href eos net -c smi tar 先收集,後續實踐。 http://blog.csdn.net/catoop/article/details/50575038 http://blog.csdn.net/neosmith/article