Browsed by
Tag: mysql

parseInt

parseInt

云通信系统的用户偶尔向我们反馈,分机的状态显示总是离线状态。我们从后台检查状态是正确的,检查其他用户的分机状态也都很正常,但是这位用户查询的结果确实总是离线状态。这事颇有些蹊跷,引起了我很大的兴趣去研究发生了什么。

检查之后的结果也很简单。后台返回的状态数据是字符串形式,而前端 javascript 脚本是按照整数进行判断,自然无法正常显示状态。但是为什么有些又能正确显示呢?

进一步检查后发现这与 MySQL 数据库的版本有关。我们的云系统有很多服务器,都是采用 Debian 的系统,同时也是采用 Debian 默认自带的数据库。旧 Debian 系统中的 MySQL 数据库版本比较陈旧,返回查询结果时都是采用字符串格式,哪怕字段是整数类型,返回的结果也是转换成字符串。而新的 Debian 系统已经将默认的数据库替换成 MariaDB,返回结果时严格遵循字段的类型,不会进行这类转换。

用户的虚拟通信系统部署在不同的 Debian 节点上,返回查询结果时就存在上述转换方面的差异。

解决方式自然也不复杂。可以从服务器端解决,也可以从前端解决。服务器端升级 Debian 系统就会同时将数据库升级到 MariaDB,自然就能返回整数类型的结果。当然也可以从 PHP (包括 pdo层)解决,由 PHP 对查询结果强制进行转换,将字符串又转换成整数即可。但是出于稳定性方面的考虑,我们一般不太愿意直接升级服务器系统(包括 PHP 等中间层),各节点的升级总是按年制定计划,不太可能为了这样一个小问题兴师动众地升级系统。

因此最后的解决方案就是对前端 JavaScript 脚本做一点修改。JS 提供了 parseInt 函数进行转换(如果是浮点数就是 parseFloat),无论服务器返回的是字符串还是整数,经转换后都可以按照整数进行判断。

此事反映出(1)我们对web、数据库等方面的技术技能比较欠缺,缺乏足够理解;(2)测试范围不够广泛,没有涵盖所有的用户类型;(3)系统配置不够一致,存在新旧并存的现象。我个人觉得后续工作要着力解决第(3)点的情况,尽量做到(包括开发、测试、线上)只有一个版本、只有一种系统。

粗浅理解数据库联合索引

粗浅理解数据库联合索引

在表中对多个列建立联合索引,比如(a, b, c),这种情况下实际建立了三个索引:

  • a
  • (a, b)
  • (a, b, c)

因此,如果对b或者c列进行查询,就需要另外建立索引进行优化。当然,不是索引越多越好,毕竟对插入、更新数据(实际也就是I/O)会有影响。

DigitalOcean小坑

DigitalOcean小坑

DigitalOcean是我个人非常喜欢的云计算服务商,我们在部署自己的网站、云通信系统、向客户推荐等各种情况都会采用DO(以及Linode,另一个非常优秀的云计算服务商)。

绝大多数情况下,DO节点运行非常快速、稳定,然而有时候也有意想不到的情况发生。最近我们发现一个节点的服务突然中断了,经检查后发现是MySQL数据库异常退出,错误原因是内存分配不足。以前从未发生过这种情况,简单对比后发现这个节点是个小内存节点,只有512M内存(通常我们都为生产环境节点配置2G内存)。我们认为这个节点的MySQL数据库不应该占用太多内存,即便512M内存不够,加上SWAP的支持也应该足够了。

然而分析该节点信息,惊讶地发现DO默认居然没有分配SWAP区(与之对比的是,Linode可以在创建节点时指定SWAP分区)!

检索了DO的文档,对这种情况的解释是建议采用更多内存的节点,SWAP做缓存会拖慢系统,并可能影响其他用户。原则上这点没错,如果频繁发生内存不够的情况,的确应优先升级节点,采用更多内存。然而,如果仅仅是在尖峰时刻偶尔少量内存不足,采用SWAP过渡一下完全合理。

更重要的是,即使SWAP相对而言慢一些,但相比程序crash而言,一个慢点但是稳定的系统显得更合理。同时考虑到DO采用SSD硬盘,速度可以接受,因此我们手工增加了2G的SWAP设置。事实证明,内存在忙时实际只少了1M,用SWAP来应对这1M内存的需求,相当合理。

在DO节点增加SWAP很容易,请点击这里了解细节。文档是基于Ubuntu 14.04,我们的节点是Debian 8,按照这篇文档的介绍,也能设置成功。

以下是简要的步骤记录:

(1)创建 swap 文件:

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

(2)修改 /etc/fstab 文件,添加以下项即可:

/swapfile none swap sw 0 0
定时自动备份MySQL数据库

定时自动备份MySQL数据库

网上搜索的一些文章或者脚本, 在Ubuntu/Kubuntu中似乎都有这样或者那样的问题, 经过一番摸索后, 以下方式是可行的.

step1: 创建定时任务, 例如在早上1:30备份数据库. 编辑/etc/crontab文件, 添加内容:

30 1    * * *   root    sh  /home/yxh/cronDayBackupMySQL.sh

step2: 创建shell脚本cronDayBackupMySQL.sh. 要非常注意脚本中的标点符号(不得不说, shell脚本是怪折磨人的)

#!/bin/bash
currDateStr=`date +%Y%m%d`
mysqlBackFileName=mysql${currDateStr}
mysqldump -u root -p db_yxh --password=1234 | gzip > /var/backups/$mysqlBackFileName.sql.gz

其中, 数据库是db_yxh, 数据库root用户密码是1234, 备份的sql文件压缩存放在/var/backups目录下.

解压缩gz文件也很简单, 直接试用gzip即可:

gzip -d xxx.gz

 

MySQL诡异的问题

MySQL诡异的问题

一直在本机(kubuntu)上调试和运行MySQL数据库,工作状况良好。某次重启后,再用mysql客户端连接server时,居然出现以下信息:

ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)

检查了一下/var/run/mysqld目录,没有发现任何文件。使用命令ps -A | grep mysql,居然没有发现mysqld进程! mysql居然没有启动!

重新启动mysql服务器(sudo service mysql start)失败,检查/var/log/mysql/error.log,发现mysql启动时crash,不明所以。

后来google了N个帖子后,按照某个帖子的建议,修改/etc/mysql/my.cnf文件,注释掉其中的bind_address行,重启mysql居然就成功了。

可是以前一直工作得很好,没有做过任何改动,诡异啊。

修改MySQL表中字段的缺省值

修改MySQL表中字段的缺省值

网上搜了一下,居然有推荐“先删除字段,再重新添加字段”的做法。如果该字段原来有一些非缺省值的记录,岂不是就丢失了吗? 这真是一点都没有爱啊。

比较有爱的做法是:使用MySQL提供的alter table语句对字段直接进行修改。

例如对tbl_local_users表中的moMaxCalls字段修改缺省值为1,可以采用以下语句:

alter table tbl_local_users alter moMaxCalls int default 1;

如果需要修改字段的类型或者变动位置,则需要用“change column”,例如:

alter table tbl_local_users change moMaxCalls int default 1 after emailAddr;

MySQL与幻象读

MySQL与幻象读

最近在部署系统的过程中,发现MySQL的一点问题,进行简单总结。

实际上就是关于事务隔离级别以及幻象读的问题。

我们的程序分成两个部分:UI层以及Service处理层。UI层使用MySQL的C库接口创建连接;Service层采用Python的MySQLdb您(底层仍然是MySQL的C接口)创建连接。

因此,实际上会与MySQL创建两个连接。

在windows环境中,如果我们通过UI修改了MySQL的数据,我们发现在service层查询时,还是以前的数据,而不是commit之后的数据。

采用Ubuntu系统下的MySQL时,没有这个问题。UI修改了MySQL数据后,Service能立刻查询到最新的结果。

我们发现,Ubuntu下的MySQL(5.1.49-1ubuntu8.1 (Ubuntu))版本较旧,采用MyISAM引擎。而Windows环境下的MySQL(5.1.53-community MySQL Community Server (GPL))较新,采用InnoDB引擎。将Windows环境下的MySQL强制指定为MyISAM时,问题也能解决,不再出现幻象读。

使用下述命令查询了Ubuntu和Windows的配置,都是REPEATABLE-READ:

SELECT @@tx_isolation;

SELECT @@global.tx_isolation;

判断,InnoDB的事务处理级别REPEATABLE-READ还是会出现幻象读。在程序中强行将session级的处理修改为READ-COMMITTED后,问题也解决,不再出现幻象读。

set session transaction isolation level read committed;

这个似乎与网上的资料有些不一致,据说REPEATABLE-READ不会出现幻象读,而READ-COMMITTED级别才会出现。实际结果是相反的。

另外,就我们的应用来说,select操作多于insert/update操作,而且数据量不大,因此MyISAM比InnoDB更适合我们的应用,可惜高版本的MySQL将缺省引擎给换成InnoDB了。

MySQL 5.5.8安装过程中的小问题

MySQL 5.5.8安装过程中的小问题

德国的一个客户反馈callingCard业务有点问题,查了半天,没找到原因。在我们的环境上一切都很正常,而在他的环境上,很容易就失败了。我们推测是不是MySQL数据库不匹配?因此决定也安装最新的MySQL 5.5.8版本测试一下。

按照以往的惯例,我们在安装时指定允许root从远端接入数据库。可是在最后的配置过程中,总是提示失败,是某个field没有default value。

这确实很奇怪啊,以往从来没有遇到这样的问题。我们重新卸载、安装,此时不再允许root从远端接入数据库,则配置过程一切正常。

5.5.8版本和以前有另外一个不一样的地方,在windows的程序启动菜单中,没有了命令行窗口的快捷方式了。需要手工打开dos窗口,然后进入MySQL安装目录下的bin子目录,运行mysql -u root -p来登录MySQL数据库。

号称5.5.8比前任版本在各方面有极大的飞跃,这个我们不得而知。不过,在我们的环境中,切换到5.5.8环境后,结果仍然是正常,开起来客户的问题可能是其他方面的啊。

远程访问MySQL数据库

远程访问MySQL数据库

Linux版本的MySQL数据库缺省不允许从远程访问(Windows版本在安装时可以进行选择),因此我们需要简单修改一下来放开这个限制。

通过软件中心安装MySQL,这没有什么好介绍的。网上有些这方面的介绍,不过中文版本的基本上都有些错误,估计大部分都只是转载,作者并没有真正尝试。

以下步骤基于Ubuntu版本。

step1:mysql> grant all privileges on *.* to 'root'@'%' identified by '1234';

其中,‘1234’是指密码,‘root‘是指远程访问的账户名。’%’是指允许从任何一个远程计算机访问。’*.*’是指所有数据库、所有表。

step2:mysql> flush privileges;

step3:修改/etc/mysql/my.cnf文件,注释掉以下行:

bind-address     = 127.0.0.1

step4: 重启MySQL服务

sudo service mysql restart

完成上述步骤后,就可以用root账户,以‘1234’为password,从任何一个远端计算机上登录并访问MySQL数据库了。

2018-09-29 更新, Debian 9之后又有了很多变化:

最大的变化莫过于MariaDB正式替换了MySQL,当然mariadb的各项操作、库(尤其是基本的操作和基本库)与MySQL还是保持兼容。同时,配置文件变更为 /etc/mysql/mariadb.conf.d/50-server.cnf。

在完成上述那些操作后,在其他用户的shell里,使用root账号登录MariaDB,会提示以下信息:

ERROR 1698 (28000): Access denied for user ‘root’@’localhost’

而直接在root用户的shell里登录是没有问题的。这种情况下,root要登录进MariaDB后,选择“mysql”数据库,然后

update user set password=password('1234') where user='root' and host='localhost';

此时设置从本机登录时,root用户的密码。

update user set plugin='' where user='root';
flush privileges;

清除root用户的plugin字段,允许root用户从其他shell里登录。

另外要注意的是,重新启动MariaDB,命令也有变换,采用 systemctl 进行操作:

systemctl stop mariadb.service
systemctl start mariadb.service
MySQL查询结果中去掉重复的值

MySQL查询结果中去掉重复的值

一个简单的应用,查询数据库中的用户名,同时去掉其他重名的用户。测试数据库如下:

mysql> select name from demo;
+———+
| name    |
+———+
| yxh     |
| yxh     |
| default |
+———+

查询时,只要限定关键词‘distinct’即可,例如:

mysql> select distinct name from demo where name != ‘default’;
+——+
| name |
+——+
| yxh  |
+——+
1 row in set (0.02 sec)