Entries Tagged as 'Mysql'

数据从mysql4.1.x倒到mysql5.0.x后中文乱码的问题

今天
把个系统从一台机器上挪到另外一台机器
由于牵涉到数据库升级
(原来的是4.1.x,中文数据编码是gbk;新的是5.0.x,中文数据编码想用utf-8)
所以就比较留心
首先把数据dump出来
mysqldump db1>db1.sql
然后传到新的服务器上
scp db1.sql xxx.xxx.xxx.xxx:/tmp/
再在新的机器上做编码转换
iconv -f gbk -t utf-8 db1.sql>db1utf8.sql
再倒入新的库
mysql db1 然后发现web页面显示需要选gbk才不乱码(跟在老机器上一样)
最后在老机器上dump时加参数指定缺省character-set
mysqldump --default-charcter-set=latin1 db1>db11.sql
这样做的数据拷到新机器上后

iconv -f gbk -t utf-8 db11.sql>db11utf8.sql
再倒入
就没有问题了(库里存的是utf8的数据了)

cacti监测mysql性能

mysql_stats

需要在被检测的mysql库里添加检测机器的权限(仅需要process权限):

grant process on *.* to username@192.168.1.1 identified by ‘password’;
flush privileges;

fc3下安装php5.2.5+pdo_mysql

也算是需求推动
产品那边需要在一台fc3(fedora core 3)的机器上装上php5
并且要启用pdo_mysql支持
偶,额滴神呀
幸好以前在别的机器上手工编过php5.x(具体版本5.2.5)
赶紧从那台机器上把php5.2.5拷过来
并把原来的./configure连同编译参数都调出来
再加上个–with-pdo-mysql重新configure一下
再make
make的时候出错了
不知道原因在哪儿
后来在网上搜了下
找了种折衷的办法
说是先编好php5
然后再把pdo_mysql的支持编进去

cd php5.2.5/ext/pdo_mysql
phpize
./configure
make
make install

这样居然成功了
再接着改php.ini
把编出来的pdo_mysql.so正确load进来
这样居然成功了!!

一台机器php连mysql出client版本不支持的问题

在控制台上直接执行php test.php
系统出错:
“PHP Warning: mysql_connect(): Client does not support authentication protocol requested by server”
于是就在本机控制台用命令
mysql -h 192.168.1.1 -u user -p
(这里192.168.1.1是mysql服务器ip)
再输入密码来连
这样没有问题
然后在192.168.1.1把程序拷过去
直接执行
然后又没有问题
当时就有点困惑了
这两台机器一样的php-mysql版本呀
一样的mysqlclient版本呀
可为什么一个能连一个出错呢
要说对client那台机器的权限有限制
但是在client那台机器上直接用mysql客户端程序也能连呀
于是
似乎陷入困境
mysql官网对这个错误的解释是老板本的mysql和新版本的mysql的密码格式不兼容
如果用老板本的mysql client去连新版本的mysql server
如果mysql server上的密码格式是新格式的话
就会出这个错误
显然,本例就是这样

最后问题解决后
才发现其实一开始分析问题的时候就出现了偏差
其实知道问题的原因是由于client的版本和server上存储密码的格式相关
那么就应该去确认这两台机器一台连不上一台没问题他们分别的client版本和server上的密码格式的
如果是这样
一开始就去服务器端
use mysql
select * from user where User = ‘user’;
一看就知道了
原来有条记录
Host正好是client的ip
client连过来的时候正好是匹配这条记录
但是其密码格式是新格式
而client上的mysql client版本是老板本
不出问题才怪呢!!
再看看从服务器上通过连为什么又没有问题呢
原来还有条记录
Host是’192.168.1.%’
他的密码格式是老格式的
服务器上连过来的时候正好是匹配这一条记录
自然OK

这样解决起来也就容易了
直接将写着client ip的那条记录删掉就好了

php连mysql的诡异问题:“MySQL server has gone away”

今天写了个小程序
用来监测某些机器上的某些进程是否存在
需要从mysql中查出ip和进程字串
然后从中控上一台一台ssh上去ps查进程是否存在
如果状态变化(原来标记不存在的现在有了,或是原来标记存在的现在没有了)
还需要更新mysql库中的相应状态字段
因为查询出来的数据比较多(600多条)
而且我还要一台一台ssh上机器检测进程
等我发现某台机器的某个进程状态改变要update库的时候
数据库报错:

MySQL server has gone away

查了好些资料
也没找出原因来
最后按照文档上建议的
先判断
然后再执行mysql_query

function connect(){
$db = mysql_connect(’xxx.xxx.xxx.xxx’, ‘xxx’, ‘xxxxxx’);
mysql_select_db(’db1′);
return $db;
}
if (!$db){
mysql_close($db);
$db = connect();
}elseif(!mysql_ping($db)){
mysql_close($db);
$db = connect();
}
mysql_query(”$sql”);

不管怎么样
这个问题算是解决了
不过说实话:为什么我还是没搞明白
:)

用tcpdump抓mysql的查询语句

在mysql的官方网站上找到几个用tcpdump来抓在mysql server上跑的sql语句
# — (1.1) To capture all traffic on the interface eth0, run:
time tcpdump -i eth0 -s 1500 -w 20060427-db-traffic-01.dmp

# — (1.2) To capture traffic on the interface eth0 coming from a specific IP address, run:
time tcpdump -i eth0 -s 1500 src host 192.168.2.10 -w 20060427-db-traffic-01.dmp

# — Press Ctrl+C — do not leave tcpdump running infinitely on high traffic interfaces

# — (2) To process the results, run:
strings 20060427-db-traffic-01.dmp | grep -i ’select’ | awk ‘{printf(”%s %s %s %s\n”, $1,$2,$3, $4);}’| sort| uniq -c | awk ‘{printf(”%06ld %s %s %s %s\n”, $1,$2,$3,$4,$5);}’|sort

还有一句诗:
tcpdump -l -i eth0 -w - src or dst port 3306 | strings

mysql中怎样的用户拥有”super”权限?

今天下午用前面提到的init-connect方法把一个mysql3.23.58的库倒到了5.0.x的库里
然后领导说,怎么那个什么页面还是乱码呀
他说的那个我知道,因为是用root用户直接连库的(init-connect的设定不生效)
于是我就胸有成竹的告诉领导是连库用了root用户的原因
然后我就在程序里把用户该成了一个普通用户
再一刷页面
“怎么还是乱码呀”
一下子,我的汗都出来了
“怎么会呀,那天测试过的,没有问题的”
于是我又重新倒库的sql语句iconv折腾了几下
重新倒库
还是不行
我仔细回想了上次测试的过程
最后,灵光一现:会不会是这个普通用户也有问题呀?
因为当时我给这个用户赋权限的时候因为其要access多个库
于是我就是用grant all privileges on *.*这种方式搞的
这样比较奇怪,我一般都是指定了某个数据库,很少有这样用”*”代替数据库名赋权限的
所以我就进mysql查了下
use mysql;
select User, Super_priv from user;
果然,这个“普通用户”的Super_priv是’Y’
而相应其他的用户(除了root)都是’N’
按照文档,具有”super”权限的用户连上mysql库,是会被忽略init-connect参数的
而php程序如果不指定,却省是用的latin1来连接数据库的
所以就乱码了呀
知道了原因,再改起来就容易了
update user set Super_priv = ‘N’ where User = ……
flush privileges;
一下就好了

MySQL配置文件my.cnf中的”init_connect”的用法

这两天折腾把一台机器的mysql(3.23.58)库倒到另外一台机器的mysql(5.0.27)库里的工作
而且最要命的是原来的库里的数据中有中文字符!
倒数据的时候倒还顺利
先在原来的库里mysqldump出来数据
然后在新的机器上用iconv转下编码(如果需要的话)
我的情况不需要,因为我的新环境差不多都已经设好了的gbk的编码
在mycnf中设置的有:

[client]
default-character-set=gbk

[mysqld]
default-character-set=gbk

然后用mysql dbname < filename.sql
这样倒入新的库里
数据成功的倒过来了
但是php程序挪过来后还有问题
因为php连mysql数据库,如果不显示的指明用什么编码来设置connection、results的话
缺省用latin1编码来设置其connection和results的属性
每个程序都改,都在连上mysql首先执行一句:

SET NAMES ‘gbk’

?
当然最好的办法是不用动程序咯
于是我找了找
发现从mysql4.1.2开始
配置文件my.cnf里开始支持参数:init_connect
比如:

[mysqld]
init_connect=’SET NAMES gbk’

这样每次连接过来的时候,首先就会去执行”SET NAMES gbk“了
这样就能避免每个php程序都要改
但是这种做法也不是完美无缺的
当拥有SUPER权限的用户连上来的时候,init_connect设定的sql语句是不会被执行的
用户”root”自然拥有SUPER权限
这里的权威文档来自官方
而我们的程序就有是用root连过来的!!!

最后只能想个折衷方案
让用root用户直接连的都改用普通用户连

Writing UNION statements in MySQL 3.x

mysql里,从4.0开始支持UNION语句
用来把不同的结果集合成一个
今天需要写个SQL语句
用UNION会非常简单,但是数据库是3.23的
于是就想3.x的mysql怎样替代union呢
于是去网上搜,还真找到了
Writing UNION statements in MySQL 3.x
这里,有点拿不准的就是表_dummy
直接用会发现说_dummy这个表找不到的错误
最后手工建了个表_dummy
还添加了2条记录:“0”、“1”
然后就搞定了

SELECT DISTINCT
IFNULL(d1.t1.ip, d2.t2.tsip) AS ip,
IFNULL(d1.t1.port, d2.t2.tsport) AS port,
IFNULL(d1.t1.cguid, d2.t2.channelid) AS cguid
FROM _dummy AS d
LEFT JOIN  d1.t1
ON (d.num = 0
AND d1.t1.ip is not null
AND d1.t1.port > 0
AND d1.t1.tport > 0)
LEFT JOIN d2.t2
ON (d.num = 1
AND d2.t2.tsport > 0
AND d2.t2.tsip != ”
AND d2.t2.tsip is not null
AND d2.t2.channelid != ”
AND d2.t2.channelid is not null)
WHERE d.num < 2
ORDER BY ip, port

mysql的一个”bug”?

昨天帮忙解决了一台机器后台数据库连接问题
当时现象是这样的
正常连接连不上去
打开mysql控制台
show processlist一看
发现一堆的”unauthenticated user“在”login
重起mysql不多久
1000个链接马上就撑满了
当时怀疑是不是在被人尝试账号、密码来连数据库呀
会不会是sql注入呀
当时的想法现在想起来好天真哟
如果机器被别人搞了
数据库的账号密码都写在程序里的,一看就知道了,还需要这么去尝试取得?
后来搜了一下
发现有n多前辈也遇到过这种问题
他们称之为这是mysql的一个”bug”
是说当mysql的client连过来的时候,服务器会主动去查client的域名
要知道,我国域名反查工作做的非常之……落后
所以最终结果只是timeout而已
因此就会有大量的连接长时间的状态是login
用户名是“unauthenticated user

我昨天碰到的问题显然也是典型的这种问题
我们的机器是内网来连mysql数据库的
我们内网ip也没有做过ip->dns的反查
所以也会查不到而timeout咯

了解了问题发生的缘由解决起来就容易了很多
我把client的ip写在mysql服务器的/etc/hosts文件里
然后随便给他一个名字跟他的ip对应
show processlist
连接数一下子就下来了
而且用户名也不是”unauthenticated user“了,都是真实连接数据库的用户名
页面访问也都正常了

这里其实还有中解决方法
就是在启动mysql的时候加入参数:–skip-name-resolve
写在my.cnf[mysqld]段也可以