linux下多线程连接mysql(C语言)
代码使用了pthread库,在Ubuntu环境下使用gcc编译并运行成功。
增加的编译选项 -lpthread -Llibmysqlclient_r.so
后者是mysql 的线程安全链接库。
原有代码嵌入在一个应用程序中,这里只给出数据库访问部分。
关键是每个线程维护一个单独的MYSQL结构,并初始化线程专用数据,由于mysql_real_connect会自动调用mysql_thread_init(),函数里面不再重复调用。
int main()
{
mysql_library_init(0,NULL,NULL);
pthread_t producer;
pthread_t consumer_1;
pthread_t consumer_2;
//produce_fun不涉及数据库链接,不贴出来
pthread_create(&producer,NULL,produce_fun,NULL);
pthread_create(&consumer_1,NULL,consume_fun,NULL);
pthread_create(&consumer_2,NULL,consume_fun,NULL);
//下面的三句非常重要,main线程等待其他三个线程的结束,避免main线程执行到mysql_library_end时退出,而
//其他三个线程仍然在运行并报错的情形
pthread_join(producer,NULL);
pthread_join(consumer_1,NULL);
pthread_join(consumer_2,NULL);
mysql_library_end();
return 0;
}
void addRecord_d(MYSQL *ptr_db,const char *t_name,int item){
char query_buffer[100];
sprintf(query_buffer,"insert into %s values(0,%d)",t_name,item);
int ret=mysql_query(ptr_db,query_buffer);
if(ret){
fprintf(stderr,"%s%s\n","cannot add record to ",t_name);
return;
}
unsigned long long update_id=mysql_insert_id(ptr_db);
printf("add record (%llu,%d) ok.",update_id,item);
}
void * consume_fun(void *arg){
MYSQL db;
MYSQL *ptr_db=mysql_init(&db);
mysql_real_connect();
//蓝色部分可以改为其他任何带操作数据库语句的代码
//procedure
while(1){
printf("consumer...");
int item=consume(&p);
addRecord_d(ptr_db,"test",item);
}
mysql_thread_end();
pthread_exit(NULL);
}
//MYSQL_RES保存查询结构
MYSQL_RES* result_ = NULL;
int error_code = 0; //保存错误码
char error_info[1024] = '\0'; //保存错误信息
//对mysql数据库进行查询操作:
char query_sql[1024] = "select * from db_name.table_name"; //构建查询sql语句
if(result_ != NULL) //防止之前已经被使用过(所有的使用,在使用前都要判空)
{
mysql_free_result(result_);
result_ = NULL;
}
if(link_ == NULL) //防止没有链接
{
//重连,按照建立mysql数据库链接的方法进行建立,前面的blog中有讲到
}
//执行sql查询
if(mysql_query(link_,query_sql) != 0)
{
//查询失败
error_code = mysql_errno(link_); //获取错误码
strncpy(error_info,mysql_error(link_),1024); //获取错误信息
if((error_code == 2013) || (error_code == 2006)) //2006 mysql服务器不可用,2013查询过程中,丢失链接
{
//重链,按照建立mysql数据库链接的方法进行建立
if(//重链失败)
{
return false;
}
//重链成功,再次查询
if(mysql_query(link_,query_sql) != 0)
{
//再次查询失败
error_code = mysql_errno(link_);
strncpy(error_info,mysql_error(link_),1024);
//返回错误
return false;
}
error_code = 0; //查询成功了。
}
}
else
{
//查询成功
}
//查询成功,保存查询结果
result_ = mysql_store_result(link_);
if(result_ == NULL)
{
error_code = mysql_errno(link_); //获取错误码
strncpy(error_info,mysql_error(link_),1024); //获取错误信息
//返回错误
return false;
}
//获取查询结果的行数(记录数)
return mysql_num_rows(result_);
//获取查询结果的字段数
return mysql_num_fields(result_);
//获取查询结果的各个字段的字段名称
MYSQL_FIELD *fields; //保存字段名字信息
unsing int num_fields;
unsigned int i;
num_fields = mysql_num_fields(result); //获取查询结果中,字段的个数
fields = mysql_fetch_fields(result); //获取查询结果中,各个字段的名字
for(i = 0; i < num_fields;i++)
{
printf("field %u is %s\n",i,fields[i].name);
}
//获取查询出来的结果,即遍历查询到的每一行记录
MYSQL_ROW row; //保存行记录信息
unsigned int num_fields;
unsigned int i;
num_fields = mysql_num_fields(result_);
while((row = mysql_fetch_row(result_))) //遍历查询结果中的各行记录
{
unsigned long *lengths = NULL;
lengths = mysql_fetch_lengths(result_); //获取每一个记录行中,每一个字段的长度,在lengths数组中。
for( i = 0; i < num_fields; i++)
{
printf("数据长度%u \t 数据内容%s",lengths[i],row[i]?row[i]:"NULL");
}
printf("\n");
}
//释放资源,断开链接
if(result_ != NULL)
{
mysql_free_result(result_);
result_ = NULL;
}
if(link_ != NULL)
{
mysql_close(link_);
link_ = NULL;
}
使用mysql C语言API编写程序—建立mysql数据库链接(超时设定,建立链接)
//MYSQL句柄 (任何一个mysql操作都是基于MYSQL这个句柄来操作的)
MYSQL* link_ = NULL;
//对mysql操作进行必要的初始化
if(link_ != NULL)
{
mysql_close(link_);
}
link_ = mysql_init(NULL); //初始化MYSQL句柄
//设置超时时间(链接超时时间,查询超时时间,写数据库超时时间)
int timeout_ = 3; //超时时间设置为3秒
if(link_ != NULL)
{
mysql_options(link_,MYSQL_OPT_CONNECT_TIMEOUT,(const char *)&timeout_);
//设置链接超时时间.
mysql_options(link_,MYSQL_OPT_READ_TIMEOUT,(const char *)&timeout);
//设置查询数据库(select)超时时间
mysql_options(link_,MYSQL_OPT_WRITE_TIMEOUT,(const char *)&timeout);
//设置写数据库(update,delect,insert,replace等)的超时时间。
}
//真正建立mysql链接
char host_name[1024] = "192.168.123.236"; //mysql服务器的IP
char user_name[1024] = "chenbaihu"; //用户名
char user_password[1024] = "xy871202"; //密码
unsigned short host_port = 3306; //服务器端口
int error_code;
char error_info[1024];
if(!mysql_real_connect(link_,host_name,user_name,user_password,NULL,host_port,NULL,0))
{
//失败处理
error_code = mysql_errno(link_); //获取错误码
strncpy(error_info,mysql_error(link_),1024); //获取错误信息
mysql_close(link_); //释放句柄
link_ = NULL;
}
else
{
//链接建立成功,可以进行具体的操作(select insert delete update replace等)
}
mysql—开发C,C++程序,避免连接超时、读数据库超时、写数据库超时,系统再也不怕被MySQL服务器挂死
避免连接超时: //可以用采用停掉mysqld或iptables封掉端口测试。
int g_iTimeOut = 5;
mysql_options(&mysql_, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&g_iTimeOut);
避免读超时: //可以采用对表加写锁 lock table tablename write 或killall -STOP mysqld等来进行测试。
int g_iTimeOut = 5;
mysql_options(&mysql_, MYSQL_OPT_READ_TIMEOUT, (const char *)&g_iTimeOut);
避免写超时: //可以采用对表加写锁 lock table tablename write 或killall -STOP mysqld等来进行测试。
int g_iTimeOut = 5;
mysql_options(&mysql_, MYSQL_OPT_WRITE_TIMEOUT, (const char *)&g_iTimeOut);
注意mysql API版本的问题::
虽然很多版本都支持上面的控制,但是建议还是使用MySQL 5.1.12及以上版本。
Mysql乱码—字段编码(filed)、表编码(table)、数据库编码(db)、数据库服务器(dbserver)编码
Mysql数据库 2010-11-28 11:09:43 阅读38 评论0 字号:大中小 订阅
Mysql数据库的编码分为四级:
1、Mysql数据库服务器编码;
(在相应的配置文件中,需要修改配置文件)
2、Mysql数据库编码;
(可以在创建的时候指定,也可以在创建之后进行修改)
3、Mysq数据库中表的编码;
(可以在创建的时候指定,也可以在创建之后进行修改)
4、Mysql数据库表中字段的编码;
(可以在创建的时候指定,也可以在创建之后进行修改)
数据库编码选择的一般准则:
1、GBK/GB2312
适合纯中文存储的数据库
2、LATIN1
适合于纯英文的存储
3、UTF8
适合中英文混合编码的存储。
创建数据库并指定编码: (数据库)
方法1、
creat database db_name default character set utf8
方法2、
create database db_name default charset=utf8
创建表并指定编码: (表)
方法1、
create table table_name
(
......//字段信息
)default character set utf8;
方法2、
create table table_name
(
......//字段信息
)default charset=utf8;
指定字段的编码: (字段) 仅有一种方法
方法:
create table table_name
(
filed_name varchar(20) character set utf8 //注意不能有default
);
MySQL++ 一个成熟的C++封装
MySQL++: MySQL++
MySQL++: MySQL++
一些用例:
1. 使用方便
一个头文件
#include <mysql++.h>
一个库
libmysqlpp
2. 方便的数据访问
#include <mysql++.h>
mysqlpp::Connection conn(db, server, user, pass);
mysqlpp::Query query = conn.query();
query << "SELECT devid, md5value from t_snmp_index limit 10";
mysqlpp::StoreQueryResult res = query.store();
mysqlpp::StoreQueryResult::const_iterator it;
for (size_t i = 0; i < res.num_rows(); ++i)
{
cout << res[i]["devid"] << "\t" << res[i]["md5value"] << endl; //通过字段名访问
}
//===> or
for (size_t i = 0; i < res.num_rows(); ++i)
{
cout << res[i][0] << "\t" << res[i][1] << endl; //通过列数访问字段名
}
3. sql模板
#include <mysql++.h>
//建立mysql链接
mysqlpp::Connection conn(db, server, user, pass);
//实现mysql查询 方法1
string sqltemplate = "select devid, md5value from %s limit %d, 10";
char buf[1024];
snprintf(buf, sizeof(buf), sqltemplate.c_str(), tablename, index);
mysqlpp::Query query = conn.query(buf);
mysqlpp::StoreQueryResult res1 = query.store();
//===> or
//实现mysql查询 方法2
mysqlpp::Query query = conn.query();
query << "SELECT devid, md5value from %0 limit %1q, 10";
query.parse();
mysqlpp::StoreQueryResult res1 = query.store(tablename, index);
4. 与stl的融合
#include <mysql++.h>
#include <ssqls.h>
// 生成struct SNMP
sql_create_6(SNMP,
1, 6,
mysqlpp::sql_int, devid,
mysqlpp::sql_int, attrid,
mysqlpp::sql_varchar, snmp_index,
mysqlpp::sql_varchar, index_name,
mysqlpp::sql_varchar, port_type,
mysqlpp::sql_char, md5value)
// 结果保存在vector中
vector<SNMP> v;
mysqlpp::Connection conn(db, server, user, pass);
mysqlpp::Query query = conn.query();
query << "SELECT * from t_snmp_index limit 10";
query.storein(v);
for (vector<SNMP>::iterator it = v.begin(); it != v.end(); ++it) {
cout << it->devid
<< "\t" << it->attrid
<< "\t" << it->snmp_index
<< "\t" << it->index_name
<< "\t" << it->port_type
<< "\t" << it->md5value
<< endl;
}