mysql中的sql_mode导致的datetime类型字段不能为0000

问题描述:

在执行建表语句的时候,出现invalid default datetime value '0000-00-00 00:00:00',从字面意思看,就是不合法的默认值’0000-00-00 00:00:00’,但是为什么呢?,datetime类型应该是允许这样的值出现。

排查:
这个时候我们需要执行

1
select @@sql_mode;

你会发现值是这样的:

1
2

@@sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'

各项数值含义:

ONLY_FULL_GROUP_BY

对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现,那么将认为这个SQL是不合法的,因为列不在GROUP BY从句中

STRICT_TRANS_TABLES

在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做任何限制

NO_ZERO_IN_DATE

在严格模式,不接受月或日部分为0的日期。如果使用IGNORE选项,我们为类似的日期插入’0000-00-00’。在非严格模式,可以接受该日期,但会生成警告。

NO_ZERO_DATE

在严格模式,不要将 ‘0000-00-00’做为合法日期。你仍然可以用IGNORE选项插入零日期。在非严格模式,可以接受该日期,但会生成警告

ERROR_FOR_DIVISION_BY_ZERO

在严格模式,在INSERT或UPDATE过程中,如果被零除(或MOD(X,0)),则产生错误(否则为警告)。如果未给出该模式,被零除时MySQL返回NULL。如果用到INSERT IGNORE或UPDATE IGNORE中,MySQL生成被零除警告,但操作结果为NULL。

NO_AUTO_CREATE_USER

防止GRANT自动创建新用户,除非还指定了密码。

NO_ENGINE_SUBSTITUTION

如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常。

解决方案:

经过排查,问题已经很明显了,所以我们怎么做呢?

答案就是去掉NO_ZERO_IN_DATE&&NO_ZERO_DATE

1
2
3
4
#1.先执行这句更改SQL模式
set @@sql_mode = 'NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
#2.在执行要执行的建表语句
create table .......

以上。

linux操作利器alias用法

写在前边

学习这件事,有时候并不一定很刻意,而是从生活,从经验中去积累,不知道什么时候就发生了。

type 命令

一般情况下,type命令被用于判断另外一个命令是否是内置命令,但是它实际上有更多的用法。

1.判断一个名字当前是否是alias、keyword、function、builtin、file或者什么都不是;

2.判断一个名字当前是否是alias、keyword、function、builtin、file或者什么都不是的另一种方法(适用于脚本编程);

3.显示一个名字的所有可能;

4.查看一个命令的执行路径(如果它是外部命令的话);

5.强制搜索外部命令。

详细参见这位老哥的博客 type命令使用

alias 命令

我们在服务器上查看日志的过程种,不可避免的要记住一大串的路径,比如说/export/www/logs_backend/Java_service_logs/,每次链接到服务器都要输一遍这个长长的路径才能进入日志目录,Linux就给我们提供了一个简单的方法来避免这种操作,就是alias,当然你也可以用软连接来简化这个过程,不过用alias会更为简单。

说这个之前我们要提一下type这个命令:

我们用到的是上边说的type命令的第一个功能,用来测试一下我们要自定义的别名有没有被占用

1
2
3
4
5
6
7
#如果没被占用
dell@DESKTOP-8U4HTOL MINGW64 /d/develop
$ type t
bash: type: t: not found
#如果被占用了
$ type ll
ll is aliased to `ls -l'

用法:alias [-p] [name[=value] … ] 注意=和字符串之间不能包含空格

1.命令alias

直接使用命令alias可以查看当前登录环境下的所有命令别名

1
2
3
4
$ alias
alias ll='ls -l'
alias log='cd /d/develop/backend/storge/logs'
alias ls='ls -F --color=auto --show-control-chars'

2.设置别名 alias 别名='完整命令'

1
$ alias log='cd /d/develop/backend/storge/logs'

3.命令alias + 命令

这将显示这个别名命令的具体含义

1
2
$ alias log
alias log='cd /d/develop/backend/storge/logs'

4.给一组命令设置别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dell@DESKTOP-8U4HTOL MINGW64 /d/develop
$ type t
bash: type: t: not found

dell@DESKTOP-8U4HTOL MINGW64 /d/develop
$ alias t='cd /d/study;mkdir test;touch 01.txt'

dell@DESKTOP-8U4HTOL MINGW64 /d/develop
$ t

dell@DESKTOP-8U4HTOL MINGW64 /d/study
$ ll
total 1
-rw-r--r-- 1 dell 197121 0 4月 4 16:03 01.txt

5.持久化别名

以上说的方法,都是临时性的,只在当前登录环境下有效,一旦退出登录就会失效,要想持久化,需要修改/etc/bash.bashrc

centos下是/etc/bashrc,ubuntu下为/etc/bash.bashrc

vi /etc/bashrc

在文件末尾添加alias log=’cd /d/develop/backend/storge/logs’并保存退出

执行source /etc/bashrc 使配置生效

以上。

关于Mysql:unknow column in where clause

写在前边:

已经很久不更新了啊,整个2月份几乎没有遇到什么新鲜事。直到昨天我又犯了一次傻,貌似只有我犯傻的时候才有材料可以跟大家分享…..

问题表现:

mysql 报错: unknow column ‘sys’ in where clause

事实上这是个挺常见的错误,我猜你大概会说,这个问题不是已经很明了了么? 你查询了一个不存在的字段! 可是事情的真相真的是这样么?并不是,报这个错误的原因还有一种可能就是你的where条件中字符串的拼接出了问题。

现场还原:

  • 还是先说一下我犯的傻吧

我首先开始排查的问题的时候输出了我的查询SQL,形似

1
2

$sql = 'select * from user where id in ('.implode(',',$idArr).')';

$idArr一个元素很多ID数组,里边的内容都是整型的数字,所以我也没想很多,然后抛出了这个mysql错误,我开始检查我的sql语句 。我用记事本打开了我刚刚打印的sql,开始搜索sys这个关键词,但是我没注意到我鼠标的位置,记事本默认向下搜索,提示没搜索到。我后来就随机把这个SQL中的id字符串删掉了一段,删的只剩几个,执行,诶!好了!我开始疑惑,难道整型的id查询在数据长的时候会出问题么?加上在CSDN看到某博客上说是字符串拼接的问题,所以我决定给他做一下处理,顺带加上了这么一段注释。

1
2
3
4
5
//做一下处理换成字符串否则在$IdString过长的时候会引发unknow column 'sys' in where clause 错误

foreach ($idArr as &$v) {
$v = '\''.$v.'\'';
}

加上之后,问题果不其然的解决了,好的,没有问题,完美!然后开开心心的上个线。

引发问题的真实原因

到了晚上快下班的时候,我在开发另一个需求的时候,突然在列表里看到了一个名为sys的用户!真的是瞬间像是被一道闪电击中了!卧槽! (这绝对值两个卧槽,才能表达我当时的内心!),是的就是你想的那样!那个用户id数组里有一个用户的idsys,而这东西是个字符串,但是却没被引号包裹。所以才引发了mysqlunknow column 'sys' in where clause错误。这才是错误的真相!

好了,不说了,趁着还没有同事发现,我要把这个包含了我愚蠢猜测的注释给删掉。

溜了溜了。

gitment初始化评论跳回博客首页

表现

众所周知,gitment评论系统需要初始化以创建对应的issue,可是我在点击login with github的时候,总是跳向博客首页!WTF!什么鬼?这样不程序啊?

WTF

排查

1.F12查看login回调链接,redirect_uri参数没有什么问题啊,行,我们回头查看,github的文档,

github文档

github文档地址

2.文档中提到,如果地址不匹配的话,就会重定向到你在OAuth Apps 中设置的Authorization callback URL,而这里我们配置的都是首页,所以会跳向首页就可以理解了,那也就是说这里的地址和回调地址里我们传的redirect_uri不匹配,那就检查这两个地址吧,对比之后果然发现了一些有意思的事情:

1
2
3
redirect_uri      https://ergou.fun/posts/3834.html

Authorization callback URL http://ergou.fun

一个是http,一个是https,当然匹配不上了啊!摔!修改一下,Authorization callback URL改为https,来来来测试一下,OK,完美解决。

后记

如果你仔细观察的时候,你会发现跳向博客首页的时候,地址栏链接变的很复杂,都是些什么东西呢,我们不妨解析一下

1
2
3
4
5
https://ergou.fun/?
error=redirect_uri_mismatch&
error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https://developer.github.com/apps/managing-oauth-apps/troubleshooting-authorization-request-errors/#redirect-uri-mismatch

//真是贴心啊,错误原因,和参考文档地址全都给了

关于浏览器请求PHP一次请求执行了两次

测试同学今天又双叒反馈了一个Bug

继上次解决了重复请求的问题之后,本来就以为可以万事大吉了,没想到我还是太年轻了,测试同学说,不行啊,老哥,你这个我点击了一次创建居然创建出来两条数据!!并且查看日志的时候,确实是发了两次网络请求!!!

我:?????

真是让人头秃啊

排查

1.先看看是不是JS的问题,我们看一下network跟踪一下,没有啊,这只发送了一个请求,挠头,继续,

2.好的,我去我的工位上复现一下,在JS处打断点,没有啊,ajax这里只进来一次,好吧,继续查,

3.好的,把host地址改向测试机,请求,我擦,日志正常,结果也正常是一条数据啊,根本没办法复现啊。

这。。。It works on my computer ! 这就非常的有趣了,测试同学和我访问的都是同一台测试机,为什么,我创建没问题,他创建就有问题呢。好奇怪,首要之急要解决问题的话,就避免重复请求,在代码里判断一下请求间隔。可是不应该啊,有这么麻烦么?我不死心啊?

猜想&&解决

讲道理,没道理一个请求到后边代码会执行两次的,会不会是有个多个进程的原因?我们重启一下NGINX好了,在服务机上执行

1
/etc/init.d/nginx resatrt

测试大哥,快执行一下试试,诶,好了耶。

好的,完美。

20190128

不得不来补充点东西

本来以为就是这样只是进程被卡住的原因,然而并没有,测试大哥后来多次给我反馈,在我还没有说话的时候就回,我重启了,没用!

好吧好吧,这个问题本来就是我们偷懒了,按说我们是应该在测试服务器上打日志,看一下代码走进来多少次的,额。。。

后来测试大哥有一次反馈这个问题,我觉得问题实在是严峻到了不得不解决的时候,重新排查,在数次复现无果之后,network也只有一次请求。我回复测试大哥,大哥,要不咱们换个浏览器?

换一个,OK,没有再重复了。很好,换回chrome,我擦又重复了。

老哥,检查一下你chrome的插件,好吧,我们打开拓展程序,一个诡异的插件映入眼帘

页面自动刷新

我擦,这是什么东西???停掉,快停掉!再试一下,果真没有重复数据的问题了。

F**king ! ! !

layer快速点击会触发多次回调

场景还原

测试同学反馈点击了一次操作,为什么会有两条操作记录?

我:????

排查思路

查看日志,看一下是不是发了两次请求,果不其然啊:

日志截图

并发了,同一时间发送了两次请求,出现了脏写。

原因

系统的confirm是线程阻塞的,而layer.confirm是非阻塞的,这一点在官方的API文档中有提到。

解决方案

1
2
3
4
5
6
7
8
9
10
var lock = false;
layer.confirm('is not?',{btn:['确定','取消']},function(index){
if(!lock) {
//加锁防止多次回调
lock =true;
$.ajax({
// .....
})
}
})

laydate V5.0.8动态设置min值

laydate通过设置min,max值来对用户输入的时间做约束

laydate v1.0版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

//日期插件
var start={
elem:"#start",
format:"YYYY-MM-DD hh:mm:ss",
min:"2013-08-18 00:00:00",
max:"2099-06-16 23:59:59",
istime:true,
istoday:true,
choose:function(a){
end.min=a;
end.start=a
}
};
var end={
elem:"#end",
format:"YYYY-MM-DD hh:mm:ss",
min:"2013-08-18 00:00:00",
max:"2099-06-16 23:59:59",
istime:true,
istoday:true,
choose:function(a){
start.max=a
}
};
laydate(start);
laydate(end);
//只要在回调函数choose中赋值就行了

laydate v5.0版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//日期插件
var start=laydate.render({
elem:"#start_time",
type:"datetime",
format:"yyyy-MM-dd HH:mm:ss",
min:"2013-08-18",
max:"2099-06-16",
done:function(value,date){
end.config.min={
year: date.year,
month: date.month-1,
date: date.date,
hours: date.hours,
minutes: date.minutes,
seconds: date.seconds
};
}
});
var end =laydate.render({
elem:"#end_time",
type:"datetime",
format:"yyyy-MM-dd HH:mm:ss",
min:"2013-08-18",
max:"2099-06-16",
done:function(a){
// start.max=a
}
});

在v5.0版本中,min值变成了一个对象,并不会重新渲染,所以直接对min设置值是没有用的,得单独对每个min的子元素赋值

特别要注意的是month要减1

虽然我也并不清楚为什么要这么做,但是It works. 我已经去layui的社区问了,希望能有人帮我解惑。

关于hexo-abbrlink链接undefined

关于hexo-abbrlink

hexo-abbrlink是一个hexo博客链接永久化的解决方案

  • 支持使用不同的算法和进制对文章链接进行转换
算法 进制 生成链接
crc16 hex https://post.zz173.com/posts/3ab2.html
crc16 dec https://post.zz173.com/posts/12345.html
crc32 hex https://post.zz173.com/posts/9a8b6c4d.html
crc32 dec https://post.zz173.com/posts/1690090958.html

安装

1
npm install hexo-abbrlink --save

使用

打开config.yml,修改permalink中类似这样

1
permalink: posts/:abbrlink.html

具体说明参照作者的github说明

项目地址在这里

可能出现的问题:

终于回到标题上来,有的同学说,这个配置完成之后,文章的链接都变成了undefined,新的文章没问题,老的文章就不行了。这个问题其实我们仔细想一下就能明白,我们首先要执行hexo clean 清楚掉以前生成的文章缓存,然后hexo g重新渲染就ok了。

cmder的segmentation fault错误修复

Segmentation fault

现场还原

  • 问题出现的原因是我在 cmder的命令行里执行了cmder /register ALL命令,本意是把cmder放到右键菜单里去的
    但我没想到的是,各种不成功,提示cmder lanchun什么的,之后,我换在了windows自带的cmd中执行这个命令,成功了。
    但是令人疑惑的是cmder的bash窗口就此开始抽疯,cd 命令可以使用 llls之类的命令直接抛出Segmentation fault
    错误。

实验过程&&猜想

  • 百度搜了很久并没有找到解决方案,百度提到可能的原因:
  1. git bash 版本过旧,有概率出现这个问题,但是升级之后并没有解决这个问题
  • 猜想可能的原因:
  1. Cmder full这个版本是有BUG的,我们看Cmder的设置的时候,可以发现他的GUI其实是ConEmu
    ,然后又拿这个调用了git bash ,那我们直接拿ConEmu调用git bash会不会有问题呢,所以我们打开ConEmu执行
    命令cd git/bin && bash --login -i 我们发现我们这时候进入bash 界面了,我们使用一下ll命令,哎,这次没有报错了。

  2. 我们换Cmder mini 试一下,打开bash:bash窗口,卧槽,啥玩意,居然说系统找不到制定路径,好的,我们从设置里看一下,执行bash窗口之后
    执行的哪个命令,可以看到是cmd /c ""%ConEmuDir%\..\git-for-windows\bin\bash" --login -i" ,我们打开安装目录,看一下,我去!
    ConEmuDir 的上级根本没有git-for-windows目录,好吧,你赢了,而在full版本中是有的!!! 我后来找到我git-bash的安装目录,复制整个文件夹
    到cmder的Vender 目录,改名成git-for-windows,打开bash:bash窗口,哎,进来了,运行命令试试,好的,Surprise ! 这次没有报错。
    问题成功解决。

结论

结论就是 Cmder full 的版本在Windows10下,可能有某种未知的Bug , 我们可以通过尝试使用给 Cmder mini 添加git-bash的办法,来代替它。

慎用array_filter函数

array_filter

(PHP 4 >= 4.0.6, PHP 5, PHP 7)

array_filter — 用回调函数过滤数组中的单元

说明

array array_filter ( array $array [, callable $callback [, int $flag = 0 ]] )

依次将 array 数组中的每个值传递到 callback 函数。如果 callback 函数返回 true,则 array 数组的当前值会被包含在返回的结果数组中。数组的键名保留不变。

参数

  • array

    要循环的数组

  • callback

    使用的回调函数

如果没有提供 callback 函数, 将删除 array 中所有等值为 FALSE 的条目。更多信息见转换为布尔值。

  • flag

    决定callback接收的参数形式:

    ARRAY_FILTER_USE_KEY - callback接受键名作为的唯一参数
    ARRAY_FILTER_USE_BOTH - callback同时接受键名和键值

    返回值

返回过滤后的数组。

array_filter其实是一个相当好用的函数,常用的场景包括,表单多条件筛选,可以直接用此函数过滤掉没有值的筛选项。

但是有一个问题,必须要重视:

array_filter会过滤掉任何值等于FALSE的值,也就是说 0值,空字符串,null,都会被过滤当你的筛选项里有值等于0时,问题就会暴露出来,在我们的项目里,在调接口时做了过滤,没想到有一个默认的状态等于0的参数被我过滤掉了,就造成了线上数据的失常,也算是一个比较低级的错误了。此文谨记。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×