mybatis如何配置使用多个数据源(environment)?
程序员文章站
2022-07-12 13:11:15
...
mybatis如何配置使用多个数据源?
一、数据库连接properties配置文件,两个数据源的地址:
二、mybatis配置文件,配置两个environment:
三、获取SqlSessionFactory,获取Mapper代理,便于在执行完Mapper方法后关闭SqlSession。
SqlSessionFactory的获取:
定义一个统一的Mapper标识接口,每一个具体的Mapper接口继承该接口:
定义一个Mapper代理工厂:
大功告成,客户端使用:
OK,到此基本上所有的工作就完成了,以上的方式就可以支持多个数据源了。
但是代码还不够优雅,以上代码我们发现DataSourceEnvironment这个枚举变量在客户端,MapperFactory以及DataSourceEnvironment
中传来传去,我们应该尽量减少一个类对外界类的耦合,也就是不符合Java编程原则中的迪米特法则。
好了,那我们来改良一下。
将MapperFactory设计成枚举策略模式:
客户端使用场景:
ok,如果大家有什么更优雅的设计方案请不吝分享分享。
一、数据库连接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);
ok,如果大家有什么更优雅的设计方案请不吝分享分享。
推荐阅读
-
Spring boot如何快速的配置多个Redis数据源
-
SpringBoot Mybatis如何配置多数据源并分包
-
mybatis如何配置使用多个数据源(environment)?
-
java项目如何配置多数据源(基于SpringBoot+Mybatis框架)
-
SpringMVC+Mybatis 如何配置多个数据源并切换?
-
Spring boot如何快速的配置多个Redis数据源
-
SpringBoot Mybatis如何配置多数据源并分包
-
spring整合c3p0整合mybatis。spring使用java配置类来整合配置c3p0数据源和mybatis。
-
如何 在Spring MVC中 使用多个Spring和MyBatis的xml配置文件(多模块配置)
-
Magento中如何在模块中使用多张数据表并配置多个model?