设为首页 收藏本站
查看: 1033|回复: 0

[经验分享] mybatis 多数据源 以及 多数据源切换

[复制链接]

尚未签到

发表于 2016-11-27 12:46:28 | 显示全部楼层 |阅读模式
  最近做流程遇到需求:
  一个流程引擎的数据源,所有流程数据都在此数据源
  针对多个系统多个 用户相关数据源
  流程中只保存  用户id,name信息,其数据来源都是从各个用户数据源取得的。
  流程引擎配置不同系统的人员,部门等配置都需要切换用户数据源来取得,而流程引擎的数据源应该一直保持。
  所以解决方案应该为: 
  两套sqlSessionFactory          一个专门针对流程引擎使用
  一个专门用于不同用户数据源
  sqlsessionFactory1---->datasource_engine
  sqlsessionFactory2 ------> datasource_business -------->(切换) userDataSource1,userDataSource2
  1:实现数据源切换
  DynamicDataSourceHolder.java

/**
* 切源数据源实现类
*
*/
public class DynamicDataSourceHolder {
private static final ThreadLocal<String> local = new ThreadLocal<String>();
/**
* 清空当前数据源
*/
public static void clear(){
local.remove();
}
/**
* 获取当前数据源
*/
public static String get(){
return local.get();
}
/**
* 设置当前数据源
*/
public static void set(String source){
local.set(source);
}
}
  DynamicDataSource.java

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
//返回当前数据源
return DynamicDataSourceHolder.get();
}
}

  spring配置

<bean id="userDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/userDataSource1"></property>
</bean><!-- 用户数据源1  -->
<!-- 使用jndi数据源需要在web容器配置如下:
<Resource auth="Container" driverClassName="oracle.jdbc.OracleDriver"
maxActive="10" maxIdle="5" maxWait="15000" name="jdbc/userDataSource1"
password="123456" type="javax.sql.DataSource" url="jdbc:oracle:thin:@localhost:1521:ORCL"
username="user" />
-->
<bean id="userDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/userDataSource2"></property>
</bean><!-- 用户数据源2 -->
<bean id="dataSource_business" class="com.xxx.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="userDataSource1" value-ref="userDataSource1"></entry>
<entry key="userDataSource2" value-ref="userDataSource2"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="userDataSource1"></property>
</bean><!-- 自定义用户路由数据源 -->
<bean id="dataSource_engine" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/engine"></property>
</bean><!-- 流程引擎数据源 -->
  使用此种方式  切源数据源的话只需要设置代码:DynamicDataSourceHolder.set(“userDataSource1”);//将用户数据源切换为key为userDataSource1的数据源
  如何动态切换呢?
  可以使用aop来实现     aop拦截相应方法      动态获取key,更改数据源
  比如
  DataSourceAopProxy.java

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Service;
/**
*  aop实现动态切换数据源
*
*/
@Aspect
@Service
public class DataSourceAopProxy {
@Pointcut("execution(* com.xxx.*.*(..))")
private void setDataSource(JoinPoint jp){
//此处进行切换数据源   根据业务条件   获取数据源id
String dataSourceName = "userDataSource1";
DynamicDataSourceHolder.set(dataSourceName);
}
//@Before("setDataSource()")
//public void setDataSourceBefore(){
//String dataSourceName = "before";
//DynamicDataSourceHolder.set(dataSourceName);
//}
//
//
//@After("setDataSource()")
//public void setDataSourceAfter(JoinPoint jp){
//String dataSourceName = "after";
//DynamicDataSourceHolder.set(dataSourceName);
//}
}
  不过上面没有具体获取数据源key的方式:
  我的想法是         1 从切面的方法参数中取  (不过好像只能取来参数值,而取不到参数名称,再者也不一定之前写的方法有那个key参数,如果加上的话改动太大太累)
  2 从session中取。针对各系统用户请求,可以知道系统id,也就可以知道key了。 针对管理员的话,对某个系统管理就需要将sesssion中的key改成此系统的
  而且管理员一次只能管理一个系统,而不能管理多个(不同管理员,session不同,可以管理不同系统)
  这种方式的话需要把session放入ThreadLocal中,在切面中取session也从threadLocal中取。不过总感觉这个方式太搓
  暂时没有别的想法了。
  2.:两套sqlSessionFactory实现
  遇到问题: 系统中用户相关和流程引擎相关实体,mapper都放在一起,分包也不够清晰,做两套sqlSessionFactory的话扫包的basePackage 需要分包
  分包的话各个service引用mapper的地方都要改,工作量太大
  解决:     查看资料发现可以使用自定义注解来取代spring的repository设置到annotationClass中。这样每个mapper文件中注入相应的注解@EngineRepository,@BusinessRepository
  <property name="annotationClass" value="org.springframework.stereotype.Repository"></property>
  改成<property name="annotationClass" value="com.xxx.EngineRepository"></property>
  配置文件如下:

<bean id="sqlSessionFactory_engine" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis_engine.xml"></property>
<property name="dataSource" ref="dataSource_engine"></property>
<property name="databaseIdProvider" ref="databaseIdProvider"></property>
</bean><!-- 流程引擎所用sqlSessionFactory -->
<bean id="sqlSessionFactory_business" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis_business.xml"></property>
<property name="dataSource" ref="dataSource_business"></property>
<property name="databaseIdProvider" ref="databaseIdProvider"></property>
</bean><!-- 用户相关sqlSessionFactory -->
<bean id="vendorProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<prop key="SQL SERVER">sqlserver</prop>
<prop key="DB2">db2</prop>
<prop key="Oracle">oracle</prop>
</props>
</property>
</bean>
<bean id="databaseIdProvider" class="org.apache.ibatis.mapping.VendorDatabaseIdProvider">
<property name="properties" ref="vendorProperties"></property>
</bean>

<bean id="scanner_engine" class="org.mybatis.spring.MapperScannerConfigurer">
<property name="annotationClass" value="com.xxx.EngineRepository"></property>
<property name="basePackage" value="com.xxx.*.model"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory_engine"></property>
</bean><!-- 流程引擎扫mapper配置 -->
<bean id="scanner_business" class="org.mybatis.spring.MapperScannerConfigurer">
<property name="annotationClass" value="com.xxx.BusinessRepository"></property>
<property name="basePackage" value="com.xxx.*.model"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory_business"></property>
</bean><!-- 用户相关扫mapper配置 -->
  如上所配置使用流程引擎的mapper文件就加上注解@EngineRepository 

// 使用dataSource_engine 数据源
@EngineRepository
public interface TaskAssignMapper {
TaskAssign getTaskAssignByDeployIdAndTaskKey(String deployId,String taskKey);
...
}
// 使用 dataSource_business 数据源
@BusinessRepository
public interface UserDaoMapper {
List<User> getAllUser();
...
}

public @interface EngineRepository {
}
public @interface BusinessRepository {
}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-306237-1-1.html 上篇帖子: Spring3MVC+MyBatis+ExtJs3整合开发系列之三:人员管理模块 下篇帖子: Spring3MVC+MyBatis+ExtJs3整合开发系列之二:菜单模块演示
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表