一种解决NOSQL和SQL数据分布式事务的技术方案

废话不多说。直奔主题!

这是目前遇见的一个业务场景:

1、为了支撑一套产品生产线,打造了一套中间件框架。这套框架集成了各种通用性功能,大大缩短了开发成本。

2、你可以理解,是一套业务中台。

3、我该次讲的是数据中台部分,一套支撑上层应用的数据访问层DAO。

也不废话,直接说设计思路:

继续说重点:

这里说的是multdao如何实现整合mysql和mongodb和ES数据库.

如果要整合,俩个目标:读和写。

写:同步syn写,一次写记录,分别在mysql、mongodb、es里存在一条,数据一致性,并且出现事务问题保证数据多库数据一致。

Mongodb.syn=true //开启同步

Mysql.syn=true //开启同步

读:可以切换,从mongodb取数据,从mysql取数据库,从ES里取数据。

DAO.name=组件名

Master.query=mongodb//查询来源库

Master.query.whitelist=项目包路径 //哪些包(精细到类名)下的查询走上述库

如何设计同步?

public String saveSyn(Object po){

try{

mysqlsession.save(po);

mongodbsession.save(po);

}catch(RuntimeException e){

mysqlsession.rollback();

mongodbsession.rollback();

}

}

这看起来不错,不过我告诉你这是错的。为啥?你这可以解决单层垮库本地事务,解决的了多层嵌套事务吗?

也就是说这样写,没有完全解决分布式事务。

不废话直接告诉你一种正确的分布式事务实现方案:

1、思想:选一款DAO中间件,比如HIBERNATE。为啥选?他统一了规范,你写一套PO映射关系就行,他对mongodb和mysql都不需要变代码。(PO就是@Entity注解的类)然后你可以extends一个父类,这个父类@MappedSuperclass注解一些公用字段。

2、你选一个支持XA本地事务的数据库,比如这里选了mysql,因为我发现hibernate 的mysql提供了拦截器和监听器接口。PostInsertEventListener,PostDeleteEventListener,PostUpdateEventListener

import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.persister.entity.EntityPersister;

说明一下,hibernate拦截器是个大杂烩,执行前执行后啥都能拦截。但是我们要的是,mysql执行成功之后,拦截进行写mongodb的操作,所以选择了过滤器。

MYSQL是支持XA事务的,因此我们可以不用自己实现事务。用MYSQL成熟的事务,我们只需要在事务回滚的时候得到触发告诉我这个语句写MYSQL成功了,那么我就可以继续去写MONGODB。如果MYSQL执行事务失败发生回滚了,告诉我不能写mongodb。

3、写三个过滤器实现。

import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.persister.entity.EntityPersister;

import gboat3.mult.dao.util.MongoUtil;

public class MongoUpdateEventListener implements PostUpdateEventListener {
    private static final long serialVersionUID = -7776598890958220332L;

    @Override
    public boolean requiresPostCommitHanding(EntityPersister persister) {
        // TODO Auto-generated method stub
        return false;
    }
    @Override
    public void onPostUpdate(PostUpdateEvent event) {
        // TODO Auto-generated method stub
        System.out.println("PostUpdateEventListener同步到mongodb:"+event.getEntity().getClass().getSimpleName());        
        MongoUtil cc=SpringContextUtil.getApplicationContext().getBean(MongoUtil.class);
        cc.updateMog(event.getEntity());
    
    }
}

插一句,有一种情况:写的过程中,MYSQL正常,突然mongodb挂了。这样mysql事务还正常执行,正常触发过滤器是吧,mongdo不断的报错,是不是就造成mysql一直写,mongodb一些写不进去。我告诉你不会出现这种情况,因为hibernate给你控制了这种情况,当mongodb连接异常的时候,mysql也不正常工作。为什么?@Configuration 注解是在上一层,它出问题了初始化不过,MYSQL也暂停写。但是数据库挂这期间的写操作丢失。(任何一个库挂了,其他库都停止写,这样多库数据一致。挂了一个,其他的都不工作。挂的期间丢失操作,日志里人工处理,我们讲的分布式事务不包含因为宕机造成的数据丢失,但是保证了宕机时不产生一致性问题)

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值