前提

上周遇到次奇葩的同步错误,error 1048 , 看似是简单的not null导致,但是为什么master可以执行,slave不行呢?为什么5.1的slave可以,5.6的slave不行呢? 带着很多疑问,准备来一窥究竟

[ERROR] Slave SQL: Error 'Column 'type_id' cannot be null' on query. Default database: ''. Query: 'insert into if_dw_stats.da_upload_nh_score_rank_result(city_id,city_name,comm_id,region_name,paid,comm_name_nh,region_id_num,region_id,subregion_id_num,subregion_id,vcuv,vcuv_z,call_vcuv,call_vcuv_z,orders_vcuv,orders_vcuv_z,peitao,peitao_z,result_score,rank,type_id,type_name,pinyin,cal_dt) values (N), 其中N>9000;

这里总结一下我遇到过的错误,分三种情况,虽然都是由于null引起,但是1048才是重点。

timestamp字段类型,为什么master执行成功,同步到slave报错?

int字段类型,5.1(master)

int字段类型,5.6(master)

接下来,开始进入主题

场景一

explicit_defaults_for_timestamp timestamp注意事项

* DB架构: Master(5.1)

* 表结构如下 :

dbadmin:abc> desc lc_time;

+-------+-----------+------+-----+-------------------+-----------------------------+

| Field | Type | Null | Key | Default | Extra |

+-------+-----------+------+-----+-------------------+-----------------------------+

| id | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |

+-------+-----------+------+-----+-------------------+-----------------------------+

1 row in set (0.00 sec)

* master

dbadmin:abc> select @@global.explicit_defaults_for_timestamp;

+------------------------------------------+

| @@global.explicit_defaults_for_timestamp |

+------------------------------------------+

| 0 |

+------------------------------------------+

1 row in set (0.00 sec)

dbadmin:abc> insert into lc_time values(null);

Query OK, 1 row affected (0.02 sec)

dbadmin:abc> select * from lc_time;

+---------------------+

| id |

+---------------------+

| 2014-11-25 13:02:14 |

+---------------------+

1 row in set (0.00 sec)

*slave

dbadmin:abc> select @@global.explicit_defaults_for_timestamp;

+------------------------------------------+

| @@global.explicit_defaults_for_timestamp |

+------------------------------------------+

| 1 |

+------------------------------------------+

1 row in set (0.00 sec)

dbadmin:abc> insert into lc_time values(null);

ERROR 1048 (23000): Column 'id' cannot be null

结论:master上explicit_defaults_for_timestamp=0,slave上explicit_defaults_for_timestamp=1,会出现这种错误。

解决方案:

保证master和slave explicit_defaults_for_timestamp 一致。

前端过滤掉null。

场景二

* DB架构

master(5.1)

|

-------------------------------------

| |

slave A(5.1) slave B(5.6)

* 表结构

dbadmin:abc> show create table abc;

+-------+-----------------------------------------------------------------------------------------------------------------------------+

| Table | Create Table |

+-------+-----------------------------------------------------------------------------------------------------------------------------+

| abc | CREATE TABLE `abc` (

`id` int(11) DEFAULT NULL,

`id2` int(11) NOT NULL DEFAULT '6'

) ENGINE=InnoDB DEFAULT CHARSET=utf8 |

+-------+-----------------------------------------------------------------------------------------------------------------------------+

1 row in set (0.00 sec)

* 核心参数: master 和 slave A,B 的sql_mode 都是 '';

* 症状:在master上执行一条SQL语句 insert into abc values(1,0),(1,null);

结果 Slave A 正常, Slave B 报error 1048,Error 'Column 'id2' cannot be null' on query, 这是为什么呢?

Question1:为什么insert into abc values(1,null)失败?insert into abc values(1,0),(1,null);成功?

Question2:为什么5.1 slave可以,5.6slave 不行?

Question3:手动去slave B上执行同样的insert,为什么可以执行成功?

如果你已经知道为什么,可以忽略下面的分析。

* 分析:

细心的读者已经发现,第一个问题的答案已经在sql_mode链接中。接下来,测试过程中发现:insert into abc values(1,0),(1,null); 在sql_mode=''的时候,不管是5.1还是5.6都会成功执行。那么问题只有一个,sql_mode出了问题。查看master binlog后发现:在insert语句之前,多了这个可以执行的注释:SET @@session.sql_mode=2097152。我们来看看:

dbadmin:abc> SET @@session.sql_mode=2097152;

Query OK, 0 rows affected (0.00 sec)

dbadmin:abc> select @@session.sql_mode;

+---------------------+

| @@session.sql_mode |

+---------------------+

| STRICT_TRANS_TABLES |

+---------------------+

1 row in set (0.00 sec)

这下,似乎发现了蛛丝马迹,那么问题又来了。

SET @@session.sql_mode=2097152; 从何而来?是程序写的?还是mysql自带的?

经过一番折腾,定位到此SQL来自java jdbc 。

以下代码摘自 java ConnectionIMPL.java

private void setupServerForTruncationChecks() throws SQLException {

if (getJdbcCompliantTruncation()) {

if (versionMeetsMinimum(5, 0, 2)) {

String currentSqlMode =

this.serverVariables.get("sql_mode");

boolean strictTransTablesIsSet = StringUtils.indexOfIgnoreCase(currentSqlMode, "STRICT_TRANS_TABLES") != -1;

if (currentSqlMode == null ||

currentSqlMode.length() == 0 || !strictTransTablesIsSet) {

StringBuffer commandBuf = new StringBuffer("SET sql_mode='");

if (currentSqlMode != null && currentSqlMode.length() > 0) {

commandBuf.append(currentSqlMode);

commandBuf.append(",");

}

commandBuf.append("STRICT_TRANS_TABLES'");

execSQL(null, commandBuf.toString(), -1, null,

DEFAULT_RESULT_SET_TYPE,

DEFAULT_RESULT_SET_CONCURRENCY, false,

this.database, null, false);

setJdbcCompliantTruncation(false); // server's handling this for us now

} else if (strictTransTablesIsSet) {

// We didn't set it, but someone did, so we piggy back on it

setJdbcCompliantTruncation(false); // server's handling this for us now

}

}

}

}

大致的意思就是:如果sql_mode = ‘’,那么java会调高sql_mode的级别,commandBuf.append("STRICT_TRANS_TABLES'");

ok,这下我们已经知道此set来自java,那么问题又来了。即便设置STRICT_TRANS_TABLES,要出问题,master就会报错了,为啥master是好的,Slave A是好的,却Slave B 同步出错呢?

结果已经很明显,因为Slave B是5.6。说的明显一点就是:

在严格模式下,5.1中可以执行,但是5.6不行,这应该算是5.6安全方面的新特性么?

有兴趣的同学可以自己测试下。

解决方案

配置java或者修改java源码,让其不要更改mysql的sql_mode

临时解决方案: insert ignore xxx;

sql_mode的规范。

场景三

来自case when的奇葩错误

* DB架构 Master(5.6)

* sql_mode 都是'';

* 报错如下:

Replicate_Wild_Ignore_Table: mysql.%,test.%

Last_Errno: 1048

Last_Error: Error 'Column 'referer' cannot be null' on query. Default database: 'action_db'. Query: 'insert into oplogin_log(`cityId`,`userId`,`userName`,`uri

`,`referer`,`logType`,`logDate`,`ip`,`status`)

values('','','kyqxmxyt','/login.php?rtn=1','http://xx.com:80/login.php?rtn=' RLIKE (SELECT (CASE WHEN (ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(schema_na

me)) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),1,1))>50) THEN 0x687474703a2f2f6f70746f6f6c732e616e6a756b652e636f6d3a38302f6c6f67696e2e7068703f72746e3d ELSE 0x28 END)) AND 'ae

WZ'='aeWZ','1','1416020259','114.242.250.192','2') #v1:checklogin@login.php (15) 1416020259'

这条奇葩且牛B的SQL,我来稍微翻译一下,如果INFORMATION_SCHEMA.SCHEMATA 去重后,得到的库名的第一个字符如果是1,返回0,否则返回 null。

将这种SQL稍微转换成简单一点的:

master:abc> desc abc;

+-------+---------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+-------+---------+------+-----+---------+-------+

| id | int(11) | YES | | NULL | |

| id2 | int(11) | NO | | 6 | |

+-------+---------+------+-----+---------+-------+

2 rows in set (0.00 sec)

master:abc> select * from abc;

+------+-----+

| id | id2 |

+------+-----+

| 1 | 0 |

| 1 | 0 |

| 2 | 0 |

| 2 | 0 |

| 1 | 1 |

| 1 | 0 |

+------+-----+

6 rows in set (0.00 sec)

master:abc> select * from lc;

Empty set (0.00 sec)

master:abc> insert into abc values('1', case when (select count(*) from lc) < 1 then 1 else NULL end );

Query OK, 1 row affected (0.00 sec)

查看master的binlog如下:

*binlog*

# at 1109

#141125 12:44:51 server id 101082106 end_log_pos 1271 CRC32 0x9ec0ca94 Query thread_id=28 exec_time=0 error_code=0

SET TIMESTAMP=1416890691/*!*/;

insert into abc values('1', case when (select count(*) from lc) < 1 then 1 else NULL end )

/*!*/;

slave:abc> select * from abc;

+------+-----+

| id | id2 |

+------+-----+

| 1 | 0 |

| 1 | 0 |

| 2 | 0 |

| 2 | 0 |

| 1 | 0 |

| 1 | 0 |

+------+-----+

6 rows in set (0.00 sec)

slave:abc> select * from lc;

+------+

| id |

+------+

| 1 |

| 2 |

| 3 |

+------+

3 rows in set (0.00 sec)

*slave status*

Last_SQL_Errno: 1048

Last_SQL_Error: Error 'Column 'id2' cannot be null' on query. Default database: 'abc'. Query: 'insert into abc values('1', case when (select count(*) from lc) < 1 then 1 else NULL end )'

结论

最终binlog并不是RBR,所以会报错。

临时解决方案: insert ignore xxx. 然后再用pt-table-checksum && pt-sync等修复。

禁止case when语句。

mysql 1048_MySQL Error 1048 奇遇记-阿里云开发者社区相关推荐

  1. 阿里云rds mysql 并发_干货 | 浅析RDS MySQL 8.0语句级并发控制-阿里云开发者社区

    背景 为了应对突发的数据库请求流量.资源消耗过载的语句访问.SQL 访问模型的变化, 并保持 MySQL 实例持续稳定运行,阿里云RDS for MySQL 8.0所采用的AliSQL分支设计了基于语 ...

  2. mysql derived2_MySQL · 新特性分析 · 5.7中Derived table变形记-阿里云开发者社区

    Derived table实际上是一种特殊的subquery,它位于SQL语句中FROM子句里面,可以看做是一个单独的表.MySQL5.7之前的处理都是对Derived table进行Material ...

  3. openSearch支持mysql版本_OpenSearch 使用二三事-阿里云开发者社区

    先交代下我们的使用场景.我们是把一张分库分表的逻辑表导入了 OpenSearch,建立了相关索引,供后台管理界面查询使用.最近在使用的过程中遇到了几个问题.记之. 查询的数据最多只有 5000 条 我 ...

  4. 阿里云mysql事件启动_mysql 启动事件-阿里云开发者社区

    事件调度器有时也可称为临时触发器(temporal triggers),因为事件调度器是基于特定时间周期触发来执行某些任务,而触发器(Triggers)是基于某个表所产生的事件触发的,区别也就在这里. ...

  5. mysql latid1_mysql数据库触发器详解-阿里云开发者社区

    1. 引言 Mysql的触发器和存储过程一样,都是嵌入到mysql的一段程序.触发器是mysql5新增的功能,目前线上凤巢系统.北斗系统以及哥伦布系统使用的数据库均是mysql5.0.45版本,很多程 ...

  6. ossim mysql密码_OSSIM 4.1安装-阿里云开发者社区

    OSSIM 4.1安装 在今年出版的畅销书<Unix/Linux网络日志分析与流量监控>一书中主要为大家介绍了开源安全运维利器-OSSIM,很多同行对Ossim表示了极大关注,纷纷来信咨询 ...

  7. liunx导出mysql慢查询日志查看_查看 MySQL 慢查询日志文件-问答-阿里云开发者社区-阿里云...

    查看 MySQL 是否启用了慢 SQL 查询: 查看慢 SQL 日志是否启用. mysql> show variables like 'log_slow_queries'; +--------- ...

  8. 万网mysql中文乱码_Linux下MySQL出现乱码的解决方法-阿里云开发者社区

    开发环境 cent os 6.5 mysql springboot duird 故障描述 本地开发环境没有任何问题,上传到服务器后发现提交的表单内容只要是中文直接变成 ??? 解决方式 错误尝试: 一 ...

  9. mysql的程序怎么升级成mysqli_如何将mysql更改为mysqli?-问答-阿里云开发者社区-阿里云...

    首先要做的可能是将每个mysql_函数调用都替换为等效函数mysqli_,至少在您愿意使用过程式API的情况下-考虑到您已经有一些基于MySQL API的代码,这将是更简单的方法是一种程序性的. 为了 ...

  10. centos mysql 设置_CentOS下MySQL安装后配置和设置-阿里云开发者社区

    CentOS下MySQL安装后配置和设置: 1:安装完成路径: 1.数据库目录 /var/lib/mysql/ 2.配置文件 /usr/share/mysql(mysql.server命令及配置文件) ...

最新文章

  1. PyTorch框架:(2)使用PyTorch框架构建神经网络模型---气温预测
  2. Linux Cp 忽略报错信息,linux使用cp报错 Text file busy
  3. mysql8 win10启动_Windows10 mysql 8.0.12 非安装版配置启动方法
  4. 使用Spring Security对RESTful服务进行身份验证
  5. 柱状图中xy轴怎么出现_如果制砂机设备在工作中出现堵料现象该怎么办?
  6. inline行内元素
  7. 学习OpenVINO笔记之Inference Engine
  8. Maven入门:使用Nexus搭建Maven私服及上传下载jar包
  9. 【干货】TCP/IP协议三次握手四次挥手
  10. php imagick gif,PHP基于php_imagick_st-Q8.dll实现JPG合成GIF图片的方法
  11. linux 修改自动联网的配置说明
  12. ASP.net 2.0 的 Membership Provider 与 Role Provider 第一部分——引进资源
  13. 支付宝芝麻认证接口-扫码方式(芝麻认证接口与之类似)
  14. 年龄估计:Ordinal Regression
  15. 谜一样的科学家——阿兰图灵
  16. 2015~2020年中国房价走势
  17. 来一起学习脚本语言吧,简单,高效,解放双手,感受自由!
  18. oppofindx5pro评测
  19. 【已解决】pdf导出的eps图形在WinEdt中只显示一半
  20. 安卓手机下拉状态栏的代码实现

热门文章

  1. 烽火通信实习应聘经验
  2. mysql查询1970年以后出生的人_1970年属狗女一生命运,70年属狗人一生灾难有哪些...
  3. 单片机、微处理器的WiFi http协议 网页响应
  4. js校验统一社会信用代码的合法性GB 32100-2015
  5. win10更改C盘下的用户文件夹名
  6. 微信小程序:聊天斗图微信表情包
  7. MySQL插入数据错误Incorrect string value: ‘\xE8\x85\xBE\xE8\xAE\xAF‘ for column ‘custname‘ at row 1
  8. Django 表单 AuthenticationFrom自动检测user的name 和 password , has no attributes cleaned_data
  9. 电脑进入安全模式的两种方法
  10. 最全的常用正则表达式--包含校验数字、字符、一些特殊的需求等等