/*******************************************************************************************/
一、mysql的安装
0.下载
MySQL数据库版本相对比较繁杂。常见的有:Community社区版、Enterprise企业版。
Community版是开源免费的,这也是我们通常用的MySQL的版本。可以满足绝大多数用户需求。
Enterprise版,官方指出提供30天免费试用期。可进一步划分为MySQL标准版、MySQL企业版、MySQL集群版。官方提供付费服务。
其中Community Server 可以直接从mysql 的官网下载。但Enterprice Edition只能从Oracle edelivery上下载,而Edelivery有时会屏蔽中国IP。
MySQL各版本区别参见:
http://www.admin10000.com/Document/62.html
下载mysql时注意区分版本细节及所应用的系统平台:linux(32/64) 、win(32/64)
举例:MySQL Community Server 5.6.20 win版本
GA 是指软件的通用版本,一般指正式发布的版本 (Generally Available (GA) Release)
mysql-essential-5.1.60-win32.msi 是精简版,如果只需要mysql服务,就选择此版本。
mysql-5.1.60-win32.msi 是完整版,包含安装程序和配置向导,有MySQL文档。
mysql-noinstall-5.1.60-win32.zip 是非安装的zip压缩包,没有自动安装程序和配置向导,无安装向导
mysql-5.1.60.zip 是用于windows的Mysql源码压缩包
linux版本
在http://www.mysql.com/downloads/网站上下载不了
在 www.oracle.com/downloads 找mysql 注册用户, 选择操作系统平台和mysql版本 进行下载
官方文档上有关MySQL安装,介绍了3种类型及其对应安装方式来安装MySQL数据库:
Linux supports anumber of different solutions for installing MySQL. The recommended method isto use one of the distributions from Oracle. If you choose this method, thereare three options available:
(1) Installingfrom a generic binary package in .tar.gz format. See Section 2.2,“Installing MySQL from Generic Binaries on Unix/Linux” for moreinformation.
(2) Extractingand compiling MySQL from a source distribution. For detailed instructions,see Section 2.9, “InstallingMySQL from Source”.
(3) Installingusing a pre-compiled RPM package. For more information on using the RPMsolution, see Section 2.5.1,“Installing MySQL from RPM Packages on Linux”
我们选用较简单的RPM 包来安装
1.查询
查询服务器上已经安装的mysql
在终端提示符输入:rpm -aq | grep MySQL 命令
2.卸载
rpm -e 软件包名--nodeps --allmatches (不理会依赖关系,删除所有上一步查出来的相同的mysql)
3.安装
解压.zip安装包
unzip V46610-01-MySQL Database 5.6.20 RPM for Oracle Linux RHEL 6 x86 (64bit).zip
安装如下软件包:
MySQL-client-advanced-5.6.20-1.el6.x86_64.rpm
MySQL-devel-advanced-5.6.20-1.el6.x86_64.rpm
MySQL-server-advanced-5.6.20-1.el6.x86_64.rpm
--#表示需要在root下执行
#rpm -ivh MySQL-server-advanced-5.6.****-1.el6.x86_64.rpm
mysql安装的时候自动初始化一个root用户(mysql数据库用户,不是操作系统用户)
用户名密码在在root目录下,通过cat目录下的 .mysql_secret文件可查看当前的密码
[[email protected] oracle]# cat /root/.mysql_secret
#rpm -ivh MySQL-client-advanced-5.6.****-1.el6.x86_64.rpm
说明:不安装mysql-client是不能使用mysql工具登陆到mysql数据库
其他软件包选择性安装,这个是开发需要安装的,如果没有安装则没有库文件以及头文件,无法进行编程:
#rpm -ivh MySQL-devel-advanced-5.6.20-1.el6.x86_64.rpm
4.修改密码
一般自己安装之后要修改密码.
--登陆
mysql -uroot -p123456
改密码,在登录后的情况下
set password=password(‘123‘);
具体安装可以参考《Redhat下安装mysql 5.6.20.docx》
5.ubuntu下安装mysql.txt
1). sudo apt-get install mysql-server
2). sudo apt-get isntall mysql-client
3). sudo apt-get install libmysqlclient-dev
提示:安装过程中会提示设置密码什么的,注意设置了不要忘了,安装完成之后可以使用如下命令来检查是否安装成功:
6.远程连接模式说明
vmvare 网卡
桥接模式 : 物理机 和虚拟机 同一网段
NAT模式 : VMNET8 与 虚拟机 同一网段
主机模式: VMNET1 与 虚拟机 同一网段。仅限于自己能连,别人连不了
/*******************************************************************************************/
二、mysql的简介
mysql 是瑞典 mysqlAB公司 ,后来被sun收购,之后被oracle 收购.
社区版和企业版
开源的 ,免费的
mysql体系结构,
mysql首先是用户,然后接下来是数据库,最后才是表。
所以学习从库开始,
先库的增删改查,然后表的增删改查,最后是数据的增删改查,
由于mysql比较小,不像oracle那么大 有个dba来操作数据库,所以mysql需要都得会
具体见图《mysql体系结构与oracle体系结构的不同.png》:
/*******************************************************************************************/
三、mysql库的操作
1.mysql启动不了的时候使用:
1).先杀掉进程 mysqld,没有这个进程,则无法登录
2).重启mysql服务
[[email protected] oracle]# service mysql restart
2.库的增删改查
1).查看当前有的数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
这三个是mysql自带的,这三个不能删,删了会有问题
2).创建一个yekai的数据库
create database yekai;
3).查看yekai数据库是怎么创建的,查看数据库(创建的相关)信息
mysql> show create database yekai;
+----------+------------------------------------------------------------------+
| Database | Create Database |
+----------+------------------------------------------------------------------+
| yekai | CREATE DATABASE `yekai` /*!40100 DEFAULT CHARACTERSET latin1 */ |
+----------+------------------------------------------------------------------+
1 row in set (0.00 sec)
4).创建了utf8字符集的数据库,这样可以支持中文
create database mydb1 character set utf8;
5).将数据库的字符集修改为utf8
alter database yekai character set utf8;
6).删除yekai这个数据库
drop database yekai;
7).创建一个utf8的数据库并对输入数据进行校对 ,创建数据库 对数据库存入的数据按照utf8格式进行一个检查
create database mydb3 character set utf8 collate utf8_general_ci;
后续操作这个数据库的时候就会检查是否是utf8格式的。
/*******************************************************************************************/
四、mysql表的管理
表的管理:增删改查
1.表的增加
我们要创建表先要选择数据库
--先选取库
use mydb1 //这个指令不需要敲分号,其他的都要敲
--再创建表,由于mysql的数据类型与oracle的不一样,所以列名后面的数据类型要用mysql自己的,相对于oracle要做修改
create table t1(id int,name varchar(30));
//具体数据类型的说明,以及数据类型表示的说明,
timeStamp: 时间戳,自动赋值为当前日期时间
注意,mysql中的数据类型:
具体见图1:
2.表的修改
--修改表的属性,可以加column关键字,oracle不能加
--增加email列
alter table t1 add email varchar(30);
--增加sal列
alter table t1 add column sal float;
--修改列属性,可以加column关键字,oracle不能加
alter table t1 modify email varchar(40);
--change可以修改列名和列的属性,如下是把列名email改为 address,并修改数据类型为varchar(20)
alter table t1 change column email address varchar(20);
desc t1;//查看表结构。
--删除列
alter table t1 drop column address;
--重命名表需要有table关键字,oracle则不需要
rename table t1 to t2;
create table t1 as select * from t2;
3.表的查看
--查看当前库下有哪些表,代替了oracle中的select * from tab;
show tables;
--查看表的创建方式:
show create table t1;
具体见图2:
其中,ENGINE(引擎)=InnoDB,
这个引擎是 InnoDB
InnoDB :引擎的一种方式,这种方式支持事务,默认情况下事务不开启(自动提交,这点和oracle不一样).
默认的这种引擎速度比较快。
另外其中列名还有表名加了单引号,表示这个名称是区分大小写的,
mysql> use Mydb1
ERROR 1049 (42000): Unknown database ‘Mydb1‘
库名区分大小写
字段不区分大小写
4.表的删除
--删除表 不支持purge关键字 ,也就是mysql不支持回收站(因为mysql是小数据库)
drop table t1;
清空表:truncate先删除表,再创建个空表
/*******************************************************************************************/
五、mysql数据处理
mysql对数据的增删改查和oracle大致是一样的。
表数据的处理,也就是增删改查
create table employee(id int,
name varchar(20),
sex int,
birthday date,
salary double,
entry_date date,
resume text
);//这里面是空格,不要有tab健,tab键会导致数据错误,缺少行
insert into employee values(1,‘叶开‘,1,‘1983-04-27‘,15000,‘2012-06-24‘,‘一个大牛‘);
insert into employee(id,name,sex,birthday,salary,entry_date,resume) values(2,‘傅红雪‘,1,‘1984-02-22‘,10000,‘2012-07-24‘,‘一个中牛‘);
insert into employee(id,name,sex,birthday,salary,entry_date,resume) values(3,‘陆小佳‘,0,‘1985-08-28‘,7000,‘2012-08-24‘,‘一个小虾‘);
update emploee set resume=‘123‘ where id =3;
delete from emploee where id =3;
事务的处理上不一样,mysql是自动提交的。
/*******************************************************************************************/
六、mysql的函数
1.日期时间函数
MySQL里面时间分为三类:时间、日期、时间戳(含有时分秒的sysdate),具体见图3:
sysdate伪列 mysql不存在,使用now()
即:select now() from dual;
--昨天,今天,明天
select now()-1,now(),now()+1 from dual;//这样类似oracle的做法不对,它把日期变为数字然后加减1了
正确的做法,使用date_add或者date_sub:
mysql> select date_add(now(),interval -1 day),now(),date_add(now(),interval 1 day) from dual;
//interval是关键字,-1 数据是多少,day是数据类型
--明年的今天
mysql> select date_add(now(),interval 1 year) from dual;
--addtime函数增加秒数,注意这个秒数要小于60
mysql> select addtime(now(),10),now() from dual;
--注意这个秒数要小于60,如果要加一分钟,则:
mysql> select addtime(now(),‘0:1:0‘),now() from dual;
2.字符串相关函数
字符串相关函数,具体可见图4:
--concat函数支持多个参数,oracle不支持这么多个,|| 语法mysql保留即不报错,但是mysql中功能不存在
mysql> select concat(‘hello‘,‘world‘,‘111‘),‘hello‘||‘world‘ from dual;
--查看字符集(编码)
mysql> select charset(‘hllo‘),charset(‘叶开‘) from dual;
+-----------------+-------------------+
| charset(‘hllo‘) | charset(‘叶开‘) |
+-----------------+-------------------+
| utf8 | utf8 |
+-----------------+-------------------+
-- 查看字符串长度,一个汉字三个字节(这时因为格式是utf8),oracle是gbk格式,所以oracle是两个字节
mysql> select length(‘hello中国‘) from dual;
+-----------------------+
| length(‘hello中国‘) |
+-----------------------+
| 11 |
+-----------------------+
3.日期转换函数
在MySQL中没有to_date函数,进行日期转换需使用date_format()来代替
1).日期转字符串:
转换函数 yyyy-mm-dd 语法支持,功能没有
mysql> select date_format(‘2013-5-11‘, ‘yyyy-mm-dd‘) from dual;
mysql> select date_format(now(), ‘%Y-%m-%d‘) from dual;
y(没有20只有17)和Y(2017)不一样。
mysql> select date_format(now(), ‘%Y-%c-%d %h:%i:%s‘) from dual;
c(02变成2,会去掉0)和m(02)、M(用英语书写的月份)不一样
2).字符串转日期:
mysql> select str_to_date(‘2013-6-04 05:14:15‘ , ‘%Y-%c-%d %h:%i:%s‘) from dual;
//最好字符串要和格式串一致,即对应起来,当然不一致也能转换
mysql> select str_to_date(‘2013-06-04 05:14:15‘ , ‘%Y-%m-%d %h:%i:%s‘) from dual;
3).格式很像Linux下的date命令,date命令后可以加格式串来得到想要的日期格式:
[[email protected] ~]$ date +‘%y-%m-%d‘
17-02-16
[[email protected] ~]$ date +‘%Y-%m-%d‘
2017-02-16
4.数学相关函数
具体可见图5:
5.group by语法
-- 求各个班英语的平均分
select avg(english),class_id,id from student group by class_id;
//这样在oracle中是不允许的(select后面出现的非主函数的列在group by后面必须出现),但是在mysql中是可以,
这个id是每个分组第一条记录对应的id,但是这样没有意义.
mysql group by语法检查不严格,我们仍然用oracle的要求.
/*******************************************************************************************/
七、多表数据
create database if not exists mydb1 character set utf8;
//if not exists 如果不存在才去执行,这样反复执行这个命令就不会报错
sql文件里面的这些sql语句除了复制粘贴来直接外,可以直接使用
source scott_data.sql
这样来执行。
Oracle中连接方法:
等值连接
不等值连接
外连接
自连接
MySQL 使用SQL99标准的连接查询(JOIN..ON..)
1.内连接
对应于oracle的等值连接
(在mysql中使用edit来书写,其实是用vi打开了,而在oracle中ed就可以了。
edit中书写完毕后,用wq保存,然后再输入;号执行。)
1).求员工号,姓名,月薪,部门名称
--oracle写法
select e.empno,e.ename,e.sal,d.dname
from emp e,dept d
where e.deptno=d.deptno;
--sql99(mysql)写法
select e.empno,e.ename,e.sal,d.dname
from emp e inner join dept d
on e.deptno=d.deptno;
口诀: 1. , --> inner join 2. where ---> on
两种写法在mysql中都能使用
2.外连接
1).求员工总人数,显示部门编号,名称,人数
--oracle写法
select d.deptno,d.dname,count(e.empno)
from emp e , dept d
where e.deptno=d.deptno;
查询结果有问题,这是由于条件不是完全相等,需要用到左外 右外才行,(也有可能是没有group by的原因)
>>>>>>oracle的外连接在mysql中不能使用,如下是oracle的外连接在mysql中不能使用
select d.deptno,d.dname,count(e.empno)
from emp e , dept d
where e.deptno(+)=d.deptno;
--sql99的写法
select d.deptno,d.dname,count(e.empno)
from emp e right outer join dept d
on e.deptno=d.deptno
group by d.deptno,d.dname;
右外连接口诀: 1 , --- > right outer join(即保留join右边的部分,也就是dept d) 2 where --> on
select d.deptno,d.dname,count(e.empno)
from dept d left outer join emp e
on e.deptno=d.deptno
group by d.deptno,d.dname;
左外连接口诀: 1 , --- > left outer join 2 where --> on
左外或者右外的取决条件是 表在(逗号(outer join))的位置,与等号无关
3.自连接(特殊的外连接)
数据都在同一张表,不在同一行
//把emp表分别当成老板表和员工表
员工表的老板是老板表的员工(连接(筛选记录的)条件,(筛选(找出)两张表组合起来的集合中满足(连接)条件的记录)).
--oracle写法(不带外连接)
select concat(e.ename,‘‘‘s boss is ‘,b.ename)
from emp e,emp b
where e.mgr = b.empno;
--sql99的写法
select concat(e.ename,‘‘‘s boss is ‘,b.ename)
from emp e left outer join emp b
on e.mgr = b.empno;
返回的结果中有一个记录是null,这时因为有一个 b.ename是null,这样字符串连接后也是null
滤空函数:
--nvl(滤空)函数mysql不支持
select concat(e.ename,‘‘‘s boss is ‘,nvl(b.ename,‘himself‘))
from emp e left outer join emp b
on e.mgr = b.empno;
--nvl(滤空)函数用ifnull替换
select concat(e.ename,‘‘‘s boss is ‘,ifnull(b.ename,‘himself‘))
from emp e left outer join emp b
on e.mgr = b.empno;
4.满外联接
任一边有值就会显示。
select e.*, d.*
from emp e full outer join dept d
on e.deptno=d.deptno
也可以省略outer关键字
5.交叉连接:
叉集,即笛卡尔集
select e.*, d.*
from emp e cross join dept d
无连接条件
6.inner 和 outer 可以省.
7.
后续实际项目中用的是redhat系统上装数据库
select ‘create synonym‘||TNAME||‘for scott.‘||TNAME from tab where tabtype=‘TABLE‘;//这样可以拿到建所有同义词的语句
序列的作用给表的主键使用,为了避免主键冲突.
nextval 默认加载到内存中 20个.如果没用完就掉电了,由于在内存中记不下来,所以重新上电后是从下一段即40开始
/*******************************************************************************************/
八、mysql的约束
1.约束的定义
*定义主键约束 primary key: 不允许为空,不允许重复
*定义主键自动增长 auto_increment
*定义唯一约束 unique
*定义非空约束 not null
*定义外键约束 constraint ordersid_FK foreign key(ordersid) references orders(id)
*删除主键:alter table tablename drop primary key ;
可以通过SELECT * FROM information_schema.`TABLE_CONSTRAINTS`;查看表的约束
2.与Oracle的区别
mysql的约束与oracle的区别在于没有检查了,即语法支持但是功能没有了
mysql主键不需要序列,只需要自动增长关键字即可
mysql定义外键语法与oracle略有不同。
定义外键约束 constraint ordersid_FK foreign key(ordersid) references orders(id)
//ordersid_FK 别名 ,ordersid 本表里用外键的字段,orders(id) 引用rders表的id字段
3.示例:
mysql> drop table myclass;
mysql> create table myclass(
class_id int primary key auto_increment,
class_name varchar(20) not null,
create_date timestamp);
mysql> insert into myclass(class_id,class_name) values(5,‘5班‘); //即使是auto_increment,只要满足主键的约束也能这样手动增加
mysql> insert into myclass(class_name) values(‘什么班‘); //自动增长的机制是取前面的最大值,然后加1,一开始啥都没有则第一个是1
mysql> create table mystudent(
student_id int primary key auto_increment,
student_name varchar(20) not null,
hiredate timestamp,
class_id int,
constraint stu_classid_FK foreign key(class_id) references myclass(class_id));
//stu_classid_FK 外键约束名,class_id 是外键,依赖于myclass表的class_id(上一个表的主键是这个表的外键(的依赖))
--非空约束
mysql> insert into mystudent(student_name,class_id) values(null,1);
ERROR 1048 (23000): Column ‘student_name‘ cannot be null
--违反外键约束//当前class_id依赖于其他表的主键,即当前的class_id的值 要是其他表的主键中已经存在的
mysql> insert into mystudent(student_name,class_id) values(‘fuhongxue2‘,8);//上一个表的class_id中没有值为8的
--有外键时删除表
-违反外键约束,需要先删除学生,再删除班级
mysql> delete from myclass where class_id=5;
mysql> delete from mystudent where class_id=5;
Query OK, 1 row affected (0.00 sec)
mysql> delete from myclass where class_id=5;
Query OK, 1 row affected (0.01 sec)
/*******************************************************************************************/
九、mysql中文乱码问题
中文乱码问题:要重视
三层因素:
因素1: MySQL自身的设计
【实验步骤1】:
mysql> show variables like ‘character%‘; 查看所有应用的字符集
结果有好几种字符集,具体哪种字符集是属于哪一端的见图《字符集归类.png》:
【实验步骤2】: 指定字符集登录数据库
$ mysql -uroot -p123456 --default_character_set=gbk 指定字符集登录数据库
mysql> show variables like ‘character%‘;
影响了与客户端相关联的 3处 (最外层)
在这种状态下执行use mydb2;
mysql> select * from employee;
查看输出,会出现乱码。
原来的三条数据,是以utf8的形式存储到数据库中,当使用gbk连接以后,数据库仍按照utf8的形式将数据返回,出错。
【实验步骤3】:
在该环境下插入带有中文的一行数据。
mysql> insert into employee(id,name,sex,birthday,salary,entry_date,resume) values(10,‘张三疯‘,1,‘1983-09-21‘,15000,‘2012-06-24‘,‘一个老牛‘);
ERROR 1366 (HY000): Incorrect string value: ‘\x80\xE4\xB8\xAA\xE8\x80...‘ for column ‘resume‘ at row 1
因素2:操作系统的语言集
linux操作系统 是一个 多用户的操作
[[email protected] ~]# cat /etc/sysconfig/i18n //查看当前语言设置
LANG="zh_CN.UTF-8" //数据存储按照UTF8格式,数据展示按照简体中文.
操作系统的菜单按照zh_CN显示, 文件存储按照utf8
linux操作系统语言环境 和 用户的配置的语言环境LANG 相互影响(两者(要)一样)
[[email protected] ~]$ echo $LANG
zh_CN.UTF-8
改了任意一个,就会乱码:
【实验步骤4】:
修改用户下的.bash_profile 中的LANG,屏蔽操作系统的LANG设置。再查数据库
mysql> select * from employee;
结论: 用户的LANG设置,影响了应用程序的语言环境,导致myql的语言环境发生了改变:
mysql> show variables like ‘character%‘;
在此环境下,检索中文会出现乱码。
【实验步骤5】:在上述环境之下,向数据库中插入中文。
insert into employee(id,name,sex,birthday,salary,entry_date,resume) values(5,‘张三疯‘,1,‘1987-05-21‘,15000,‘2014-06-24‘,‘一个老牛‘);
数据能插入到数据库中,没 有 报 任 何 错 误!但显示不正确。
因素3:文件存储格式
命令输入字符的格式,
比如
远程连接工具里配置输入命令的字符编码 不一致时也会有问题
所以操作前要查询一下数据,并且操作后再查一下,确定一个是否有乱码。
/*******************************************************************************************/
十、mysql分页问题处理
前面说的那两个mysql本来就有,且不能删除的表,里面都是一些mysql库相关的信息,比如表的约束啥的
可以切换到那两个数据库,然后查询看看里面的内容。
--显示数据
select * from emp \G; 这种方式显出出来的结果是一行一行的展示数据,就和没有\G的效果完全不同了
--top-N问题解决(mysql解决top-N问题的方法与oracle不同,主要就是使用了limit)
-- limit 取前3名,
select * from emp order by sal desc limit 3;
-- limit取5-8名,limit 后的两个数字,代表跳过的记录数,和然后取的记录数.
select * from emp order by sal desc limit 4,4;
/*******************************************************************************************/
十一、mysql api编程
mysql API详细见《MySQL 中文完全参考手册5.1.chm》,主要研究的是c库,也就是mysql提高给c的api
(下面摘出的是文档中需要特别注意的地方,并作了相应的注释)
1.依赖
C API代码是与MySQL一起提供的。它包含在mysqlclient库中,并允许C程序访问数据库。
//也就是c操作mysql时需要这个库文件以及相关的头文件
//依赖的头文件和库文件
/usr/include/mysql/mysql.h
/usr/lib64/mysql/libmysqlclient.a
[[email protected] ~]$ locate mysql.h //或者使用locate命令找到头文件和库文件 这时由于linux平台对文件信息做了记录,数据也不是实时更新的所以速度快,使用locate可查询到
//比如新增了一个文件,用locate不一定找的出来,但是用find可以找出来 //同样对于libmysqlclient.a文件,也可以用这个命令找到路径
2.使用流程
与MySQL交互时,应用程序应使用该一般性原则(流程):
1).通过调用mysql_library_init(),初始化MySQL库。库可以是mysqlclient C客户端库,或mysqld嵌入式服务器库,具体情况取决于应用程序是否与“-libmysqlclient”或“-libmysqld”标志链接。
2).通过调用mysql_init()初始化连接处理程序,并通过调用mysql_real_connect()连接到服务器。
3).发出SQL语句并处理其结果。(在下面的讨论中,详细介绍了使用它的方法)。
4).通过调用mysql_close(),关闭与MySQL服务器的连接。
5).通过调用mysql_library_end(),结束MySQL库的使用。
//其中第一步和第五步可以省略
//mysql编程的流程:
mysql_init 初始化
mysql_real_connect 连接
//做操作
mysql_close 关闭
3.示例
熟悉mysql api编程的方式:编写一个mysql客户端:
1).成功连接到mysql
2).做一下查询和新增数据的操作
3).编写客户端
1).成功连接到mysql(配置环境)
(1).初始化函数
MYSQL *mysql_init(MYSQL *mysql) 初始化函数
MYSQL 代表mysql连接句柄 ,传入参数可以为NULL
返回成功 是 连接句柄,失败 NULL
(2).连接mysql的函数
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)
mysql 连接句柄 ,要用初始后的返回值
host 主机 本地ip地址
user 用户 mysql的用户
passwd 密码 mysql的用户的密码
db 库名
port 端口 一般不用,填0
unix_socket 一般不用,填NULL
client_flag 标志位 通常为0,具体见手册,里面有说明
返回值: 返回 连接句柄,失败返回 NULL
(3).关闭连接
void mysql_close(MYSQL *mysql)
mysql 连接句柄 mysql_real_connect
代码见《hello.c》:
1 //gcc 01_hello.c -o 01_hello -I/usr/include/mysql/ -L/usr/lib64/mysql/ -lmysqlclient -lstdc++ -ldl -lpthread -lrt 2 #include "mysql.h" 3 #include <stdio.h> 4 #include <stdlib.h> 5 6 #define _HOST_ "127.0.0.1" //主机 7 #define _USER_ "root" //用户 mysql的用户 8 #define _PASSWD_ "123" //密码 mysql 9 #define _DB_ "scott" //库 10 11 12 13 int main() 14 { 15 MYSQL *mysql = NULL; 16 //1. mysql_init 17 mysql = mysql_init(NULL); 18 if(mysql == NULL){ 19 printf("mysql init err\n"); 20 exit(1); 21 } 22 //2. mysql_real_connect 23 //MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) 24 mysql = mysql_real_connect(mysql,_HOST_,_USER_,_PASSWD_,_DB_,0,NULL,0); 25 if(mysql == NULL ){ 26 printf("mysql connect err!\n"); 27 exit(1); 28 } 29 printf("welcome to mysql!\n"); 30 //3. mysql_close 31 mysql_close(mysql); 32 return 0; 33 }
hello.c
注意编译:
//gcc 01_hello.c -o 01_hello -I/usr/include/mysql/ -L/usr/lib64/mysql/ -lmysqlclient
这样首先会报gxx的错误,这是缺少g++的库,解决方法:
//gcc 01_hello.c -o 01_hello -I/usr/include/mysql/ -L/usr/lib64/mysql/ -lmysqlclient -lstdc++
这样首先会报dlxx的错误,man 相关缺少定义的函数,然后加上需要的,解决方法:
gcc 01_hello.c -o 01_hello -I/usr/include/mysql/ -L/usr/lib64/mysql/ -lmysqlclient -lstdc++ -ldl -lpthread -lrt
(4).makefile编写
make -n //假装走一遍,并不是真的执行,相当于测试指令。
具体内容见《makefile》:
1 #gcc 01_hello.c -o 01_hello -I/usr/include/mysql/ -L/usr/lib64/mysql/ -lmysqlclient -lstdc++ -ldl -lpthread -lrt 2 3 GCC=gcc 4 IncPath=/usr/include/mysql/ 5 LibPath=/usr/lib64/mysql/ 6 PubLib=-lmysqlclient -lstdc++ -ldl -lpthread -lrt 7 8 SrcFiles=$(wildcard *.c) 9 TargetFiles=$(patsubst %.c,%,$(SrcFiles)) 10 11 all:$(TargetFiles) 12 13 14 %:%.c 15 $(GCC) $? -o [email protected] -I$(IncPath) -L$(LibPath) $(PubLib) 16 17 18 clean: 19 rm -f $(TargetFiles)
makefile
2).mysql api新增数据
实现insert功能:
-- mysql sql执行函数 执行完了就完了,不会返回结果
int mysql_query(MYSQL *mysql, const char *query)
mysql 连接句柄
query 执行的sql
成功返回0 ,失败返回非0
代码见《insert.c》:
1 //insert 2 #include "mysql.h" 3 #include <stdio.h> 4 #include <stdlib.h> 5 6 #define _HOST_ "127.0.0.1" //主机 7 #define _USER_ "root" //用户 mysql的用户 8 #define _PASSWD_ "123" //密码 mysql 9 #define _DB_ "scott" //库 10 11 12 13 int main() 14 { 15 MYSQL *mysql = NULL; 16 //1. mysql_init 17 mysql = mysql_init(NULL); 18 if(mysql == NULL){ 19 printf("mysql init err\n"); 20 exit(1); 21 } 22 //2. mysql_real_connect 23 //MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) 24 mysql = mysql_real_connect(mysql,_HOST_,_USER_,_PASSWD_,_DB_,0,NULL,0); 25 if(mysql == NULL ){ 26 printf("mysql connect err!\n"); 27 exit(1); 28 } 29 printf("welcome to mysql!\n"); 30 31 // 在此处添加业务代码 32 char *rSql = "insert into dept(deptno,dname,loc) values(50,‘caiwu‘,‘beijing‘)"; 33 //执行 34 if(mysql_query(mysql,rSql) ){ 35 printf("mysql query err:%s\n",rSql); 36 mysql_close(mysql); 37 exit(1); 38 } 39 printf("insert ok!\n"); 40 //3. mysql_close 41 mysql_close(mysql); 42 return 0; 43 }
insert.c
3).实现mysql查询
除了用执行函数外,还需要知道返回的结果,也就是查询结果集,
这时需要使用的函数:
MYSQL_RES *mysql_store_result(MYSQL *mysql)
描述
对于成功检索了数据的每个查询(SELECT、SHOW、DESCRIBE、EXPLAIN、CHECK TABLE等),必须调用mysql_store_result()或mysql_use_result() 。
对于其他查询,不需要调用mysql_store_result()或mysql_use_result(),但是如果在任何情况下均调用了mysql_store_result(),它也不会导致任何伤害或性能降低。通过检查mysql_store_result()是否返回0,可检测查询是否没有结果集(以后会更多)。
MYSQL_RES关于该结构体的描述可以去mysql.h里面查找
mysql 连接句柄
返回 结果集 MYSQL_RES ,失败 返回 NULL
--取结果集的下一行,循环调用这个函数则可以得到结果集的所有行
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result) //可以调用mysql_fetch_row()来获取结果集中的行
result 取回的结果集
MYSQL_ROW 返回下一行的结构 //MYSQL_ROW 是char**,是一个二维数组,表示一行的内容
char ** 可以展示.
即二维数组中的每一个元素是每一列的内容,比如row[0]是该行第一列的内容,row[1]是该行第二列的内容
--释放结果集//一旦完成了对结果集的操作,必须调用mysql_free_result()。
void mysql_free_result(MYSQL_RES *result)
获取列的个数的函数:
unsigned int mysql_num_fields(MYSQL_RES *result) //返回结果集中的行数。
获取列名使用的函数:
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result) //返回所有MYSQL_FIELD结构的数组,数组的元素就是每一列的列名
代码见《select.c》:
1 //select 查询功能 2 #include "mysql.h" 3 #include <stdio.h> 4 #include <stdlib.h> 5 6 #define _HOST_ "127.0.0.1" //主机 7 #define _USER_ "root" //用户 mysql的用户 8 #define _PASSWD_ "123" //密码 mysql 9 #define _DB_ "scott" //库 10 11 12 13 int main() 14 { 15 MYSQL *mysql = NULL; 16 //1. mysql_init 17 mysql = mysql_init(NULL); 18 if(mysql == NULL){ 19 printf("mysql init err\n"); 20 exit(1); 21 } 22 //2. mysql_real_connect 23 //MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) 24 mysql = mysql_real_connect(mysql,_HOST_,_USER_,_PASSWD_,_DB_,0,NULL,0); 25 if(mysql == NULL ){ 26 printf("mysql connect err!\n"); 27 exit(1); 28 } 29 printf("welcome to mysql!\n"); 30 31 //在此处添加业务代码 32 33 //执行查询 34 if(mysql_query(mysql,"select * from emp") ){ 35 printf("mysql query err\n"); 36 mysql_close(mysql); 37 exit(1); 38 } 39 //处理查询结果集 40 MYSQL_RES *result = mysql_store_result(mysql); 41 MYSQL_ROW row; 42 int i =0; 43 if(result != NULL)//代表有结果集 44 { 45 // MYSQL_ROW mysql_fetch_row(MYSQL_RES *result) 46 while( (row=mysql_fetch_row(result) )) { 47 for(i = 0; i < 8 ; i ++)//针对 列的循环,一共是8列 48 { 49 printf("%s\t",row[i]); 50 } 51 printf("\n");//上面处理是一行,此处换行 52 } 53 mysql_free_result(result); 54 } 55 56 57 58 //3. mysql_close 59 mysql_close(mysql); 60 return 0; 61 }
select.c
4).客户端工具编写
类似输入mysql -uroot -p123进行登录,并输入sql语句后会返回结果的程序工具
编写客户端:
连接到mysql数据库 mysql_init mysql_real_connect
打印管理台信息 MYSQL>
等待输入sql
执行输入的sql,主要是两类,有结果集(查询),没有结果集的
有结果集的打印结果集
关闭 mysql_close
注意,获取控制台的输入数据一般也可以使用fgets,该函数是阻塞的。
my_ulonglong mysql_affected_rows(MYSQL *mysql) //返回的是,多少个数在集合中
描述
返回上次UPDATE更改的行数,上次DELETE删除的行数,或上次INSERT语句插入的行数。
//连接之后设置一下字符集,来保证不同地方登录到服务器写入的数据的编码格式都是一样的。
int mysql_set_character_set(MYSQL *mysql, char *csname)
描述
该函数用于为当前连接设置默认的字符集。
mysql_set_character_set(mysql,"utf8"); //设置字符集
代码见《client.c》:
1 //select2 查询功能 完善 2 #include "mysql.h" 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #define _HOST_ "127.0.0.1" //主机 8 #define _USER_ "root" //用户 mysql的用户 9 #define _PASSWD_ "123" //密码 mysql 10 #define _DB_ "scott" //库 11 12 //显示结果集的函数 13 void showresult(MYSQL_RES *result,MYSQL *mysql) 14 { 15 unsigned int num_fields; 16 unsigned int i; 17 MYSQL_FIELD *fields; 18 19 num_fields = mysql_num_fields(result);//获得字段数 20 fields = mysql_fetch_fields(result);//获取字段数组 21 for(i = 0; i < num_fields; i++) 22 { 23 printf("%s\t", fields[i].name);//打印字段,也就是表头 24 } 25 printf("\n"); 26 27 printf("----------------------------------------------------------------\n"); 28 29 MYSQL_ROW row; 30 if(result != NULL)//代表有结果集 31 { 32 // MYSQL_ROW mysql_fetch_row(MYSQL_RES *result) 33 while( (row=mysql_fetch_row(result) )) { 34 for(i = 0; i < num_fields ; i ++)//num_fields 列数 35 { 36 printf("%s\t",row[i]); 37 } 38 printf("\n");//上面处理是一行,此处换行 39 } 40 41 } 42 printf("----------------------------------------------------------------\n"); 43 printf("%ld rows in set\n",(long) mysql_affected_rows(mysql)); 44 45 } 46 47 int main() 48 { 49 MYSQL *mysql = NULL; 50 //1. mysql_init 51 mysql = mysql_init(NULL); 52 if(mysql == NULL){ 53 printf("mysql init err\n"); 54 exit(1); 55 } 56 //2. mysql_real_connect 57 //MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) 58 mysql = mysql_real_connect(mysql,_HOST_,_USER_,_PASSWD_,_DB_,0,NULL,0); 59 if(mysql == NULL ){ 60 printf("mysql connect err!\n"); 61 exit(1); 62 } 63 printf("welcome to mysql!\n"); 64 65 mysql_set_character_set(mysql,"utf8"); //设置字符集 66 67 68 //在此处添加业务代码 69 char rSql[512]; 70 71 72 while(1){ 73 printf("yekaiSQL>"); 74 memset(rSql,0x00,sizeof(rSql)); 75 fgets(rSql, sizeof(rSql), stdin); 76 printf("rSql:%s\n",rSql); 77 if(strncmp(rSql,"quit",4) == 0 || strncmp(rSql,"QUIT",4) == 0) 78 { 79 printf("bye bye\n"); 80 break; 81 } 82 //执行sql 83 if(mysql_query(mysql,rSql) ){ 84 printf("mysql query err\n"); 85 //mysql_close(mysql); 86 //exit(1); 87 } 88 //处理查询结果集 89 MYSQL_RES *result = mysql_store_result(mysql); 90 if(result != NULL){ 91 showresult(result,mysql);//打印结果集 92 mysql_free_result(result); 93 } 94 } 95 96 //3. mysql_close 97 mysql_close(mysql); 98 return 0; 99 }
client.c
/*******************************************************************************************/
十二、mysql预处理
1.预处理函数主要作用就是为了提高速度,适合sql语句多次反复执行
2.MySQL客户端/服务器协议提供了预处理语句。该功能采用了由mysql_stmt_init()初始化函数返回的MYSQL_STMT语句处理程序数据结构。
3.对于多次执行的语句,预处理执行是一种有效的方式。
首先对语句进行解析,$$$为执行作好准备$$$。
接下来,在以后使用初始化函数返回的语句句柄执行一次或多次。
对于多次执行的语句,预处理执行比直接执行快,主要原因在于,
仅对查询执行$$$一次解析操作$$$。在直接执行的情况下,每次执行语句时,均将进行查询。
此外,由于每次执行预处理语句时仅需$$$发送参数$$$的数据,从而减少了网络通信量。
4.预处理语句的另一个优点是,它采用了二进制协议,从而使得客户端和服务器之间的数据传输更有效率。
5.下述语句可用作预处理语句:
CREATE TABLE、DELETE、DO、INSERT、REPLACE、SELECT、SET、UPDATE、
以及大多数SHOW语句。在MySQL 5.1中,不支持其他语句。
6.缺点:用的比较难一点,也就是编程的时候难一点。
7.预处理流程见图《预处理的流程.png》:
8.mysql预处理详解(代码说明)
#define INSERT_SAMPLE "INSERT INTO test_table(col1,col2,col3) VALUES(?,?,?)"
//其中那三个问号代表占位,其实就是代表要传入的参数
MYSQL_BIND bind[3];//绑定变量 ,前面有三个问号,即有三个参数,所以这里是三个
bind[0].buffer= (char *)&int_data;//内存地址的映射
//注意,这个是指针的赋值导致的结果是双向的,即bind[0].buffer指向的内容改变了,则int_data
里面的内容也跟着变化了,同时,int_data里面的内容改变了,即bind[0].buffer所指向的内容也变化了
bind[0].is_null= 0;//由于是取地址赋值的,所以改为等于NULL更合适,
bind[0].length= 0;//由于是取地址赋值的,所以改为等于NULL更合适,
//如果绑定变量内的成员不等于NULL,那么由于内存映射的关系,修改了赋值的变量,则就是修改了绑定变量指向的
内存,同时也会传递到sql语句(类似传递了实参),因为绑定变量已经和sql语句建立了联系
示例:
int_data= 10; /* integer */
strncpy(str_data, "MySQL", STRING_SIZE); /* string */
str_length= strlen(str_data);
/* INSERT SMALLINT data as NULL */
is_null= 1;//指示插入的第三个字段是否为null,如果等于1表示要插入的是空,则无论指向的内存是什么情况,插入的数据都是null
/* Execute the INSERT statement - 1*/
if (mysql_stmt_execute(stmt)) //预处理的执行,第一次执行
补充:
//int mysql_stmt_fetch(MYSQL_STMT *stmt) 涉及到查询,具体看手册
param_count= mysql_stmt_param_count(stmt);//获得参数个数 ,这个函数不是预处理必须的流程,
代码见《prepare_insert.c》:
1 #include <stdio.h> 2 #include "mysql.h" 3 #include <stdlib.h> 4 #include <string.h> 5 6 #define _HOST_ "localhost" //主机 7 #define _USER_ "root" //mysql用户,非主机 8 #define _PASSWD_ "123" //密码 9 #define _DBNAME_ "scott" //库名 10 11 #define STRING_SIZE 50 12 13 #define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS test_table" 14 #define CREATE_SAMPLE_TABLE "CREATE TABLE test_table(col1 INT, 15 col2 VARCHAR(40), 16 col3 SMALLINT, 17 col4 TIMESTAMP)" 18 #define INSERT_SAMPLE "INSERT INTO test_table(col1,col2,col3) VALUES(?,?,?)" 19 void prepare_insert(MYSQL *mysql); 20 21 int main() 22 { 23 //1.初始化 24 MYSQL * mysql = NULL; 25 mysql = mysql_init(NULL) ; 26 if(mysql == NULL ) 27 { 28 printf("mysql init err\n"); 29 exit(1); 30 } 31 //2.连接 32 mysql = mysql_real_connect(mysql, _HOST_,_USER_, _PASSWD_,_DBNAME_, 0, NULL,0); 33 if(mysql == NULL) 34 { 35 printf("mysql_real_connect connect err\n"); 36 exit(1); 37 } 38 printf("welcome to mysql \n"); 39 prepare_insert(mysql); 40 //3.关闭 41 mysql_close(mysql); 42 return 0; 43 } 44 45 46 47 48 void prepare_insert(MYSQL *mysql) 49 { 50 MYSQL_STMT *stmt;//预处理的句柄 51 MYSQL_BIND bind[3];//绑定变量 52 my_ulonglong affected_rows; 53 int param_count; 54 short small_data; 55 int int_data; 56 char str_data[STRING_SIZE]; 57 unsigned long str_length; 58 my_bool is_null; 59 60 if (mysql_query(mysql, DROP_SAMPLE_TABLE))//删除表 61 { 62 fprintf(stderr, " DROP TABLE failed\n"); 63 fprintf(stderr, " %s\n", mysql_error(mysql)); 64 exit(0); 65 } 66 67 if (mysql_query(mysql, CREATE_SAMPLE_TABLE))//创建表 68 { 69 fprintf(stderr, " CREATE TABLE failed\n"); 70 fprintf(stderr, " %s\n", mysql_error(mysql)); 71 exit(0); 72 } 73 74 /* Prepare an INSERT query with 3 parameters */ 75 /* (the TIMESTAMP column is not named; the server */ 76 /* sets it to the current date and time) */ 77 stmt = mysql_stmt_init(mysql); //预处理的初始化 78 if (!stmt) 79 { 80 fprintf(stderr, " mysql_stmt_init(), out of memory\n"); 81 exit(0); 82 } 83 if (mysql_stmt_prepare(stmt, INSERT_SAMPLE, strlen(INSERT_SAMPLE))) //insert 语句 的预处理 84 { 85 fprintf(stderr, " mysql_stmt_prepare(), INSERT failed\n"); 86 fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); 87 exit(0); 88 } 89 fprintf(stdout, " prepare, INSERT successful\n"); 90 91 /* Get the parameter count from the statement */ 92 param_count= mysql_stmt_param_count(stmt);//获得参数个数 93 fprintf(stdout, " total parameters in INSERT: %d\n", param_count); 94 95 if (param_count != 3) /* validate parameter count */ 96 { 97 fprintf(stderr, " invalid parameter count returned by MySQL\n"); 98 exit(0); 99 } 100 101 /* Bind the data for all 3 parameters */ 102 103 memset(bind, 0, sizeof(bind)); 104 105 /* INTEGER PARAM */ 106 /* This is a number type, so there is no need to specify buffer_length */ 107 bind[0].buffer_type= MYSQL_TYPE_LONG; 108 bind[0].buffer= (char *)&int_data;//内存地址的映射 109 bind[0].is_null= 0; 110 bind[0].length= 0; 111 112 /* STRING PARAM */ 113 bind[1].buffer_type= MYSQL_TYPE_STRING; 114 bind[1].buffer= (char *)str_data;//char 100 115 bind[1].buffer_length= STRING_SIZE; 116 bind[1].is_null= 0; 117 bind[1].length= &str_length; 118 119 /* SMALLINT PARAM */ 120 bind[2].buffer_type= MYSQL_TYPE_SHORT; 121 bind[2].buffer= (char *)&small_data; 122 bind[2].is_null= &is_null;//是否为null的指示器 123 bind[2].length= 0; 124 125 /* Bind the buffers */ 126 if (mysql_stmt_bind_param(stmt, bind)) //绑定变量 参数绑定 127 { 128 fprintf(stderr, " mysql_stmt_bind_param() failed\n"); 129 fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); 130 exit(0); 131 } 132 133 //第一波赋值 134 int_data= 10; /* integer */ 135 strncpy(str_data, "MySQL", STRING_SIZE); /* string */ 136 str_length= strlen(str_data); 137 138 /* INSERT SMALLINT data as NULL */ 139 is_null= 1;//指示插入的第三个字段是否为null 140 141 /* Execute the INSERT statement - 1*/ 142 if (mysql_stmt_execute(stmt)) //预处理的执行,第一次执行 143 { 144 fprintf(stderr, " mysql_stmt_execute(), 1 failed\n"); 145 fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); 146 exit(0); 147 } 148 149 /* Get the total number of affected rows */ 150 affected_rows= mysql_stmt_affected_rows(stmt);//预处理的影响条数 151 fprintf(stdout, " total affected rows(insert 1): %lu\n", 152 (unsigned long) affected_rows); 153 154 if (affected_rows != 1) /* validate affected rows */ 155 { 156 fprintf(stderr, " invalid affected rows by MySQL\n"); 157 exit(0); 158 } 159 160 //第二波赋值 161 int_data= 1000; 162 strncpy(str_data, "The most popular Open Source database", STRING_SIZE); 163 str_length= strlen(str_data); 164 small_data= 1000; /* smallint */ 165 is_null= 0; /* reset */ 166 167 /* Execute the INSERT statement - 2*/ 168 if (mysql_stmt_execute(stmt))//第二次执行 169 { 170 fprintf(stderr, " mysql_stmt_execute, 2 failed\n"); 171 fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); 172 exit(0); 173 } 174 175 /* Get the total rows affected */ 176 affected_rows= mysql_stmt_affected_rows(stmt); 177 fprintf(stdout, " total affected rows(insert 2): %lu\n", 178 (unsigned long) affected_rows); 179 180 if (affected_rows != 1) /* validate affected rows */ 181 { 182 fprintf(stderr, " invalid affected rows by MySQL\n"); 183 exit(0); 184 } 185 186 /* Close the statement */ 187 if (mysql_stmt_close(stmt)) 188 { 189 fprintf(stderr, " failed while closing the statement\n"); 190 fprintf(stderr, " %s\n", mysql_stmt_error(stmt)); 191 exit(0); 192 } 193 194 }
prepare_insert.c
/*******************************************************************************************/
十三、mysql事务处理
mysql默认事务不开启,但是事务是支持的,是可以开启的。
#define SET_TRAN "SET AUTOCOMMIT=0" //代表自动提交是被关闭了的,也就是事务开启了。———手动commit
#define UNSET_TRAN "SET AUTOCOMMIT=1" //自动commit,执行完sql语句,立刻就提交,也就是恢复了默认
//无论设置事务为手动提交还是自动提交,都要先开启事务,即执行"start transaction"
具体见代码《tran.c》:
1 //mysql中的事务 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include "mysql.h" 6 7 #define SET_TRAN "SET AUTOCOMMIT=0" //手动commit ————手动commit 8 #define UNSET_TRAN "SET AUTOCOMMIT=1" //自动commit 9 10 #define _HOST_ "127.0.0.1" 11 #define _USER_ "root" 12 #define _PASSWD_ "123" 13 #define _DBNAME_ "scott" 14 15 //设置事务为手动提交 16 int mysql_OperationTran(MYSQL *mysql) 17 { 18 //--开启事务 19 int ret = mysql_query(mysql, "start transaction"); 20 if (ret != 0) { 21 printf("mysql_OperationTran query start err: %s\n", mysql_error(mysql)); 22 return ret; 23 } 24 25 //--设置事务为手动提交 26 ret = mysql_query(mysql, SET_TRAN); //set autocommmit = 0 27 if (ret != 0) { 28 printf("mysql_OperationTran query set err: %s\n", mysql_error(mysql)); 29 return ret; 30 } 31 32 return ret; 33 } 34 35 //设置事务为自动提交 36 int mysql_AutoTran(MYSQL *mysql) 37 { 38 //--开启事务 39 int ret = mysql_query(mysql, "start transaction"); 40 if (ret != 0) { 41 printf("mysql_AutoTran query start err: %s\n", mysql_error(mysql)); 42 return ret; 43 } 44 45 //--设置事务为自动提交 46 ret = mysql_query(mysql, UNSET_TRAN); //"set autocommit = 1" 47 if (ret != 0) { 48 printf("mysql_AutoTran query set err: %s\n", mysql_error(mysql)); 49 return ret; 50 } 51 52 return ret; 53 } 54 55 //执行commit,手动提交事务 56 int mysql_Commit(MYSQL *mysql) 57 { 58 int ret = mysql_query(mysql, "COMMIT"); //提交 59 if (ret != 0) { 60 printf("commit err: %s\n", mysql_error(mysql)); 61 return ret; 62 } 63 return ret; 64 } 65 66 //执行rollback,回滚事务 67 int mysql_Rollback(MYSQL *mysql) 68 { 69 int ret = mysql_query(mysql, "ROLLBACK"); 70 if (ret != 0) { 71 printf("rollback err: %s\n", mysql_error(mysql)); 72 return ret; 73 } 74 return ret; 75 76 } 77 78 #define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS test_table" 79 #define CREATE_SAMPLE_TABLE "CREATE TABLE test_table(col1 INT, 80 col2 VARCHAR(10), 81 col3 VARCHAR(10))" 82 83 #define sql01 "INSERT INTO test_table(col1,col2,col3) VALUES(10, ‘AAA‘, ‘A1‘)" 84 #define sql02 "INSERT INTO test_table(col1,col2,col3) VALUES(20, ‘BBB‘, ‘B2‘)" 85 #define sql03 "INSERT INTO test_table(col1,col2,col3) VALUES(30, ‘CCC‘, ‘C3‘)" 86 #define sql04 "INSERT INTO test_table(col1,col2,col3) VALUES(40, ‘DDD‘, ‘D4‘)" 87 88 int main(void) 89 { 90 int ret = 0; 91 92 MYSQL *mysql = mysql_init(NULL); 93 94 mysql = mysql_real_connect(mysql, _HOST_, _USER_, _PASSWD_, _DBNAME_, 0, NULL, 0); 95 if (mysql == NULL) { 96 ret = mysql_errno(mysql); 97 printf("func mysql_real_connect() err:%d\n", ret); 98 return ret; 99 } 100 printf(" --- connect ok......\n"); 101 //执行删除表 102 if (mysql_query(mysql, DROP_SAMPLE_TABLE)) { 103 fprintf(stderr, " DROP TABLE failed\n"); 104 fprintf(stderr, " %s\n", mysql_error(mysql)); 105 exit(0); 106 } 107 //执行创建表 108 if (mysql_query(mysql, CREATE_SAMPLE_TABLE)) { 109 fprintf(stderr, " CREATE TABLE failed\n"); 110 fprintf(stderr, " %s\n", mysql_error(mysql)); 111 exit(0); 112 } 113 114 ret = mysql_OperationTran(mysql); //开启事务,并修改事务属性为手动commit 115 if (ret != 0) { 116 printf("mysql_OperationTran() err:%d\n", ret); 117 return ret; 118 } 119 120 ret = mysql_query(mysql, sql01); //向表中插入第一行数据 ‘AAA’ 121 if (ret != 0) { 122 printf("mysql_query() err:%d\n", ret); 123 return ret; 124 } 125 126 ret = mysql_query(mysql, sql02); //向表中插入第二行数据 ‘BBB’ 127 if (ret != 0) { 128 printf("mysql_query() err:%d\n", ret); 129 return ret; 130 } 131 132 ret = mysql_Commit(mysql); //手动提交事务 133 if (ret != 0) { 134 printf("mysql_Commit() err:%d\n", ret); 135 return ret; 136 } 137 //////////AAA BBB 进去了。 138 139 #if 1 140 ret = mysql_AutoTran(mysql); // =再次= 修改事务属性为【自动】commit 141 if (ret != 0) { 142 printf("mysql_OperationTran() err:%d\n", ret); 143 return ret; 144 } 145 #else 146 ret = mysql_OperationTran(mysql); // =再次= 修改事务属性为【手动】commit 147 if (ret != 0) { 148 printf("mysql_OperationTran() err:%d\n", ret); 149 return ret; 150 } 151 #endif 152 153 ret = mysql_query(mysql, sql03); //向表中插入第三行数据 ‘CCC’ 154 if (ret != 0) { 155 printf("mysql_query() err:%d\n", ret); 156 return ret; 157 } 158 159 ret = mysql_query(mysql, sql04); //向表中插入第四行数据 ‘DDD’ 160 if (ret != 0) { 161 printf("mysql_query() err:%d\n", ret); 162 return ret; 163 } 164 165 ret = mysql_Rollback(mysql); //直接rollback操作 166 if (ret != 0) { 167 printf("mysql_Rollback() err:%d\n", ret); 168 return ret; 169 } 170 171 //rollback操作是否能回退掉CCC、DDD的值,取决于事务属性。 172 173 mysql_close(mysql); 174 175 return 0; 176 }
tran.c
原文地址:https://www.cnblogs.com/yuweifeng/p/9264423.html