MySQL基础2
使用别人的库
mysql头文件
#include <mysql/mysql.h>
生成代码的步骤:编译 -> 链接
调用一个函数的要求
编译:只要有函数声明就可以通过编译
连接:必须右一个函数定义才可以通过链接
在C语言阶段要使用别人的库(环境),需要:
- 提供源码 *.c --> *.o
- 提供静态库或动态库 *.a *.so 链接时加上 -l 选项
学习第三方库的使用
- 在学习第三方库时不要用AI,会有严重的幻觉问题。
- 最权威的资料是官方手册。
- 没有办法的情况下,就只能看源码。
了解数据结构
先看5.2章节
三个类型。先和Mysql服务端进行连接,结果为行的集合,而每一行在数据库中是字符串数组形式存在的。
和MySQL相关的操作
mysql_init(MYSQL *mysql)
给MYSQL类型的变量去申请内存 --> 线程不安全(需要在操作中加入锁)
mysql_real_connect(MYSQL *mysql)
建立连接
- mysql : init的返回值
- host : "localhost"
- user : "root"
- passwd : "用户自己的密码"
- db: database的名字
- 其余参数填0或者NULL
mysql_close()
关闭连接,释放资源。
mysql中检查失败
和C中的stderr()相似,会将报错信息以字符串提示
int ret = mysql_real_connect( …………………… ); if(ret ==NULL ){fprintf(stderr,"%s:%s\n","mysql_real_connect",mysql_error(mysql));exit(-1); }
执行指令
- 用c风格的字符串去存储一个SQL语句
- 调用mysql_query()
实现动态SQL语句
难点变成了字符串的拼接
代码实现:
#include <my_header.h> #include <mysql/mysql.h> /* Usage: */ int main(int argc, char *argv[]){ MYSQL *mysql = mysql_init(NULL);MYSQL *ret = mysql_real_connect(mysql,"localhost","root","123","sql_work_day2",0,NULL,0);if(ret == NULL){fprintf(stderr,"[%s] %s\n","mysql_real_connect",mysql_error(mysql));exit(-1);}char id[1024];char name[1024];printf("请输入id\n"); fgets(id,1024,stdin);printf("请输入name\n");fgets(name,1024,stdin);id[strlen(id)-1] = '\0';name[strlen(name)-1] = '\0';char sql[4096] = {0};sprintf(sql,"insert into test (id,name) values ('%s','%s');",id,name);int qret = mysql_query(mysql,sql);if(qret !=0){fprintf(stderr,"[%s] %s\n","mysql_query",mysql_error(mysql));exit(-1);}mysql_close(mysql);return 0; }
Makefile文件:在编译链接时加入指令 -lmysqlclient
SRCS := $(wildcard *.c) OUTS := $(patsubst %.c,%,$(SRCS)) CC := gcc COM_OP := -Wall -g -lmysqlclient .PHONY: clean rebuild allall: $(OUTS) % : %.c$(CC) $^ -o $@ $(COM_OP)clean:$(RM) $(OUTS)rebuild: clean all
结果:成功插入
可能面临的风险:sql注入
sql注入
如果在运行程序时,客户输入了形如:
大碗宽面);delete from test;
会造成严重后果
读类型返回指令
返回一个表格 show/desc/select
只有读类型的指令,在执行完mysql_query之后,要调用mysql_store_result返回一个结果,取出的结果是一个行的集合。
- mysql_num_field() : 获取列数
- mysql_fetch_row() : 获取一行
- mysql_num_rows() :获取行数
一行的底层是字符串数组,使用 [ ] 就可以将字符串数组内容提取出来。
一般表格的行数远远多于列数,因此使用长整型接收行数。随后可以利用获取一行mysql_fetch_row(),遍历各行。任何mysql的数据类型都转换成了c里面的自符串。
代码实现:
#include <my_header.h> #include <mysql/mysql.h> /* Usage: */ int main(int argc, char *argv[]){ MYSQL *mysql = mysql_init(NULL);MYSQL *ret = mysql_real_connect(mysql,"localhost","root","123","sql_work_day2",0,NULL,0);if(ret == NULL){fprintf(stderr,"[%s] %s\n","mysql_real_connect",mysql_error(mysql));exit(-1);}char sql[]= "select * from test;";int qret = mysql_query(mysql,sql);if(qret != 0){fprintf(stderr,"[%s] %s\n","mysql_query",mysql_error(mysql));exit(-1);}MYSQL_RES *rows = mysql_store_result(mysql);printf("row = %ld, col = %d\n",mysql_num_rows(rows),mysql_num_fields(rows));for(unsigned long i = 0;i<mysql_num_rows(rows);i++){MYSQL_ROW row = mysql_fetch_row(rows);for(unsigned int j=0; j<mysql_num_fields(rows);j++){printf("%s\t",row[j]);}printf("\n");}mysql_close(mysql);return 0; }
实现结果:
总结
- mysql_init()
- mysql_real_connect()
- 准备一个字符串,里面放sql语句insert
- mysql_query
- 如果是读语句:mysql_store_result语句。mysql_num_field() : 获取列数。mysql_fetch_row() : 获取一行。mysql_num_rows() :获取行数
- mysql_close()
把mysql接入线程池
- 每个线程执行一次mysql_init()和mysql_real_connect(),确保每个线程拿到的连接是不同的,后续就不用再加锁。
- 每个线程启动的时候做一次mysql_init和mysql_real_connect,之后这个连接可以重复使用,不需要多次重复连接。
- 多线程有内存踩踏的风险,建议再mysql_init()之前加锁lock,在msql_real_connect()之后解锁unlock
连续执行mysql_query()可能会有问题
如果前一个mysql_query做的是读类型指令,并且在下一次执行mysql_query的时候没有执行mysql_store_result,那么就会报错。
清空表
truncate 表名;
指令是DDL,删除更彻底