当业务复杂后或者有新来的同事,不是那么的了解业务,压根不可能知道说我改了这个数据对其他那些索引有影响,所以这个方案还是有优化的空间。
荣耀黄金的方案是将所有的事件都统一为一个,然后在事件里加属性来区分修改的数据是哪里的。每个数据需要同步变更的索引都有自己的监听器,去监听这个统一的事件,这样对于发布者来说我只需要发送一个事件告诉你,我这边改数据了,你要不要消费,要不要更新索引我并不关心。
定义一个数据表发生修改的事件,代码如下:
public class TableUpdateEvent extends ApplicationEvent { private String table; private String id; public TableUpdateEvent(Object source, String id, String table) { super(source); this.id = id; this.table = table; } public String getId() { return id; } public String getTable() { return table; } }然后每个索引都需要消费这个事件,只需要关注这个索引中数据的来源表有没有变动,如果有变动则去刷新索引。
比如索引A的数据都是article表中过来的,所以只要是article表中的数据发生了变更,索引A都要做对应的处理,所以索引A的监听器只需要关注article表有没有修改即可。
@Component public class MyEventListener { private List<String> consumerTables = Arrays.asList("article"); @Async @EventListener public void onEvent(TableUpdateEvent event) { System.out.println(event.getId() + "\t" + event.getTable()); if (consumerTables.contains(event.getTable())) { System.out.println("消费自己关注的表数据变动,然后处理。。。"); } } }比如索引B的数据是从comment和comment_reply两个表中过来的,所以只要是comment和comment_reply两个表的数据发生了变更,索引B都需要做对应的处理,所以索引B的监听器只需要关注comment和comment_reply两个表有没有修改即可。
@Component public class MyEventListener2 { private List<String> consumerTables = Arrays.asList("comment", "comment_replay"); @Async @EventListener public void onEvent(TableUpdateEvent event) { System.out.println(event.getId() + "\t" + event.getTable()); if (consumerTables.contains(event.getTable())) { System.out.println("消费自己关注的表数据变动,然后处理。。。"); } } } 实现方案-尊贵铂金荣耀黄金的方案已经很完美了,代码解耦不说,使用者关注点也少了,不容易出错。
但还有一个致命的问题就是所有涉及到业务修改的方法中,得手动往外发送一个事件,从代码解耦的场景来说还残留了一点瑕疵,至少还是有那么一行代码来发送事件。
尊贵铂金的方案将完全解耦,不需要写代码的时候手动去发送事件。我们将通过订阅MySql的binlog来统一发送事件。
binlog是MySQL数据库的二进制日志,用于记录用户对数据库操作的SQL语句信息,MySQL的主从同步也是基于binlog来实现的,对于我们这种数据异构的场景再合适不过了。
binlog订阅的方式有很多种,开源的框架一般都是用canal来实现。
canal:https://github.com/alibaba/canal
如果你买的云数据库,像阿里云就有dts数据订阅服务,跟canal一样。
之后的方案图如下:
实现方案-永恒钻石没有什么方案和架构是永恒的,跟着业务的变更而演进,符合当前业务的需求才是王道。越后面考虑的东西越多,毕竟最后是要升级到最强王者的,哈哈。