一,数据库的概念
1,数据库的构成
服务器端其实就是一个数据库管理系统
数据库存在于一个文件中,数据库文件存在于磁盘上,数据库管理系统
数据库系统(DBS) 包含数句库(DB)和数据库管理系统()
数据库是一个CS模式服务器,客户端(就是TCP连接)
总是通过数据可得客户端连接到数据库的服务器端然后通过SQL语句来操作
查看数据库服务状态
service mysql status 查看数据库服务状态(是否启动)
二,数据库的基本操作
端口号:3306,底层用的是TCP协议
重启,停止,启动,数据库的命令
数据库的登录退出
上面的root是数据库管理员root
mysql刚装好,root用户没有设置密码,此时可以直接登录
创建数据库,删除数据库
create datebase +名字 charset =utf8;
创建数据库,防止乱码
drop database 数据库名
删除数据库
mysql> drop database testdb;
Query OK, 0 rows affected (0.00 sec)mysql>
查看数据库,查看当前使用了那个数据库,使用某个数据库,展示某个数据库里面的表
数据库(数据库文件存在磁盘上) 数据库管理系统构成数据库 service mysql status 查看数据库服务状态(是否启动)
端口号:3306,底层用的是TCP协议 mysql -uroot -p 登录成数据库管理员 show databases;查看各种数据库
show tables;查看具体的一个数据库(表格) quit退出数据库 create datebase +名字 charset
=utf8;创建数据库,防止乱码 select database( );查询当前使用的数据库create table students (id int,name varchar,age int);创建学生表
insert into student values(1001,“那么”,18);插入数据
显示数据库的版本
select version();
mysql> select version();
±------------------------+
| version() |
±------------------------+
| 8.0.25-0ubuntu0.20.04.1 |
±------------------------+
1 row in set (0.00 sec)
四,数据表的操作
创建数据表,查看表结构,修改表结构,修改表名称
create table students (id int,name varchar,age int);
创建学生表
desc 表名;
查看表结构
alter table 表名 modify sn int primary key sn
为约束键
alter table 表名 add age int;
添加年龄这一列
alter table student change birthday birth datetime;
重命名字段
alter table 表名 drop age int;
删除这列//删除字段
alter table 原表名 rename [to] 新表名;
修改表的名字,其中to可以省略
创建表
VACHAR用的较多
键值约束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
创建学生表
查看表结构
查看表结构也就是的各个字段的信息。
添加年龄这一列
重命名字段
修改表名称
表的查询
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 “%三%”;
查询带“三”的name
排序查询,去重查询,分页查询,条件查询,分组查询
排序查询
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;
获取前三行
条件查询
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
分组查询
以指定字段为依据,对表中数据进行分组统计
分组查询结果中只能有分组依据字段以及聚合函数
分组查询的过滤条件不能使用where语句只能使用having
select role,max(salary),min(salary),avg(salary) from 表名 group by role;以岗位进行分组,显示最大值,最小值,平均值
利用聚合函数统计某字段某数据个数,一个字段所有数据和,平均值,最大值,最小值
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 表名;
求英语成绩的最小值
向表中插入数据,删除表中数据,修改表中数据,删除表
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='张三';
修改内容
drop table 表名;
删除表
delete from 表名;
删除所有的数据
alter table 表名 drop age int;
删除这列
delete from 表名 where name='张三';
删除一行
测试c语言连接数据库
测试c语言连接数据库,这里连接’test’库,没有自己创建
#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);
}
//连接到mysql
//if(mysql_real_connect(&mysql_con,"localhost","root","密码","数据库名",端口号,NULL,0)==NULL)
if(mysql_real_connect(&mysql_con,"localhost","root","Ljl123456789","c219db",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连接
mysql_close(&mysql_con);
}
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<mysql/mysql.h>
5
6 int main()
7 {
8 MYSQL mysql_conn;
9 MYSQL *mysql=mysql_init(&mysql_conn);
10 if(mysql==NULL)
11 {
12 printf("mysql init err\n");
13 exit(1);
14 }
15 mysql=mysql_real_connect(mysql,"localhost","root","Ljl123456789","c219db",3306,NULL,0);
16 if(mysql==NULL)
17 {
18 printf("connect mysql err\n");
19 exit(1);
20 }
21 char *sql="insert into student values(1004,'小红',12)";
22 int n=mysql_query(mysql,sql);
23 if(n!=0)
24 {
25 printf("query sql err:%s\n",mysql_error(mysql));
26 mysql_close(mysql);
27 exit(1);
28 }
29 mysql_close(mysql);
30 exit(0);
31
32 }
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>
int main()
{
MYSQL mysql;
if ( mysql_init(&mysql) == NULL )
{
printf("mysql init err\n");
return 0;
}
if (
mysql_real_connect(&mysql,"localhost","root","123456","testdb",3306,NULL,0) ==
NULL)
{
printf("connect mysql failed\n");
return 0;
}
printf("connect mysql success\n");
//char* sql = "insert into student2 values(6,'小王')";
char* sql = "select * from student2";
int query_res = mysql_query(&mysql,sql);
if ( query_res != 0 )
{
printf("query err:%s\n",mysql_error(&mysql));
return 0;
}
//MYSQL_RES * mysql_res =mysql_use_result(&mysql);
MYSQL_RES * mysql_res =mysql_store_result(&mysql);
if ( mysql_res == NULL )
{
printf("result err:%s\n",mysql_error(&mysql));
return 0;
}
//判断返回的行数
int num = mysql_num_rows(mysql_res);
if ( num == 0 )
{
printf("没有记录\n");
return 0;
}
printf("得到:%d 条记录\n",num);
MYSQL_ROW sqlrow;
for( int i = 0; i < num; i++)
{
sqlrow = mysql_fetch_row(mysql_res);
if (sqlrow == NULL)
{
printf("数据处理完,或者出错\n");
break;
}
//判断列数
int fields = mysql_field_count(&mysql);
for( int j = 0; j < fields; j++)
{
printf("fieds[%d]=%s\n",j,sqlrow[j]);
}
}
//MYSQL_ROW sqlrow = NULL;
//while( ( sqlrow = mysql_fetch_row(mysql_res)))
//{
//printf("sqlrow[0]=%s,sqlrow[1]=%s\n",sqlrow[0],sqlrow[1]);
// }
mysql_free_result(mysql_res);
mysql_close(&mysql);
}
看书mysql数据库(三大范式)
第一范式:表中的所有字段必须保持原子特性(省 市)
第二范式:表中所有的字段都必须与主键完全相关,而不能部分相关(主要针对组合主键的使用,就是有一个字段只与其中的一个主键有关),不完全相关会出现大量的数据冗余。
第三范式:表中的字段必须与主键直接相关,不能间接相关(会数据冗余)
多表联查
多表联查
将多张表的数据合并在一起进行查询
表中的数据取笛卡尔积进行合并
合并规则: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;
视图
索引
索引
作用:大大提高数据的查询效率
消耗:以插入,更新,删除的效率为代价
表中的那些字段适合作为索引:
1.表中的这个字段被作为查询依据的条件的频率较高
2.经常修改的字段不适合作为索引
3.有大量重复的数据字段是不适合作索引(可以重复)
4.索引字段尽量使用数据或者固定长度的字段
alter table 表名 add index(字段名)增加索引
show index from 表名;查看索引
alter table 表名 drop index 字段名;删除索引
create index 索引名 on 表名(字段名)
drop index 索引名 on 表名(字段名)
聚簇索引:一张表中只能有一个聚簇索引,其他索引都是辅助索引
非聚簇索引:并不区分主键索引和辅助索引,在物理磁盘上也不一定是有序的
当我们表中字段设置成主键,唯一键,外键约束,则对应字段会自动生成索引
你只需要创建索引,查询时会自己使用索引
索引的底层结构是b+树,其他的数据结构也可以,当数据量打的时候b+树稳定性更高;
索引假的太多会增大开销,不要一昧的增加索引,不太必要的列上就不要加索引了,后面数据表修改时也要修改索引
创建表并向表中加入数据
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<unistd.h>
4 #include<string.h>
5 #include<mysql/mysql.h>
6
7 int main()
8 {
9 MYSQL mysql_conn;
10 MYSQL*mysql=mysql_init(&mysql_conn);
11 if(mysql==NULL)
12 {
13 printf("mysql init err\n");
14 exit(1);
15 }
16
17 mysql=mysql_real_connect(mysql,"localhost","root","Ljl123456789","c219db",3306,NULL,0);
18 if(mysql==NULL)
19 {
20 printf("connect err\n");
21 exit(1);
22 }
23
24 char sql_buff[128]={0};
25
26 for(int i=0;i<10000;i++)
27 {
28 sprintf(sql_buff,"insert into test_index values('hello-%d')",i);
29 if(mysql_query(mysql,sql_buff)!=0)
30 {
31 break;
32 }
33 }
34
35 mysql_close(mysql);
36 }
创建索引
加索引和不加索引的查询时间
删除索引
事务
事务
特点:
原子性:要么不做要么,一次性完成的操作 一致性:事务开始到结束后,数据库的完整性没有被破坏,符合预设规则
隔离性:保证数据库的并发操作是安全的 持久性:持久化存储,防止数据丢失
隔离性是如何实现的,如何实现并发操作安全?
脏读 不可重复读 幻读
脏读:在A事务还没提交之前,B事务查询到了修改的数据,A有可能会事务回滚
不可重复读:两次读到的数据不同
幻读:指的是在不同的时间段所读取的数据结果条数不同
隔离级别:读未提交 读提交 可重复读 串行化
读未提交:相当于没有隔离性,会存在脏读,不可重复读,幻读的问题
读已提交:只能读取已经提交的事物的改变,解决了脏读,但依然存在不可重复读,幻读的问题
可重复读:不管当前其他事务做了改变,事务有没有提交,总是能保证在不同时间段读取到的结果一致,解决了不可重复读,但依然存在幻读的问题
串行化:给事务强制进行排序,避免冲突,从而解决所有的并发问题,使用较少,解决了幻读
事务看成一组sql语句,将一组SQL视为一个独立的单元,要么都执行,要么都不执行;
事务的特性
隔离级别
查看当前的隔离级别
查看系统的隔离级别
设置隔离级别