mysql的两个问题

最近遇到两个mysql的问题,记录一下。第一个是在微博上看到Erlang发的一个看似是mysql的bug的查询。测试了一下,确实存在问题:

mysql> desc test2;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | YES  |     | NULL    |       |
| name  | varchar(16) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

mysql> select * from test2 where name=0;
+------+------+
| id   | name |
+------+------+
|    1 | wang |
+------+------+

原因是mysql的类型转换的问题,对非int类型列的数据在跟int类型比较时会将其造型为int类型,结果cast成了默认值0,所以条件满足了。当然稍微严谨一点的sql不会这么写,应该对字符串类型加上引号的。

第二个问题是Cobar遇到的问题。最近一个业务需要某个时间字段为毫秒级的精度,结果直连数据库时(mysql 5.6.24)没有问题,而连到cobar上则时间的精度只能到秒,后边的小数部分被忽略掉了。DBA和我一起排查了一下,用mysql客户端直接连到cobar上insert这条语句是没有问题的,也就是说是应用层传给cobar时出的问题。通过tcpdump验证了一下,发现确实应用发送过来的sql语句里的时间列数据只精确到秒,而直连mysql是到毫秒的。

有了这个证据后,猜测是mysql驱动层面的问题,可能是cobar冒充的mysql版本太低导致mysql driver在行为上有所不同,毕竟毫秒时间精度是在5.6之后才支持的。跟cobar的开发者电话联系了一下,说了一下我们的猜测,他说有这个可能。后来我们修改了cobar server端代码里定义的版本号,把版本号改为跟后端mysql一致,结果ok了。

回头看了一下mysql driver的代码,确实在com.mysql.jdbc.PreparedStatement里有个属性是serverSupportsFracSecs,而这个属性是根据数据库的版本来判断的:

protected void detectFractionalSecondsSupport() throws SQLException {
    this.serverSupportsFracSecs = this.connection != null && 
            this.connection.versionMeetsMinimum(5, 6, 4);
}

所以修改的方式要么让cobar反回大于5.6.4版本的值,要么hack一下mysql driver让这块儿对cobar返回true。

阿里云vps上mysql挂掉的解决办法

用阿里云的vps用作blog服务器,系统很稳定,已经100多天一直运行正常,大概从上个月开始发现blog的mysql会有时挂掉,会收到短信通知。之前没太追究,重新启动了mysql解决的。今天上午又收到短信,已经第三次了。

查了一下日志,三次基本都是一样的:

130728  6:50:14 [Note] Plugin 'FEDERATED' is disabled.
130728  6:50:14 InnoDB: The InnoDB memory heap is disabled
130728  6:50:14 InnoDB: Mutexes and rw_locks use GCC atomic builtins
130728  6:50:14 InnoDB: Compressed tables use zlib 1.2.3.4
130728  6:50:14 InnoDB: Initializing buffer pool, size = 128.0M
InnoDB: mmap(137363456 bytes) failed; errno 12
130728  6:50:14 InnoDB: Completed initialization of buffer pool
130728  6:50:14 InnoDB: Fatal error: cannot allocate memory for the buffer pool
130728  6:50:14 [ERROR] Plugin 'InnoDB' init function returned error.
130728  6:50:14 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
130728  6:50:14 [ERROR] Unknown/unsupported storage engine: InnoDB
130728  6:50:14 [ERROR] Aborting
130728  6:50:14 [Note] /usr/sbin/mysqld: Shutdown complete

解决方法:
1) 在 /etc/mysql/my.cnf 的 mysqld 下增加下面一句:

innodb_buffer_pool_size = 64M

还要设置一下swap分区,因为我的vps是没有swap分区的,通过fdisk -l1mount 看不到swap的信息,需要手动添加一下。

2) 添加swap分区的步骤:

2.1) dd if=/dev/zero of=/swapfile bs=1M count=1024
2.2) mkswap /swapfile
2.3) swapon /swapfile
2.4) 添加这行: /swapfile swap swap defaults 0 0 到 /etc/fstab

目前已经设置了swap分区,并重启了mysql,后续观察一下看看还会不会出现吧。

参考:http://stackoverflow.com/questions/10284532/amazon-ec2-mysql-aborting-start-because-innodb-mmap-x-bytes-failed-errno-12

补充,经过近2个月观察,没再发生down掉的情况。

mysql忘记root密码的恢复方式

1) 先停止mysql进程

2) 设置初始文件,内容如下

UPDATE mysql.user SET Password=PASSWORD('newPassword') WHERE User='root';
FLUSH PRIVILEGES;

3) 重启动 mysql

$ mysqld_safe --init-file=/tmp/cure &

注,在某些服务器上,启动mysql时,不能在bin目录下执行 ./mysqld_safe 启动不成功,而要在上级目录下
$ ./bin/mysqld_safe --init-file=/tmp/cure &

ubuntu下mysql开机启动的问题

ubuntu下安装mysql后发现默认开机会启动,尝试通过sysv-rc-conf命令将mysql开机启动取消,但并不生效。看过了在/etc/rc2.d/ 下mysql脚本是以K开头的(S开头表示start,改成其他则不会被启动;K表示kill),是正常的,很奇怪。

搜了一下,原来mysql同时定义了upstart-job/etc/init/mysql.conf 里面定义了 start on levels;要想开机不启动的话,需要修改这个启动级别。

修改 /etc/init/mysql.conf 里的内容,start on  runlevel [2345] 将里面的2去掉

有关upstart:
http://askubuntu.com/questions/19320/whats-the-recommend-way-to-enable-disable-services