Dec
13
@2012.12.31 更多细节参见这篇.
根据官方文档:
也就是说,不管是哪个版本,希望启用MYSQL_OPT_RECONNECT,都应该调用mysql_options()明确设置它。由于一个BUG,5.0.19之前必须在mysql_real_connect()之后设置,而更新的版本则可以在mysql_real_connect之前设置。
这里的坑是,在没有设置了RECONNECT时,mysql_ping()并不会自动重连。
因此最完整的解决方法是:
1. 在使用mysql_real_connect连接数据库之后,再使用mysql_options( &mysql, MYSQL_OPT_RECONNECT, … ) 来设置为自动重连。这样当mysql连接丢失的时候,使用mysql_ping能够自动重连数据库。
示例代码:
2. 在执行查询的之前使用mysql_ping()确保自动重连。(但是这个是必要的吗?找不到相应的说明。。。)
UPDATE@2012.12.30:原来之前有很多误解(认为是5.1.6之后就不需要设置MYSQL_OPT_RECONNECT),多谢@Zind同学提醒,这篇基本上是重写了。。。
根据官方文档:
引用
MYSQL_OPT_RECONNECT (argument type: my_bool *)
Enable or disable automatic reconnection to the server if the connection is found to have been lost. Reconnect has been off by default since MySQL 5.0.3; this option is new in 5.0.13 and provides a way to set reconnection behavior explicitly.
#如果连接丢失,启用或禁用自动重连到Serve,。自5.0.3之后,重连默认被禁用。这个选项是5.0.13新增的,提供了明确设置重连行为的选项。
Note: mysql_real_connect() incorrectly reset the MYSQL_OPT_RECONNECT option to its default value before MySQL 5.0.19. Therefore, prior to that version, if you want reconnect to be enabled for each connection, you must call mysql_options() with the MYSQL_OPT_RECONNECT option after each call to mysql_real_connect(). This is not necessary as of 5.0.19: Call mysql_options() only before mysql_real_connect() as usual.
#注意:mysql_real_connect() 在5.0.19之前错误地重置了MYSQL_OPT_RECONNECT选项为默认值(不启用),因此,在5.0.19之前,如果你希望为连接启用重连,你必须在mysql_real_connect()之后调用mysql_options来设置MYSQL_OPT_RECONNECT。5.0.19之后就不需要这样了,只需要(跟其他选项一样)在mysql_real_connect之前调用即可。
Enable or disable automatic reconnection to the server if the connection is found to have been lost. Reconnect has been off by default since MySQL 5.0.3; this option is new in 5.0.13 and provides a way to set reconnection behavior explicitly.
#如果连接丢失,启用或禁用自动重连到Serve,。自5.0.3之后,重连默认被禁用。这个选项是5.0.13新增的,提供了明确设置重连行为的选项。
Note: mysql_real_connect() incorrectly reset the MYSQL_OPT_RECONNECT option to its default value before MySQL 5.0.19. Therefore, prior to that version, if you want reconnect to be enabled for each connection, you must call mysql_options() with the MYSQL_OPT_RECONNECT option after each call to mysql_real_connect(). This is not necessary as of 5.0.19: Call mysql_options() only before mysql_real_connect() as usual.
#注意:mysql_real_connect() 在5.0.19之前错误地重置了MYSQL_OPT_RECONNECT选项为默认值(不启用),因此,在5.0.19之前,如果你希望为连接启用重连,你必须在mysql_real_connect()之后调用mysql_options来设置MYSQL_OPT_RECONNECT。5.0.19之后就不需要这样了,只需要(跟其他选项一样)在mysql_real_connect之前调用即可。
也就是说,不管是哪个版本,希望启用MYSQL_OPT_RECONNECT,都应该调用mysql_options()明确设置它。由于一个BUG,5.0.19之前必须在mysql_real_connect()之后设置,而更新的版本则可以在mysql_real_connect之前设置。
这里的坑是,在没有设置了RECONNECT时,mysql_ping()并不会自动重连。
因此最完整的解决方法是:
1. 在使用mysql_real_connect连接数据库之后,再使用mysql_options( &mysql, MYSQL_OPT_RECONNECT, … ) 来设置为自动重连。这样当mysql连接丢失的时候,使用mysql_ping能够自动重连数据库。
示例代码:
mysql_init() ...
mysql_real_connect()...
char value = 1;
mysql_options(&mysql, MYSQL_OPT_RECONNECT, (char *)&value);
mysql_real_connect()...
char value = 1;
mysql_options(&mysql, MYSQL_OPT_RECONNECT, (char *)&value);
2. 在执行查询的之前使用mysql_ping()确保自动重连。(但是这个是必要的吗?找不到相应的说明。。。)
UPDATE@2012.12.30:原来之前有很多误解(认为是5.1.6之后就不需要设置MYSQL_OPT_RECONNECT),多谢@Zind同学提醒,这篇基本上是重写了。。。
Nov
3
这里委屈MySQL一下,只是想测试,如果二者用于比较纯粹的key/value存储,性能如何。
机器配置:RHEL5.6
AMD Opteron(tm) 6128HE 2GHz, 32G RAM,
HDD(应该不是SSD,7200还是10000rpm不知道)
连续读54.5 MB/s (dd if=/dev/zero of=test bs=1048576 count=512)
====
MySQL: 使用源码附带的的 my-medium.cnf 配置
CREATE TABLE nn (k INTEGER PRIMARY KEY, v INTEGER); #默认MyISAM引擎
100,000条数据
INSERT: 4k QPS, 24.45s #类似于 INSERT INTO nn VALUES (42, 42)
UPDATE: 2.7k QPS, 36.00s #类似于 UPDATE nn SET v=43 WHERE k=42
SELECT(key随机): 3.3k QPS, 31.22s #类似于 SELECT * FROM nn WHERE k=42
空间占用:1.9M 其中数据879K,索引1004K
5,000,000 条数据 (不测试INSERT和UPDATE了……)
LOAD: 32.8万条/s, 15.25s # LOAD DATA INFILE '/tmp/data' INTO TABLE nn (k, v)
SELECT(10w次, key随机): 4k QPS, 25.49s
空间占用:92M 其中数据43M,索引49M
以上测试除了MySQL Load之外完全使用C代码调用MySQL的官方C API
====
Berkeley DB(BTree, 没测hash):
100w条插入:15.9s, 62.9k QPS
100w条查询(key随机):8.69s, 115k QPS
空间占用:100w=>25M, 1000w=>259M, 2亿=>5.4G
p.s. 如果把cache_size设置为512MB的话,插入基本都在内存中完成,100w跳只需要大约2.64s,378.6k QPS,和MySQL在同一个级别。
以上测试使用c编码完成,使用默认参数,没有设置内存占用大小。
Python使用bsddb模块效率约是c的50%。
机器配置:RHEL5.6
AMD Opteron(tm) 6128HE 2GHz, 32G RAM,
HDD(应该不是SSD,7200还是10000rpm不知道)
连续读54.5 MB/s (dd if=/dev/zero of=test bs=1048576 count=512)
====
MySQL: 使用源码附带的的 my-medium.cnf 配置
CREATE TABLE nn (k INTEGER PRIMARY KEY, v INTEGER); #默认MyISAM引擎
100,000条数据
INSERT: 4k QPS, 24.45s #类似于 INSERT INTO nn VALUES (42, 42)
UPDATE: 2.7k QPS, 36.00s #类似于 UPDATE nn SET v=43 WHERE k=42
SELECT(key随机): 3.3k QPS, 31.22s #类似于 SELECT * FROM nn WHERE k=42
空间占用:1.9M 其中数据879K,索引1004K
5,000,000 条数据 (不测试INSERT和UPDATE了……)
LOAD: 32.8万条/s, 15.25s # LOAD DATA INFILE '/tmp/data' INTO TABLE nn (k, v)
SELECT(10w次, key随机): 4k QPS, 25.49s
空间占用:92M 其中数据43M,索引49M
以上测试除了MySQL Load之外完全使用C代码调用MySQL的官方C API
====
Berkeley DB(BTree, 没测hash):
100w条插入:15.9s, 62.9k QPS
100w条查询(key随机):8.69s, 115k QPS
空间占用:100w=>25M, 1000w=>259M, 2亿=>5.4G
p.s. 如果把cache_size设置为512MB的话,插入基本都在内存中完成,100w跳只需要大约2.64s,378.6k QPS,和MySQL在同一个级别。
以上测试使用c编码完成,使用默认参数,没有设置内存占用大小。
Python使用bsddb模块效率约是c的50%。
Oct
27
每天备份一次数据库;删除5天之前的备份;每逢周一将备份好的数据库发送到邮箱。
p.s. uuencode是sharutils这个软件包里面的。yum或者apt-get都可以直接安装。
#!/bin/bash
dbhost=127.0.0.1
dbuser=user
dbpass=pass
dbname=dbname
dir=~/backupdir/
fname=$dir/db_`date +%Y-%m-%d`.sql
fname1=$dir/db_`date +%Y-%m-%d -d "5 days ago"`.sql.bz2
mysqldump -h $dbhost -u $dbuser -p$dbpass --databases $dbname > $fname
bzip2 $fname
rm -rf $fname1
day=`date +%A`
fname=$fname.bz2
if [ $day == "Monday" ]; then
uuencode $fname `basename $fname` | mail -t some@gmail.com -s "[`date +%Y-%m-%d`] Database Backup"
fi
dbhost=127.0.0.1
dbuser=user
dbpass=pass
dbname=dbname
dir=~/backupdir/
fname=$dir/db_`date +%Y-%m-%d`.sql
fname1=$dir/db_`date +%Y-%m-%d -d "5 days ago"`.sql.bz2
mysqldump -h $dbhost -u $dbuser -p$dbpass --databases $dbname > $fname
bzip2 $fname
rm -rf $fname1
day=`date +%A`
fname=$fname.bz2
if [ $day == "Monday" ]; then
uuencode $fname `basename $fname` | mail -t some@gmail.com -s "[`date +%Y-%m-%d`] Database Backup"
fi
p.s. uuencode是sharutils这个软件包里面的。yum或者apt-get都可以直接安装。
Apr
10
安装bo-blog的时候还不太懂编码的问题,于是数据库的编码就选择了按照服务器的设置存取。
于是在phpmyadmin里面看到的数据,只要遇到中文,全部都是乱码,郁闷。
花了一点时间,转换了一下:
1。用我的那个后台管理程序,它有数据库备份功能,备份出来的就是UTF-8编码的了。
2。修改数据库编码。直接在phpmyadmin里面修改,或者运行
3。导入第一步备份出来的数据库文件。
4。对于bo-blog,还需要修改data/config.php里面的$db_410,把后面的"0"改成"1"
哦也,问题解决拉~
于是在phpmyadmin里面看到的数据,只要遇到中文,全部都是乱码,郁闷。
花了一点时间,转换了一下:
1。用我的那个后台管理程序,它有数据库备份功能,备份出来的就是UTF-8编码的了。
2。修改数据库编码。直接在phpmyadmin里面修改,或者运行
ALTER DATABASE `dbname` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci
3。导入第一步备份出来的数据库文件。
4。对于bo-blog,还需要修改data/config.php里面的$db_410,把后面的"0"改成"1"
哦也,问题解决拉~
Mar
13
花了n久的时间终于搞清楚了,丫丫的,真麻烦
编译:
这个mysql目录是某个mysql的源码目录,如果有安装mysql-devel可能是在/usr/ooxx/mysql,没有的话自己去down源码
编译:
引用
g++ -Imysql/include -Lmysql/lib -o a.out a.cpp -lmysqlclient -lz
这个mysql目录是某个mysql的源码目录,如果有安装mysql-devel可能是在/usr/ooxx/mysql,没有的话自己去down源码
#include<iostream>
#include<string>
#include<fstream>
#include"mysql.h"
using namespace std;
MYSQL * conn = NULL; //MySQL连接句柄
//读取配置
bool read_conf(string &dbhost,
string &dbuser,
string &dbpass,
string &dbname){
ifstream is("judge.conf");
is >> dbhost >> dbuser >> dbpass >> dbname;
return true;
}
bool query(){
int status, state, state2;
MYSQL_RES * res;
MYSQL_ROW row;
string cmd;
MYSQL *conn, mysql;
string dbhost, dbuser, dbpass, dbname;
if(read_conf(dbhost,dbuser, dbpass, dbname)){ //读取数据库
if (mysql_init(&mysql) == NULL){
fprintf(stderr, "初始化错误\n");
return false;
}
conn = mysql_real_connect(&mysql, dbhost.c_str(), dbuser.c_str(),
dbpass.c_str(), dbname.c_str(), NULL,
"/var/run/mysqld/mysqld.sock", 0);
if(conn == NULL){ //连接失败
fprintf(stderr, "连接失败!\n");
return false;
}
}else{ //读取配置失败
fprintf(stderr, "读取配置失败!\n");
return false;
}
cmd = "SELECT OOXX FROM OOXX";
cout << "Command: " << cmd << endl;
state = mysql_query(conn, cmd.c_str());
cout << "state: " << state << endl;
if(state != 0){//查询出错
fprintf(stderr, "%s\n", mysql_error(conn));
return false;
}
res = mysql_store_result(conn);
cout << "affected_rows:" << conn->affected_rows << endl;
while(row = mysql_fetch_row(res), row != NULL){
printf("%s\n", row[0]);
}
return true;
}
int main(){
query();
return 0;
}
#include<string>
#include<fstream>
#include"mysql.h"
using namespace std;
MYSQL * conn = NULL; //MySQL连接句柄
//读取配置
bool read_conf(string &dbhost,
string &dbuser,
string &dbpass,
string &dbname){
ifstream is("judge.conf");
is >> dbhost >> dbuser >> dbpass >> dbname;
return true;
}
bool query(){
int status, state, state2;
MYSQL_RES * res;
MYSQL_ROW row;
string cmd;
MYSQL *conn, mysql;
string dbhost, dbuser, dbpass, dbname;
if(read_conf(dbhost,dbuser, dbpass, dbname)){ //读取数据库
if (mysql_init(&mysql) == NULL){
fprintf(stderr, "初始化错误\n");
return false;
}
conn = mysql_real_connect(&mysql, dbhost.c_str(), dbuser.c_str(),
dbpass.c_str(), dbname.c_str(), NULL,
"/var/run/mysqld/mysqld.sock", 0);
if(conn == NULL){ //连接失败
fprintf(stderr, "连接失败!\n");
return false;
}
}else{ //读取配置失败
fprintf(stderr, "读取配置失败!\n");
return false;
}
cmd = "SELECT OOXX FROM OOXX";
cout << "Command: " << cmd << endl;
state = mysql_query(conn, cmd.c_str());
cout << "state: " << state << endl;
if(state != 0){//查询出错
fprintf(stderr, "%s\n", mysql_error(conn));
return false;
}
res = mysql_store_result(conn);
cout << "affected_rows:" << conn->affected_rows << endl;
while(row = mysql_fetch_row(res), row != NULL){
printf("%s\n", row[0]);
}
return true;
}
int main(){
query();
return 0;
}
Dec
29
据说MySQL是从v4.0开始支持事务(Transaction)的,一直没去试过。
今天心血来潮,于是就玩了一下。
首先,mysql里面有一个状态量叫做 autocommit ,默认值是1
也就是说,当你提交一个SQL语句以后,这条语句会被立即执行并修改数据库内容(如果有必要的话)。
所以如果你想要开始一个事务,那么首先应该把这个东东设置为0,有这么几种方法:
1. 提交SQL语句 START TRANSACTION;
2. 提交SQL语句 BEGIN;
3. 提交SQL语句 SET AUTOCOMMIT=0;
4. (PHP) mysqli_autocommit($conn, false);
然后就可以开始进行你想做的数据库修改了,比如INSERT, UPDATE, DELETE
修改完以后,如果返回的结果有不对劲的地方,OK,试试
1. 提交SQL语句 ROLLBACK;
2. 或者(PHP) mysqli_rollback($conn);
然后你就会发现数据库好像根本没有操作过似的
(其实仔细观察的话会发现auto_increment那个字段的max值变大了-____-)
如果一切OK,那么就用这个:
1. 提交SQL语句 COMIIT;
2. 或者(PHP) mysqli_commit($conn);
注意,在提交COMMIT以后,数据库的改动就正式写到硬盘,不能撤销啦。
给俩例子吧:
a. 在MySQL命令行下进行的操作
OK,再来个PHP版本的:
今天心血来潮,于是就玩了一下。
首先,mysql里面有一个状态量叫做 autocommit ,默认值是1
也就是说,当你提交一个SQL语句以后,这条语句会被立即执行并修改数据库内容(如果有必要的话)。
所以如果你想要开始一个事务,那么首先应该把这个东东设置为0,有这么几种方法:
1. 提交SQL语句 START TRANSACTION;
2. 提交SQL语句 BEGIN;
3. 提交SQL语句 SET AUTOCOMMIT=0;
4. (PHP) mysqli_autocommit($conn, false);
然后就可以开始进行你想做的数据库修改了,比如INSERT, UPDATE, DELETE
修改完以后,如果返回的结果有不对劲的地方,OK,试试
1. 提交SQL语句 ROLLBACK;
2. 或者(PHP) mysqli_rollback($conn);
然后你就会发现数据库好像根本没有操作过似的
(其实仔细观察的话会发现auto_increment那个字段的max值变大了-____-)
如果一切OK,那么就用这个:
1. 提交SQL语句 COMIIT;
2. 或者(PHP) mysqli_commit($conn);
注意,在提交COMMIT以后,数据库的改动就正式写到硬盘,不能撤销啦。
给俩例子吧:
a. 在MySQL命令行下进行的操作
mysql> use t;
mysql> CREATE TABLE `test`(`id` int primary key auto_increment, `name` char(50));
mysql> START TRANSACTION;
mysql> INSERT INTO `test` VALUES (NULL, 'a');
mysql> COMMIT; #或者 mysql> ROLLBACK;
mysql> SELECT * FROM `test`;
看看效果如何?mysql> CREATE TABLE `test`(`id` int primary key auto_increment, `name` char(50));
mysql> START TRANSACTION;
mysql> INSERT INTO `test` VALUES (NULL, 'a');
mysql> COMMIT; #或者 mysql> ROLLBACK;
mysql> SELECT * FROM `test`;
OK,再来个PHP版本的:
<?php
$conn = new mysqli("localhost", "root", "123456", "t");
$conn->autocommit(false);
$res = $conn->query("INSERT INTO `test` VALUES(NULL, 'a')");
if($res)
$conn->commit();
else
$conn->rollback();
$conn->close();
?>
$conn = new mysqli("localhost", "root", "123456", "t");
$conn->autocommit(false);
$res = $conn->query("INSERT INTO `test` VALUES(NULL, 'a')");
if($res)
$conn->commit();
else
$conn->rollback();
$conn->close();
?>
Nov
5
Cannot connect to the mysql server.Error:
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
cpp可以正常编译,但是在连接数据库时会出现这个错误
是因为没有在mysql_real_connect里面指定参数,应该这样:
mysql_real_connect(ssock,"localhost","root","password","databaseName",0,"/tmp/mysql.sock",0)
如果是在mysql -uroot -p的时候出现这个错误
则应该查看一下mysql的配置文件,找到socket文件的位置如 /tmp/mysql.sock
然后 mysql -uroot -p --socket=/tmp/mysql.sock
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
cpp可以正常编译,但是在连接数据库时会出现这个错误
是因为没有在mysql_real_connect里面指定参数,应该这样:
mysql_real_connect(ssock,"localhost","root","password","databaseName",0,"/tmp/mysql.sock",0)
如果是在mysql -uroot -p的时候出现这个错误
则应该查看一下mysql的配置文件,找到socket文件的位置如 /tmp/mysql.sock
然后 mysql -uroot -p --socket=/tmp/mysql.sock
Oct
6
所以在给whumstc做图书馆藏书情况查询系统的时候
因为觉得用SELECT COUNT(*) FROM `ooxx`是很耗时的
所以就没有做过多的分页功能,只做了首页/上页/下页/跳页。
现在发现我的想法非常愚蠢 - 会如此频繁使用的功能,MySQL怎会不优化呢
不过当时(十一)是在老家,没有网络不能查。
今天想起这个问题,于是google了一下,答案是:
使用MYISAM存储引擎的表,会保存表的记录数。
如果使用SELECT COUNT(*) FROM `table_name`;语句进行查询的时候
会直接返回该记录数。
注意使用InnoDB引擎存储的表没有这个功能
这条SQL语句也不能加上WHERE限定语句,否则将要扫描所有记录。
专门看了一下MySQL Manual的Chapter 7.2.4 MySQL怎样优化WHERE子句, 很有收获。
因为觉得用SELECT COUNT(*) FROM `ooxx`是很耗时的
所以就没有做过多的分页功能,只做了首页/上页/下页/跳页。
现在发现我的想法非常愚蠢 - 会如此频繁使用的功能,MySQL怎会不优化呢
不过当时(十一)是在老家,没有网络不能查。
今天想起这个问题,于是google了一下,答案是:
使用MYISAM存储引擎的表,会保存表的记录数。
如果使用SELECT COUNT(*) FROM `table_name`;语句进行查询的时候
会直接返回该记录数。
注意使用InnoDB引擎存储的表没有这个功能
这条SQL语句也不能加上WHERE限定语句,否则将要扫描所有记录。
专门看了一下MySQL Manual的Chapter 7.2.4 MySQL怎样优化WHERE子句, 很有收获。






