因为这个功能,产品刚从医院出来,但我想再送他回去

前段时间遇到这么个事

产品和我说项目里的人员搜索功能他看着有点不对劲,说罢,用需要加需求的眼神看着我...

哥们虎躯一震...

搞了半天,原来是因为他在人员搜索框内填写部门名称,结果搜索器觉着他是傻子,没理他,所以他边哭喊着爸爸,边来找我

我说那地方本来就是填人名的呀,正常人都填人名...

他回复道,钉钉有啊,钉钉有的我们也要有,如果我们没有,那就是对像他这种有追求的产品职业操守上的侮辱...

我像看弱智一样看了他一会,然后道,“好吧 就为了你的节操...”

后来我查了下源码和数据发现,搜索的数据存储在ES里,但ES里的部门数据只有ID没有名称,所以面临的问题可能需要同步数据,从mysql同步到ES

可是问题是,如果只是同步数据的话还简单,但是同步数据之后需要维护的事情还有很多

就比如,如果当前人换部门了或者部门名称变了,在变更这些数据的时候同时都要考虑ES要怎么更新,这样会越来越繁琐

万一之后的需求有一项极复杂的骚修改...那真是恶心它儿子回家

这倒让我想起了之前的一件恶心事,也是和ES数据同步有关

倒不是问题有多恶心,而是没太看懂前人的代码,他的代码里没有ES的数据更新,但是在修改完mysql数据后,神奇的事情却发生了

我反复走了好几遍代码,拦截器也翻看了好几遍,都没有操作ES的地方,这确实让我挺懵的...

好巧不巧,那二货中午的时候给我发过来一个并夕夕友尽链接,以此为要挟下才只知道原来果然是魔法!

用的是阿里的一个中间件canal,功能确实比较神奇,它会伪装成mysql集群里的一个子节点,当主节点向子节点同步binlog日志的时候,canal可以解析binlog日志,然后发送一条消息到消息队列来同步es数据

具体来说呢,如此操作

Mysql

首先要有个mysql服务器,肯定有集群才有master和slave

然后在MySQL中需要创建一个用户,并授权

// 使用命令登录:mysql -u root -p
// 创建用户 用户名:canal 密码:Canal@123456
create user 'canal'@'%' identified by 'Canal@123456';
// 授权 *.*表示所有库
grant SELECT, REPLICATION SLAVE, REPLICATION CLIENT on *.* to 'canal'@'%' identified by 'Canal@123456';

下一步在MySQL配置文件my.cnf设置如下信息

[mysqld]
# 打开binlog
log-bin=mysql-bin
# 选择ROW(行)模式
binlog-format=ROW
# 配置MySQL replaction需要定义,不要和canal的slaveId重复
server_id=1

改了配置文件之后,重启MySQL,使用命令查看是否打开binlog模式:

show variables like 'log_bin'
//查看bin日志文件列表
show binary logs
//查看当前正在写入的binlog文件
show master status

canal

去官网下载页面进行下载:https://github.com/alibaba/canal/releases

解压canal.deployer-1.1.4.tar.gz,我们可以看到里面有四个文件夹 bin conf lib logs

在bin目录下找到startup.bat启动就可以了

java客户端操作

引入maven依赖

<dependency>
   <groupId>com.alibaba.otter</groupId>
   <artifactId>canal.client</artifactId>
   <version>1.1.4</version>
</dependency>

在CannalClient类使用Spring Bean的生命周期函数afterPropertiesSet():

@Component
public class CannalClient implements InitializingBean {

   private final static int BATCH_SIZE = 1000;

   @Override
   public void afterPropertiesSet() throws Exception {
       // 创建链接
       CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("127.0.0.1", 11111), "example", "", "");
       try {
           //打开链接
           connector.connect();
           //订阅全部表
           connector.subscribe(".*\\..*");
           //回滚到未进行ack的地方,下次fetch的时候,可以从最后一个没有ack的地方开始拿
           connector.rollback();
           while (true) {
               // 获取指定数量的数据
               Message message = connector.getWithoutAck(BATCH_SIZE);
               //获取批量ID
               long batchId = message.getId();
               //获取批量的数量
               int size = message.getEntries().size();
               //如果没有数据
               if (batchId == -1 || size == 0) {
                   try {
                       //线程休眠2秒
                       Thread.sleep(2000);
                  } catch (InterruptedException e) {
                       e.printStackTrace();
                  }
              } else {
                   //如果有数据,处理数据
                   printEntry(message.getEntries());
              }
               //进行 batch id 的确认。确认之后,小于等于此 batchId 的 Message 都会被确认。
               connector.ack(batchId);
          }
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           connector.disconnect();
      }
  }

   /**
    * 打印canal server解析binlog获得的实体类信息
    */
   private static void printEntry(List<Entry> entrys) {
       for (Entry entry : entrys) {
           if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {
               //开启/关闭事务的实体类型,跳过
               continue;
          }
           //RowChange对象,包含了一行数据变化的所有特征
           //比如isDdl 是否是ddl变更操作 sql 具体的ddl sql beforeColumns afterColumns 变更前后的数据字段等等
           RowChange rowChage;
           try {
               rowChage = RowChange.parseFrom(entry.getStoreValue());
          } catch (Exception e) {
               throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(), e);
          }
           //获取操作类型:insert/update/delete类型
           EventType eventType = rowChage.getEventType();
           //打印Header信息
           System.out.println(String.format("================》; binlog[%s:%s] , name[%s,%s] , eventType : %s",
                   entry.getHeader().getLogfileName(), entry.getHeader().getLogfileOffset(),
                   entry.getHeader().getSchemaName(), entry.getHeader().getTableName(),
                   eventType));
           //判断是否是DDL语句
           if (rowChage.getIsDdl()) {
               System.out.println("================》;isDdl: true,sql:" + rowChage.getSql());
          }
           //获取RowChange对象里的每一行数据,打印出来
           for (RowData rowData : rowChage.getRowDatasList()) {
               //删除语句
               if (eventType == EventType.DELETE) {
                   printColumn(rowData.getBeforeColumnsList());
                   //新增语句
              } else if (eventType == EventType.INSERT) {
                   printColumn(rowData.getAfterColumnsList());
                   //更新的语句
              } else {
                   //变更前的数据
                   System.out.println("------->; before");
                   printColumn(rowData.getBeforeColumnsList());
                   //变更后的数据
                   System.out.println("------->; after");
                   printColumn(rowData.getAfterColumnsList());
              }
          }
      }
  }

   private static void printColumn(List<Column> columns) {
       for (Column column : columns) {
           System.out.println(column.getName() + " : " + column.getValue() + "   update=" + column.getUpdated());
      }
  }
}

这样执行就可以了!

canal的好处在于对业务代码没有侵入,因为是基于监听binlog日志去进行同步数据的。实时性也能做到准实时,是很多企业一种比较常见的数据同步的方案

以上

原文地址:https://cloud.tencent.com/developer/article/2097873

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340