MySQL C API 使用(基本函数)
liaoxuefeng SQL
了解了以上基础知识,去包装一些函数用来给c使用
accept_mysql 用来连接数据库
MYSQL accept_mysql()
{
MYSQL mysql;
if(NULL==mysql_init(&mysql)){
err_sys("mysql_init err",__LINE__);
}
if(mysql_library_init(0,NULL,NULL)!=0){
err_sys("mysql_init err",__LINE__);
}
if(NULL==mysql_real_connect(&mysql,"127.0.0.1","root","sss","chatroom",0,NULL,0))
err_sys("mysql_real_connect",__LINE__);
if(mysql_set_character_set(&mysql,"utf8")<0)
err_sys("mysql_set_character_set",__LINE__);
printf("连接数据库成功\n");
return mysql;
}
close_mysql(关闭数据库)
int close_mysql(MYSQL mysql)
{
mysql_close(&mysql);
mysql_library_end();
return 0;
}
use_mysql
return 1 代表没数据
return -1 代表mysql语句出错
(用于查询数据库或者修改数据库中的数据,但这个函数的缺点select是只能打印,不能传出单个数据)
int use_mysql(const char*string,MYSQL mysql)
{
int i;
int ret;
unsigned int num_fields,num_rows;
MYSQL mysql_temp=mysql;
MYSQL_RES *result=NULL;
MYSQL_ROW row;
MYSQL_FIELD *field;
ret=mysql_query(&mysql_temp,string);
if(!ret){
result = mysql_store_result(&mysql_temp);
if(result){
num_rows=mysql_num_rows(result);
if(num_rows==0){
mysql_free_result(result);
return 1;
}
num_fields =mysql_num_fields(result);
while (field=mysql_fetch_field(result)){
printf("%-20s",field->name);
}
printf("\n");
while(row=mysql_fetch_row(result)){
for ( i = 0; i < num_fields; i++){
if(row[i]){
printf("%-20s",row[i]);
}else{
printf("NULL");
}
}
printf("\n");
}
}else{
mysql_free_result(result);
return 1;
}
mysql_free_result(result);
}
else{
fprintf(stderr,"query err\n");
return -1;
}
return 0;
}
而如果想要得到select 的每一个数据,我采取的方法是开辟动态内存,但坏处是调用此函数之后要手动free,会很繁琐,而且内存开辟的位置得在函数里面,因为无法确定有多少行结果,同时只有函数返回0或者返回-2的时候要free。调用函数的时候需要if判断。
调用方式
mysqlMsg*mmsglist=NULL;
int mNum=0;
int ret=mysqlGetMsgByUid(mysql,x,&mmsglist,mMum);
if(ret==-2){
...
if(mmsglist!=NULL){
free(mmsglist);
mmsglist=NULL;
}
}else if(ret==0){
...
if(mmsglist!=NULL){
free(mmsglist);
mmsglist=NULL;
}
}else{
...
}
(如果大家有什么更好的方法可以教教我)
int mysqlGetMsgByUid(MYSQL mysql,int uid,mysqlMsg**mMsgList,int *mNum)
{
int i=0;
int ret;
unsigned int num_fields,num_rows;
MYSQL mysql_temp=mysql;
MYSQL_RES *result=NULL;
MYSQL_ROW row;
MYSQL_FIELD *field;
char table[MYSQL_TABLE_LEN]="message";
char mysql_order[MYSQL_ORDER_MAXLEN];
*mNum=0;
snprintf(mysql_order,MYSQL_ORDER_MAXLEN," select id,uid,type,sid,msg,status,flag from %s \
where uid ='%d' \
",table,uid);
ret=mysql_query(&mysql_temp,mysql_order);
if(!ret){
result = mysql_store_result(&mysql_temp);
if(result){
// num_fields =mysql_num_fields(result);
num_rows= mysql_num_rows(result);
if(num_rows==0){
mysql_free_result(result);
return 1;
}
*mNum=num_rows;
*(mMsgList)=malloc(num_rows*sizeof(mysqlMsg));
memset(*mMsgList,0,sizeof (num_rows*sizeof(mysqlMsg)));
while(row=mysql_fetch_row(result)){
if((!row[0])||(!row[6])||(!row[1])||(!row[2])||(!row[3])||(!row[4])||(!row[5])){
mysql_free_result(result);
fprintf(stderr,"出现 NULL");
return -2;
}
(*(mMsgList)+i)->id=atoi(row[0]);
(*(mMsgList)+i)->recv_id=atoi(row[1]);
(*(mMsgList)+i)->type=atoi(row[2]);
(*(mMsgList)+i)->send_id=atoi(row[3]);
strncpy((*(mMsgList)+i)->message,row[4],MYSQL_MSG_SIZE);
(*(mMsgList)+i)->status=atoi(row[5]);
(*(mMsgList)+i)->flag=atoi(row[6]);
// (*(mMsgList)+i)->recv_id=uid;
i++;
}
}else{
mysql_free_result(result);
return 1;
}
mysql_free_result(result);
}else{
fprintf(stderr,"???query fail\n");
return -1;
}
return 0;
}
聊天室里经常用到的mysql语句
增删改查
insert into xxx(name,xxxx,xx)values(xx,xxx,xxxx);
delete from xxx where x=y;
update xxx set x1=y1,x2=y2
select xxx from xx where x= y;
create table
AUTO_INCREMENT 自增
ENGINE=InnoDB 引擎
PRIMARY KEY (id
) 主键
NOT NULL 的意义(《mysql必知必会》)
不允许 NULL 值的列不接受该列没有值的行,
换句话说,在插入或更新行时,该列必须有值。
use_mysql("create table account(\
id BIGINT NOT NULL AUTO_INCREMENT,\
姓名 varchar(20) NOT NULL ,\
帐号 varchar(20) NOT NULL UNIQUE,\
PRIMARY KEY (`id`)\
)ENGINE=InnoDB
AUTO_INCREMENT=1
DEFAULT CHARSET=utf8",mysql);
在c++中mysql封装成类的确会方便很多,同时它分成了 mysql_noResult_query
,mysql_select_query,mysql_select_SingleLine_query(这个并不必要)三种方式,因为vector,map容器动态扩容的特点,也就不需要上述c版本麻烦的动态内存。
class mysql_db
{
public:
mysql_db();
~mysql_db();
public:
/*
mysql_open()
return : 1 OK
-1 失败
*/
int mysql_open(const char * host, const char * user, const char * password, const char * database, unsigned int port );
/*
mysql_noResult_query();
非select语句查询
return >0 成功, 为受影响的行数
-1 失败
*/
int mysql_noResult_query(const char * sql );
/*
mysql_select_query();
有结果集的查询
return >0 ok 返回结果集条数
-1 失败
map_results first = 行 second = values
*/
int mysql_select_query(const char * sql, map<int,vector<string>> & map_results);
/*
mysql_select_SingleLine_query();
只有一条数据 , 或者只有一个字段 N 条的查询. 直接调用vector即可
*/
int mysql_select_SingleLine_query(const char * sql, vector<string> & v_results);
/*
mysql_lasterror();
返回最近一次错误信息
*/
string mysql_lasterror();
private:
MYSQL sqlCon;
MYSQL_RES *m_pResult;
MYSQL_ROW m_Row;
};
mysql_db::mysql_db() {
mysql_init(&sqlCon);// mysql 初始化
}
mysql_db::~mysql_db() {
mysql_close(&sqlCon);// 关闭连接
}
int mysql_db::mysql_open(const char *host, const char *user, const char *password, const char *database,
unsigned int port) {
char nvalue = 1;
mysql_options(&sqlCon, MYSQL_OPT_RECONNECT, (char *) &nvalue);// 断线自动重连
mysql_options(&sqlCon, MYSQL_SET_CHARSET_NAME, "utf8");
if (!mysql_real_connect(&sqlCon, host, user, password, database, port, NULL, 0)) {
return -1;
}
return 1;
}
int mysql_db::mysql_noResult_query(const char *sql) {
if (mysql_query(&sqlCon, sql) != 0) {
return -1;
}
return (int) mysql_affected_rows(&sqlCon);
}
int mysql_db::mysql_select_query(const char *sql, map<int, vector<string>> &map_results) {
if (mysql_query(&sqlCon, sql) != 0) {
return -1;
}
if(!(m_pResult = mysql_use_result(&sqlCon))){
return -1;
}
int i=0;
int count = mysql_num_fields(m_pResult);
while(m_Row=mysql_fetch_row(m_pResult)){
vector<string>vVal;
for (int j = 0; j < count; ++j) {
if(m_Row[j])
vVal.push_back(m_Row[j]);
else
vVal.push_back("null");
}
map_results[i++]=vVal;
}
mysql_free_result(m_pResult);
return i;
}
int mysql_db::mysql_select_SingleLine_query(const char *sql, vector<string> &v_results) {
if (mysql_query(&sqlCon, sql) != 0) {
return -1;
}
if(!(m_pResult = mysql_use_result(&sqlCon))){
return -1;
}
int count = mysql_num_fields(m_pResult);
while(m_Row=mysql_fetch_row(m_pResult)){
for (int j = 0; j < count; ++j) {
v_results.push_back(m_Row[j]);
}
}
mysql_free_result(m_pResult);
return 0;
}
string mysql_db::mysql_lasterror() {
return mysql_error(&sqlCon);
}
关于表怎么设计,我认为聊天室中的我设计的很不好,9张表,由于我的姓名放在account表,我就没去设计如何换姓名。由于密保放在了account表导致群帐号必须重新建表,而不是和人帐号放一起,还得分出文件表和群文件表这导致了程序更加繁琐。
fri_mask表使用来屏蔽好友消息的不知道是不有点鸡肋。。。
虽说第一次设计的不好,但至少程序能跑,而且有了经验,下次就没这么难了。