群里好几位同学问 pt-table-checksum 3.0.4, 主从两个表数据是不一致,为啥检测不出来?前段时间自己也测试过,只是没整理成随笔^_-

一、基本环境

VMware10.0+CentOS6.9+MySQL5.7.19

ROLE HOSTNAME BASEDIR DATADIR IP PORT
Master ZST1 /usr/local/mysql /data/mysql/mysql3306/data 192.168.85.132 3306
Slave ZST2 /usr/local/mysql /data/mysql/mysql3306/data 192.168.85.133 3306

基于Row+Gtid搭建的一主一从复制结构:Master->Slave

二、构造差异数据

借助样例数据库sakila做测试

# 主库flush logs
mydba@192.168.85.132,3306 [sakila]> flush logs; # 主库开启general_log
[root@ZST1 ~]# rm -rf /data/mysql/mysql3306/data/mysql-general.log
mydba@192.168.85.132,3306 [sakila]> set global general_log_file='/data/mysql/mysql3306/data/mysql-general.log';
mydba@192.168.85.132,3306 [sakila]> set global general_log =1;
mydba@192.168.85.132,3306 [sakila]> show variables like 'general_log%'; # 从库修改部分数据,造成不一致
mydba@192.168.85.133,3306 [sakila]> delete from sakila.actor where actor_id<=3; # 外键约束删除失败
mydba@192.168.85.133,3306 [sakila]> update sakila.actor set last_name=first_name where actor_id<=3;
# 主库sakila.actor数据
mydba@192.168.85.132,3306 [sakila]> select * from sakila.actor limit 3;
+----------+------------+-----------+---------------------+
| actor_id | first_name | last_name | last_update |
+----------+------------+-----------+---------------------+
| 1 | PENELOPE | GUINESS | 2006-02-15 04:34:33 |
| 2 | NICK | WAHLBERG | 2006-02-15 04:34:33 |
| 3 | ED | CHASE | 2006-02-15 04:34:33 |
+----------+------------+-----------+---------------------+
# 从库sakila.actor数据
mydba@192.168.85.133,3306 [sakila]> select * from sakila.actor limit 3;
+----------+------------+-----------+---------------------+
| actor_id | first_name | last_name | last_update |
+----------+------------+-----------+---------------------+
| 1 | PENELOPE | PENELOPE | 2017-11-08 09:54:10 |
| 2 | NICK | NICK | 2017-11-08 09:54:10 |
| 3 | ED | ED | 2017-11-08 09:54:10 |
+----------+------------+-----------+---------------------+

从库修改部分数据,造成主从不一致

三、pt-table-checksum

3.1、检测数据是否一致

pt-table-checksum可以在任何机器上执行,只要它能连接到Master就行。我是在从库执行,最后的参数指定到主库就行

# 运行pt-table-checksum
[root@ZST2 ~]# pt-table-checksum --nocheck-binlog-format --nocheck-replication-filters --recursion-method=hosts --replicate=sakila.checksums --databases=sakila --tables=actor,city --host=192.168.85.132 --port= --user=mydba --password=mysql5719
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
-08T09:: 0.075 sakila.actor
-08T09:: 0.034 sakila.city
[root@ZST2 ~]#

DIFFS=0表示没有差异数据。实际上主从数据不一致,这里却没有检测出来~
主库得到的general-log、binlog拷贝到其他文件夹,方便后续分析

# 拷贝general-log、binlog文件
[root@ZST1 ~]# cp /data/mysql/mysql3306/data/mysql-general.log /data/backup/mysql-general.log.ptchecksum3306
[root@ZST1 ~]# cp /data/mysql/mysql3306/logs/mysql-bin. /data/backup/mysql-bin..ptchecksum3306

3.2、查看general-log

[root@ZST1 ~]# cat /data/backup/mysql-general.log.ptchecksum3306
/usr/local/mysql/bin/mysqld, Version: 5.7.-log (MySQL Community Server (GPL)). started with:
Tcp port: Unix socket: /tmp/mysql3306.sock
Time Id Command Argument
--08T01::.750917Z Connect mydba@192.168.85.133 on using TCP/IP
--08T01::.751564Z Query set autocommit=
--08T01::.752220Z Query SHOW VARIABLES LIKE 'innodb\_lock_wait_timeout'
--08T01::.757028Z Query SET SESSION innodb_lock_wait_timeout=
--08T01::.757521Z Query SHOW VARIABLES LIKE 'wait\_timeout'
--08T01::.760950Z Query SET SESSION wait_timeout=
--08T01::.761400Z Query SELECT @@SQL_MODE
--08T01::.761772Z Query SET @@SQL_QUOTE_SHOW_CREATE = /*!40101, @@SQL_MODE='NO_AUTO_VALUE_ON_ZERO,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'*/
--08T01::.762140Z Query SELECT @@server_id /*!50038 , @@hostname*/
--08T01::.762475Z Query SELECT @@SQL_MODE
--08T01::.762772Z Query SET SQL_MODE=',NO_AUTO_VALUE_ON_ZERO,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'
--08T01::.763098Z Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
--08T01::.763504Z Query SHOW VARIABLES LIKE 'wsrep_on'
--08T01::.766949Z Query SELECT @@SERVER_ID
--08T01::.767470Z Query SHOW SLAVE HOSTS
--08T01::.787329Z Query SHOW VARIABLES LIKE 'wsrep_on'
--08T01::.790712Z Query SELECT @@SERVER_ID
--08T01::.794388Z Query SHOW VARIABLES LIKE 'wsrep_on'
--08T01::.797637Z Query SELECT @@SERVER_ID
--08T01::.801356Z Query SHOW DATABASES LIKE 'sakila'
--08T01::.802164Z Query CREATE DATABASE IF NOT EXISTS `sakila` /* pt-table-checksum */
--08T01::.802951Z Query USE `sakila`
--08T01::.803300Z Query SHOW TABLES FROM `sakila` LIKE 'checksums'
--08T01::.806111Z Query CREATE TABLE IF NOT EXISTS `sakila`.`checksums` (
db CHAR() NOT NULL,
tbl CHAR() NOT NULL,
chunk INT NOT NULL,
chunk_time FLOAT NULL,
chunk_index VARCHAR() NULL,
lower_boundary TEXT NULL,
upper_boundary TEXT NULL,
this_crc CHAR() NOT NULL,
this_cnt INT NOT NULL,
master_crc CHAR() NULL,
master_cnt INT NULL,
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (db, tbl, chunk),
INDEX ts_db_tbl (ts, db, tbl)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
--08T01::.825908Z Query SHOW GLOBAL STATUS LIKE 'Threads_running'
--08T01::.828793Z Query SELECT CONCAT(@@hostname, @@port)
--08T01::.844001Z Query SELECT CRC32('test-string')
--08T01::.844518Z Query SELECT CRC32('a')
--08T01::.845025Z Query SELECT CRC32('a')
--08T01::.845517Z Query SHOW VARIABLES LIKE 'wsrep_on'
--08T01::.849157Z Query SHOW DATABASES
--08T01::.850038Z Query SHOW /*!50002 FULL*/ TABLES FROM `sakila`
--08T01::.851486Z Query /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */
--08T01::.851943Z Query USE `sakila`
--08T01::.852408Z Query SHOW CREATE TABLE `sakila`.`actor`
--08T01::.853034Z Query /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */
--08T01::.854092Z Query EXPLAIN SELECT * FROM `sakila`.`actor` WHERE =
--08T01::.857374Z Query USE `sakila`
--08T01::.857990Z Query DELETE FROM `sakila`.`checksums` WHERE db = 'sakila' AND tbl = 'actor'
--08T01::.877626Z Query USE `sakila`
--08T01::.878413Z Query EXPLAIN SELECT COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `actor_id`, convert(`first_name` using utf8mb4), convert(`last_name` using utf8mb4), UNIX_TIMESTAMP(`last_update`))) AS UNSIGNED)), , )), ) AS crc FROM `sakila`.`actor` /*explain checksum table*/
--08T01::.879347Z Query REPLACE INTO `sakila`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT 'sakila', 'actor', '', NULL, NULL, NULL, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `actor_id`, convert(`first_name` using utf8mb4), convert(`last_name` using utf8mb4), UNIX_TIMESTAMP(`last_update`))) AS UNSIGNED)), , )), ) AS crc FROM `sakila`.`actor` /*checksum table*/
--08T01::.881166Z Query SHOW WARNINGS
--08T01::.881764Z Query SELECT this_crc, this_cnt FROM `sakila`.`checksums` WHERE db = 'sakila' AND tbl = 'actor' AND chunk = ''
--08T01::.897051Z Query UPDATE `sakila`.`checksums` SET chunk_time = '0.001821', master_crc = '6816983c', master_cnt = '' WHERE db = 'sakila' AND tbl = 'actor' AND chunk = ''
--08T01::.900914Z Query SHOW GLOBAL STATUS LIKE 'Threads_running'
--08T01::.930534Z Query /*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, @@SQL_MODE := '', @OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, @@SQL_QUOTE_SHOW_CREATE := 1 */
--08T01::.931387Z Query USE `sakila`
--08T01::.932194Z Query SHOW CREATE TABLE `sakila`.`city`
--08T01::.933399Z Query /*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, @@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */
--08T01::.935136Z Query EXPLAIN SELECT * FROM `sakila`.`city` WHERE =
--08T01::.940169Z Query USE `sakila`
--08T01::.941026Z Query DELETE FROM `sakila`.`checksums` WHERE db = 'sakila' AND tbl = 'city'
--08T01::.942010Z Query USE `sakila`
--08T01::.943012Z Query EXPLAIN SELECT COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `city_id`, convert(`city` using utf8mb4), `country_id`, UNIX_TIMESTAMP(`last_update`))) AS UNSIGNED)), , )), ) AS crc FROM `sakila`.`city` /*explain checksum table*/
--08T01::.945033Z Query REPLACE INTO `sakila`.`checksums` (db, tbl, chunk, chunk_index, lower_boundary, upper_boundary, this_cnt, this_crc) SELECT 'sakila', 'city', '', NULL, NULL, NULL, COUNT(*) AS cnt, COALESCE(LOWER(CONV(BIT_XOR(CAST(CRC32(CONCAT_WS('#', `city_id`, convert(`city` using utf8mb4), `country_id`, UNIX_TIMESTAMP(`last_update`))) AS UNSIGNED)), , )), ) AS crc FROM `sakila`.`city` /*checksum table*/
--08T01::.960088Z Query SHOW WARNINGS
--08T01::.960938Z Query SELECT this_crc, this_cnt FROM `sakila`.`checksums` WHERE db = 'sakila' AND tbl = 'city' AND chunk = ''
--08T01::.961674Z Query UPDATE `sakila`.`checksums` SET chunk_time = '0.015889', master_crc = '4d700c4', master_cnt = '' WHERE db = 'sakila' AND tbl = 'city' AND chunk = ''
--08T01::.964712Z Query SHOW GLOBAL STATUS LIKE 'Threads_running'
--08T01::.972503Z Quit
[root@ZST1 ~]#

general-log逻辑
• 设置SESSION选项
• 创建checksums数据表
• 针对每一张需要check的表执行下面操作
  • DELETE:从checksums表中删除sakila的记录
  • EXPLAIN:分析计算sakila的this_cnt,this_crc的执行计划
  • REPLACE INTO:计算sakila的this_cnt,this_crc
  • UPDATE:使用this_cnt,this_crc更新master_crc,master_cnt
在主库上这些以SQL语句的形式执行,且执行时没有设置SESSION的日志格式为STATEMENT,主库的binlog_format='ROW',所以binlog里记录的是语句的最终执行结果(具体的数值,而非SQL语句)

3.3、查看binlog

[root@ZST1 ~]# mysqlbinlog -v --base64-output=decode-rows /data/backup/mysql-bin..ptchecksum3306

binlog逻辑是:首先创建checksums数据表,然后delete->insert->update checksums  具体数值
主库上最后一个update语句

SELECT this_crc, this_cnt FROM `sakila`.`checksums` WHERE db = 'sakila' AND tbl = 'actor' AND chunk = ''
UPDATE `sakila`.`checksums` SET chunk_time = '0.001821', master_crc = '6816983c', master_cnt = '' WHERE db = 'sakila' AND tbl = 'actor' AND chunk = ''

在binlog体现为(原封不动应用到从库)

[root@ZST1 ~]# mysqlbinlog -v --base64-output=decode-rows /data/backup/mysql-bin..ptchecksum3306
...
COMMIT/*!*/;
# at
# :: server id end_log_pos CRC32 0x16bf0702 GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= '8ab82362-9c37-11e7-a858-000c29c1025c:575'/*!*/;
# at
# :: server id end_log_pos CRC32 0xee6b7639 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x589cc01f Table_map: `sakila`.`checksums` mapped to number
# at
# :: server id end_log_pos CRC32 0xc0604f63 Update_rows: table id flags: STMT_END_F
### UPDATE `sakila`.`checksums`
### WHERE
### @='sakila'
### @='actor'
### @=
### @=NULL
### @=NULL
### @=NULL
### @=NULL
### @='6816983c'
### @=
### @=NULL
### @=NULL
### @=
### SET
### @='sakila'
### @='actor'
### @=
### @=0.001821
### @=NULL
### @=NULL
### @=NULL
### @='6816983c'
### @=
### @='6816983c'
### @=
### @=
# at
# :: server id end_log_pos CRC32 0x1f197fe6 Xid =
COMMIT/*!*/;
# at

也就是说从库不会去计算所谓的CRC32,它直接完整copy主库的checksums的所有内容

3.4、如何解决

个人认为只有在statement格式下才能进行,因为两边要计算CRC32,计算完后再把主上的master_crc、master_cnt更新到从库,最后在从库对比master和this相关列。pt-table-checksum 3.0.4在执行时缺少SET @@binlog_format='STATEMENT',建议不要使用。
有一种很挫的方法,仅仅是为了看差异结果(生产环境勿用),执行pt-table-checksum前,在主上 set global binlog_format='STATEMENT';

# 主库修改binlog_format为statement
mydba@192.168.85.132, [sakila]> set global binlog_format='STATEMENT'; # 从库运行pt-table-checksum
[root@ZST2 ~]# pt-table-checksum --nocheck-binlog-format --nocheck-replication-filters --recursion-method=hosts --replicate=sakila.checksums --databases=sakila --tables=actor,city --host=192.168.85.132 --port= --user=mydba --password=mysql5719
TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE
-08T12:: 0.015 sakila.actor
-08T12:: 0.024 sakila.city
[root@ZST2 ~]#

DIFFS=1,说明sakila.actor表存在差异

# 差异信息
mydba@192.168.85.133,3306 [sakila]> SELECT db,tbl,SUM(this_cnt) AS total_rows,COUNT(*) AS chunks
FROM sakila.checksums
WHERE (master_cnt <> this_cnt OR master_crc <> this_crc OR ISNULL(master_crc) <> ISNULL(this_crc))
GROUP BY db,tbl;
+--------+-------+------------+--------+
| db | tbl | total_rows | chunks |
+--------+-------+------------+--------+
| sakila | actor | 200 | 1 |
+--------+-------+------------+--------+
1 row in set (0.00 sec)

主要就是查看master_cnt、this_cnt和master_crc、this_crc

四、pt-table-sync

4.1、修复数据不一致

前面已经检测出主从数据不一致,下面使用pt-table-sync修复数据

# 打印命令
[root@ZST2 ~]# pt-table-sync --replicate=sakila.checksums --sync-to-master h=192.168.85.133,u=mydba,p=mysql5719,P= --databases=sakila --charset=utf8 --print
REPLACE INTO `sakila`.`actor`(`actor_id`, `first_name`, `last_name`, `last_update`) VALUES ('', 'PENELOPE', 'GUINESS', '2006-02-15 04:34:33') /*percona-toolkit src_db:sakila src_tbl:actor src_dsn:A=utf8,P=3306,h=192.168.85.132,p=...,u=mydba dst_db:sakila dst_tbl:actor dst_dsn:A=utf8,P=3306,h=192.168.85.133,p=...,u=mydba lock:1 transaction:1 changing_src:sakila.checksums replicate:sakila.checksums bidirectional:0 pid:3365 user:uest host:ZST2*/;
REPLACE INTO `sakila`.`actor`(`actor_id`, `first_name`, `last_name`, `last_update`) VALUES ('', 'NICK', 'WAHLBERG', '2006-02-15 04:34:33') /*percona-toolkit src_db:sakila src_tbl:actor src_dsn:A=utf8,P=3306,h=192.168.85.132,p=...,u=mydba dst_db:sakila dst_tbl:actor dst_dsn:A=utf8,P=3306,h=192.168.85.133,p=...,u=mydba lock:1 transaction:1 changing_src:sakila.checksums replicate:sakila.checksums bidirectional:0 pid:3365 user:uest host:ZST2*/;
REPLACE INTO `sakila`.`actor`(`actor_id`, `first_name`, `last_name`, `last_update`) VALUES ('', 'ED', 'CHASE', '2006-02-15 04:34:33') /*percona-toolkit src_db:sakila src_tbl:actor src_dsn:A=utf8,P=3306,h=192.168.85.132,p=...,u=mydba dst_db:sakila dst_tbl:actor dst_dsn:A=utf8,P=3306,h=192.168.85.133,p=...,u=mydba lock:1 transaction:1 changing_src:sakila.checksums replicate:sakila.checksums bidirectional:0 pid:3365 user:uest host:ZST2*/;
[root@ZST2 ~]# # 执行命令
[root@ZST2 ~]# pt-table-sync --replicate=sakila.checksums --sync-to-master h=192.168.85.133,u=mydba,p=mysql5719,P= --databases=sakila --charset=utf8 --execute
REPLACE statements on sakila.actor can adversely affect child table `sakila`.`film_actor` because it has an ON UPDATE CASCADE foreign key constraint. See --[no]check-child-tables in the documentation for more information. --check-child-tables error while doing sakila.actor on 192.168.85.133
[root@ZST2 ~]#

--execute就是执行打印出来的命令,REPLACE INTO实际对应delete、insert操作,由于外键约束delete失败(构造差异数据时就尝试过delete),修复不成功。
pt-table-checksum及pt-table-sync详细说明请参考:pt-table-checksum解读使用pt-table-checksum及pt-table-sync校验复制一致性

pt-table-checksum 3.0.4检测不出主从差异数据的更多相关文章

  1. pt-table-checksum检测不出主从差异处理

    几个月前写过pt-table-checksum 3.0.4检测不出主从差异数据,当时的解决方案是使用旧版本,另一个挫方法是自行设置binlog_format='STATEMENT'.现在已经发布到3. ...

  2. NXP ARM Vector Table CheckSum

    Signature Creator for NXP Cortex-M Devices Algorithm for creating the checksum The reserved Cortex-M ...

  3. 从客户端(ctl00$ContentPlaceHolder1$result="<?xml version="1.0" ...")中检测到有潜在危险的 Request.Form 值。

    ylbtech-Error-WebForm:从客户端(ctl00$ContentPlaceHolder1$result="<?xml version="1.0" . ...

  4. 从 Delta 2.0 开始聊聊我们需要怎样的数据湖

    盘点行业内近期发生的大事,Delta 2.0 的开源是最让人津津乐道的,尤其在 Databricks 官宣 delta2.0 时抛出了下面这张性能对比,颇有些引战的味道. 虽然 Databricks ...

  5. Redis哨兵模式主从同步不可以绑定127.0.0.1或者0.0.0.0,不然无法进行主从同步

    Redis哨兵模式主从同步不可以绑定127.0.0.1或者0.0.0.0,不然无法进行主从同步,一定要绑定内网IP,而对于跨机房的问题,可以使用iptables进行nat转发来解决.

  6. pytorch入门2.0构建回归模型初体验(数据生成)

    pytorch入门2.x构建回归模型系列: pytorch入门2.0构建回归模型初体验(数据生成) pytorch入门2.1构建回归模型初体验(模型构建) pytorch入门2.2构建回归模型初体验( ...

  7. 痞子衡嵌入式:kFlashFile v1.0 - 一个基于Flash的掉电数据存取方案

    大家好,我是痞子衡,是正经搞技术的痞子.今天给大家带来的是痞子衡的个人小项目 - kFlashFile. 痞子衡最近在参与一个基于 i.MXRT1170 的项目,项目有个需求,需要在 Flash 里实 ...

  8. ISAPI和CGI限制中没有ASP.NET v4.0 ; vS2013检测到在集成的托管管道模式下不适用的 ASP.NET 设置。

    统确实自带了ASP.NET v4.0,但是ISAPI中没有这个选项,导致服务器开不起来 解决方法如下: 1.确保安装IIS时确实安装了ASP.NET,如果没有的话,勾上重新装一下,一般出现404.2时 ...

  9. spring3.0框架检测方法运行时间测试(转)

    主要利用了Spring AOP 技术,对想要统计的方法进行横切处理,方法执行前开始计时,方法执行后停止计时,得到计时方法就是该方法本次消耗时间. 步骤: 首先编写自己的Interceptor类来实现M ...

随机推荐

  1. 桌面输入法评测报告 之 搜狗拼音输入法vs必应拼音输入法

    输入法是电脑用户不可或缺的软件,它几乎无时无刻不陪伴在使用者的身旁.一个优秀的输入法,应该满足客户对使用体验以及效率的需求.我们小队的任务便是对当今最为常用的两种输入法: 搜狗拼音输入法和必应拼音输入 ...

  2. Linux读书笔记第三、四章

    第三章 主要内容: 进程和线程 进程的生命周期 进程的创建 进程的终止 1. 进程和线程 进程和线程是程序运行时状态,是动态变化的,进程和线程的管理操作(比如,创建,销毁等)都是有内核来实现的. Li ...

  3. Linux内核分析——第四周学习笔记20135308

    第四周 扒开系统调用的“三层皮” 一.内核.用户态和中断 (一)如何区分用户态.内核态 1.一般现在的CPU有几种不同的指令执行级别 ①在高级别的状态下,代码可以执行特权指令,访问任意的物理地址,这种 ...

  4. 20135316王剑桥Linux内核学习笔记第三周

    20135316王剑桥 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC 1000029000 三个法宝:存储程序计算机.函数调 ...

  5. # linux读书笔记(3章)

    linux读书笔记(3章) 标签(空格分隔): 20135328陈都 第三章 进程管理 3.1 进程 进程就是处于执行期的程序(目标码存放在某种存储介质上).但进程并不仅仅局限于一段可执行程序代码( ...

  6. Android TextView中图文混排设置行间距导致高度不一致问题解决

    最近项目中需要实现一个评论带表情的功能,刚开始一切顺利,非常easy,突然有一天发现文字跟表情混排的时候,TextView中图文高度不一致,excuse...什么鬼,之前明明测试过图文混排,不存在这个 ...

  7. 用node编写cli工具

    cli是command-line interface的缩写,即命令行工具,常用的vue-cli, create-react-app, express-generator 等都是cli工具. 本文以自己 ...

  8. SVN Update Error: Please execute the 'Cleanup' command

    尝试用下面两种方法 svn clean up 中有一个选项break lock勾选上 把对应的文件来里的.svn里面的lock文件删除. svn local delete, incoming dele ...

  9. 【设计模式】—— 中介者模式Mediator

    前言:[模式总览]——————————by xingoo 模式意图 使用一个中介的对象,封装一组对象之间的交互,这样这些对象就可以不用彼此耦合. 这个中介者常常起着中间桥梁的作用,使其他的对象可以利用 ...

  10. P3254 圆桌问题

    题目链接 非常简单的一道网络流题 我们发现每个单位的人要坐到不同餐桌上,那也就是说每张餐桌上不能有同一单位的人.这样的话,我们对于每个单位向每张餐桌连一条边权为1的边,表示同一餐桌不得有相同单位的人. ...