数据库(数据库文件存在磁盘上)
数据库管理系统构成数据库
为什么要使用
数据库?不使用文件
文件不安全,每个人都可以查看
文件不利于海量数据的存储,查询和管理
数据库管理系统在数据的组织上采用了非常好的数据结构以及提高查询效率的索引机制
文件在程序中控制不方便,数据库是一个c/s架构,并且良好的解决了并发访问的数据安全(事务)
关系型数据库和非关系型数据库
关系型数据库
:采用了一种库,表,行,列的关系模型进行数据的组织
非关系型
:存储在内存
DDL
数据定义语言,用来维护存储结构与数据:create drop alter
DML
数据操纵语言,用来对数据进行操作:insert delete update
DCL
数据控制语言,只要负责权限管理和事务:grant revoke commit
service mysql status
查看数据库服务状态(是否启动)
端口号:3306
,底层用的是TCP协议
mysql -uroot -p
登录成数据库管理员
show databases;
查看都有哪些数据库
select database( );
查询当前使用的数据库
drop database 库名;
删除库
use 库名;
选择使用的库名
quit
退出数据库
create datebase +名字 charset =utf8;
创建数据库,防止乱码
show tables;
查看当前数据库中所有的表
desc 表名
查看表结构
修改表结构
alter table 表名 modify sn int primary key
sn为约束键
alter table 表名 add age int;
添加年龄这一列
alter table 表名 drop age int;
删除这列
drop table 表名
删除表
create table students (id int,name varchar,age int);
创建学生表
insert into student values(1001,"那么",18,'2001-03-04 10.28.00');
插入一条数据
insert into 表名 values(..),(..);
插入多条数据
insert into 表名(id,name)values(12,‘撒砸’);插入指定字段的数据
update 表名 set age=0 where name='张三';
修改内容
delete from 表名;
删除所有的数据
delete from 表名 where name='张三';
删除一行
select * from 表名
查询所有的数据
select name,age from 表名;
查询指定字段
select name,math+age from 表名;
查询字段可以是表达式
select name,math+age as total from 表名;
给字段取别名
select * from 表名 where name in('张三','李四');
查找名字是张三和李四
select * from 表名 where name like “%三%”
排序查询:
select * from 表名 order by age asc;
以升序排序(递增)默认
select * from 表名 order by age desc;
降序排序
select * from 表名 order by age desc,math asc;
多字段排序,第一个字段相同时使用第二个
select distinct age from 表名;
对某个字段去重查询
select distinct age,name from 表名;
以某个组合多字段进行去重,两个都相同时去重
分页查询:
select * from 表名 limit 3;
获取前三行
浮点类型:
float(4,2)4个数字,其中2个小数 精度小常用的是decimal(M,D)
字符串类型:char(L)
L是字符的个数不是位数
varchar(L)用多少开辟多少L是指最大的
日期类型:datatime八字节
条件查询:
select * from 表名 where name='李四';
查询名字为李四
select * from 表名 where math>60;
数学成绩>60
select * from 表名 where math!=/<>60;
不等于的两种方式
select * from 表名 where math=/<=>60;
等于60的两种方式
select * from 表名 where name is NULL;
针对NULL的判断,is not NULL
聚合函数
mysql数据库中内置的一些数据统计函数
cout(*):
统计结果条数
select count(*) from 表名 where en<60;
统计英语不及格的人数
sum(字段名称):对指定字段数据求和
select sum(en) from 表名;
对英语成绩进行求和
avg(字段名):对指定字段数据求平均值
select avg(en) from 表名;
对英语成绩求平均值
max(字段名):求最大值
select max(en) from 表名;
求英语的最高成绩
min(字段名):取最小值
select min(en) from 表名;
求英语成绩的最小值
分组查询
以指定字段为依据,对表中数据进行分组统计
分组查询结果中只能有分组依据字段以及聚合函数
分组查询的过滤条件不能使用where语句只能使用having
select role,max(salary),min(salary),avg(salary) from 表名 group by role;
以岗位进行分组,显示最大值,最小值,平均值
select role,avg(salary) from 表名 group by role having avg(salary)>10000;
键值约束primary key
对表中的指定字段的描述及约束
主键:primary key,约束是表中指定字段,值不能为NULL,且数据不能产生重复,主键一张表中只能有一个,但是存在组合主键
create table 表名(id int primary key,name varchar(32));单个主键
create table 表名(id int,name varchar(32),primary key pk(id,name));
唯一键unqiue key
约束表中的指定字段值不能重复但可以为NULL
create table 表名(id int primary key,name varchar(32) unique key,age int unique key,set int,unqiue key p(set));
非空约束not null
约定表中指定的字段值不能为空
create table 表名(id int primary key,name varchar(32) not null);
当表中没有主键时,但是指定了非空且为一字段,则这个约束会升级为主键约束
外键约束foreign key…references…
create table class(id int primary key,info varchar(32));
create table stu(id int primary key,name varchar(32),class_id int,foreign key (class_id) reference class(id));
默认值default
当没有主动插入某个字段的时候,则自动以默认值进行新增
create table 表名(id int primary key,name varchar(32),sex varchar(32) not null default “男”);
自增属性auto_increment
只能针对整数的主键字段进行设置,当不插入数据的时候默认从1开始自增
create table 表名(id int unique key auto_increment,name varchar(32));
插入数据的时候就可以在id的位置写null
三大范式
第一范式
:表中的所有字段必须保持原子特性(省 市)
第二范式
:表中所有的字段都必须与主键完全相关,而不能部分相关(主要针对组合主键的使用,就是有一个字段只与其中的一个主键有关),不完全相关会出现大量的数据冗余。
第三范式
:表中的字段必须与主键直接相关,不能间接相关(会数据冗余)
多表联查
将多张表的数据合并在一起进行查询
表中的数据取笛卡尔积进行合并
合并规则:student.class_id=class.id
内连接
:对两张表进行连接,但是连接的时候只取出符合合并规则的数据交集
外连接
:以两张表中某张表为基表,然后在另一张表中找到符合合并规则的数据,将其合并过来,没有找到的以null填充
外连接包括:左连接(以左表为基表) 和右连接(以右表为基表)
自连接
:
对同一个字段的值进行比较
select score1.id,score1.score,score2.score from score as score1inner join score as score2 on score1.id=score2.id inner join course on score1.course_id=course1.id inner join course as course2 onscore2.course_id=course1.id ;
内连接:inner join..on..
左连接:left join... on..
右连接:right join... on..
具体应用
:
select * from classes inner join stu on classes.id=stu.class_id;后面为合并规则
select * from classes left join stu on classes.id=stu.class_id;
select * from classes right join stu on classes.id=stu.class_id;
查询时先连接后where
子查询
:
也是多表联查的一种,但是他是将一条查询语句的结果当作一张表,再次查询
select * from student where class_id=(selelct class_id from student where name=‘躺平’);
合并查询
:union去重 union all不去
将两条查询语句的结果合并在一起
如:查询语文和英文的成绩
select * from score where course_id=4 union select * from score where course_id=6;
索引
索引
是一种对数据库表中的一列或多列的值进行排序的一种存储结构
索引优点:
所有的字段类型都可以被索引,也就是可以给任意字段设置索引
索引可以大大加快数据的查询速度
缺点:
索引占用内存
创建索引和维护索引要浪费时间
索引类型
:
普通索引
(index):允许在定义索引列中插入重复值和空值
唯一索引
(unique):值必须唯一,但不允许有空值
主键索引
(primary key):一种特殊的唯一索引,不允许值重复或者为空
全文索引
:只能在char,varchar,text类型的列上建立索引,只有myisam存储引擎支
持全文索引
创建索引:create 索引类型 索引名 on 表名(列名)
create index en_name on emp(ename)
作用:大大提高数据的查询效率
消耗:以插入,更新,删除的效率为代价
表中的那些字段适合作为索引
:
1.表中的这个字段被作为查询依据的条件的频率较高
2.经常修改的字段不适合作为索引
3.有大量重复的数据字段是不适合作索引(可以重复)
4.数据少的列不作为索引(性别)
alter table 表名 add index
(字段名)增加索引
show index from 表名;
查看索引
alter table 表名 drop index 字段名;
删除索引
create index 索引名 on 表名(字段名)
drop index 索引名 on 表名(字段名)
聚簇索引:一张表中只能有一个聚簇索引,其他索引都是辅助索引
非聚簇索引:并不区分主键索引和辅助索引,在物理磁盘上也不一定是有序的
当我们表中字段设置成主键,唯一键,外键约束,则对应字段会自动生成索引
myisam引擎和innodb区别
:
- InnoDB 支持事务,MyISAM 不支持事务。
- InnoDB 支持外键,而 MyISAM 不支持
- InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而MyISAM 用一个变量保存了整个表的行数
- InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限
- InnoDB 是聚集索引,MyISAM 是非聚集索引。聚簇索引的文件存放在主键索引的叶子节点上,因此 InnoDB 必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而 MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
事务
原子性:要么不做要么,一次性完成的操作
一致性:事务开始到结束后,数据库的完整性没有被破坏,符合预设规则
隔离性:保证数据库的并发操作是安全的
持久性:持久化存储,防止数据丢失
隔离性是如何实现的,如何实现并发操作安全
?
脏读 不可重复读 幻读
脏读:在A事务还没提交之前,B事务查询到了修改的数据,A有可能会事务回滚
不可重复读:两次读到的数据不同
幻读:指的是在不同的时间段所读取的数据结果条数不同
隔离级别
:读未提交 读提交 可重复读 串行化
读未提交
:相当于没有隔离性,会存在脏读,不可重复读,幻读的问题
读已提交
:只能读取已经提交的事物的改变,解决了脏读,但依然存在不可重复读,幻读的问题
可重复读
:不管当前其他事务做了改变,事务有没有提交,总是能保证在不同时间段读取到的结果一致,解决了不可重复读,但依然存在幻读的问题
串行化
:给事务强制进行排序,避免冲突,从而解决所有的并发问题,使用较少,解决了幻读
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<mysql/mysql.h>
int main()
{
MYSQL mysql_con;
if(mysql_init(&mysql_con)==NULL)
{
printf("mysql init err\n");
exit(1);
}
if(mysql_real_connect(&mysql_con,"localhost","root","密码","数据库名",3306,NULL,0)==NULL);
{
printf("connect err\n");
}else
{
printf("connect success\n");
}
char* sql="insert into student values(1002,'名字',16)";
if(mysql_query(&mysql_con,sql)!=0)执行数据库语句
{
printf("query sql err\n");
}
mysql_close(&mysql_con);
}
gcc -o main main.c -lmysqlclient编译时链接库