Spring环境下MyBatis支持多个Datasource参考实现

本文介绍了在Spring环境下,如何实现一个MyBatis支持多个相同Schema的Datasource,采用代理方式动态切换数据源。文章详细阐述了识别用户对应数据库的方法,即根据用户位置判断,并提供了实现代码示例。同时,讨论了使用AbstractRoutingDataSource作为替代方案的可能性。
摘要由CSDN通过智能技术生成

需求背景

最近接到一个项目,需要改造一个老的系统。该老系统以Oracle为存储,巨量的PL/SQL代码实现业务代码,C实现Socket Server,作为Client和PL/SQL的桥梁。不出所料,该老系统最大的问题是PL/SQL代码量巨大(上万的Procedure好几个),且毫无组织可言,实在改不动了,其次是性能有问题。改动的方向是,把PL/SQL从Oracle中踢出,用Java改写相关业务逻辑,放到Web Server中,不过Oracle中的Schema不动。

到目前位置,改造老系统和笔者要分享的主题没啥关系。问题来了,老系统有三套,A,B,C,就是说有三个Oracle数据库,Schema以及PL/SQL完全相同,但是数据没有啥关系,完全独立的三个数据库。历史的问题,不好评说,但是只是为了解决性能问题,搞了三套,客户被分配到不同的套系统,和传统的游戏开个服务器一个思路。

我们有3个方案:
1. 部署三套WebServer,对应三个Oracle数据库,客户端连接到不同的Web Server,和原来架构相同。数据库和Server都继续分。
2. 把三个数据库整合为一个数据库,部署一套Web Server。数据和,Server和。
3. 保持三套Oracle数据库不变,一个Web Server,但是Server需要把三个Oracle都管理起来。

方案1最简单,最容易,但是当性能已经不再是问题的时候还是部署三套Web Server,实在是有些说不过去,运维工作增加,客户端维护不同的版本(服务器地址),不太愿意选择,暂时备选。

方案2很难,非常的难。原来的三个Oracle数据库,完全独立,没有全局的主键,基本上无法区分开数据。放弃!

方案3是个折中的方案,中国人讲究中庸之道。最终我们选择了方案3。

设计思路

方案3要解决的问题是同一个Server如何集成3个数据库,具体来说,就是Spring里面如何管理3个Shema完全相同的Datasouce。我们的系统Server的技术选型是常见的Spring+MyBatis。管理多个Shema不同的Datasouce,网上有很多例子,Schema相同这叫分库吗,貌似很少?那进一步在Spring环境下呢?没有找到。强调Spring只想知道一个Mapper,而非3个。是因为,Spring只想知道一个Mapper,而非3个。

其中的关键技术难点如下:

  1. 如何识别什么样的数据应该存到哪一个Oracle数据库?
    我们的解法是根据用户所在的位置来判断,用户在A库,那么后续的操作针对A库,在B库就操作B库。最开始登录的时候先探测用户到底存在于哪一个库。我们认为用户名+密码应该是跨三个数据库唯一的
  2. 如何动态切换数据库?
    代理,用代理来实现。Spring容器内注册的就是一个代理而已,代理被调用的时候,我们截获调用,根据登录时候获得的环境(哪一个库),来动态切换,委托给背后的MyBatis Mapper来执行。

下图是我画的切换的示意图。偷懒的原因,我只画了A,B两套,实战中是A,B,C。

使用代理实现动态切换

实例代码

识别应该存于哪一个数据库

稍微改造一下Shiro访问用户信息的地方,增加环境的属性。注意两点,一是遍历数据源,探测用户所在的数据库,而是直接用SqlSessionFactory的bean name作为环境名,够简单直白!

Shiro Realm代码如下:

public class ShiroRealm extends AuthorizingRealm {
    @Autowired
    private UserService userService;
    @Autowired
    private SecureService secureService;
    @Autowired
    private AuthorizationService authorizationService;

    @PostConstruct
    public void initAlgorithms() {
        AllowAllCredentialsMatcher credentialsMatcher = new AllowAllCredentialsMatcher();
        setCredentialsMatcher(credentialsMatcher);
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken pairToken = (UsernamePasswordToken) token;
        String userName = pairToken.getUsername();
        String password = new String(pairToken.getPassword());

        // determine env
        Map<String, Object>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值