【MySQL】基础入门大全

【MySQL】基础入门大全

目录

一、安装流程

二、SQL语句

三、多种查询方法

四、理解数据库

五、总结



温馨提示:
                我的Linux环境为:Ubuntu 20.04 LTS
                我的mysql版本为:Ver 8.0.42 for Linux on x86_64
                为了方便操作,以下大部分操作使用超级用户身份


一、安装流程

前置:获取 MySQL APT 配置包,用于给系统添加正确的软件源
下载官网:MySQL :: Begin Your Download
下载不要解压,通过 rz 指令传输到服务器中


开始安装:(安装过程忘记截图了,相当于省流了)

1.su - 切换为超级用户,确保安装包通过rz指令发送到了服务器

2.dpkg -i mysql-apt-config_0.8.36-1_all.deb 安装下载的 MySQL APT 配置包

3.设置安装选项,mysql8.0和确认工具...(安装过程中会跳出弹窗,我的是两个设置选项,第一个选择版本,第二个点enable确认安装组件和工具,最后选择OK回车)

4.apt-get update 更新一下安装包

5.apt-get install mysql-server 安装mysql(过程比较慢)

6.安装完成会弹窗,根据提示设置密码和确认密码

7.systemctl status mysql 查看mysql服务是否正常运行,有绿色字体就是正常运行

8.systemctl enable mysql 设置开机自启动(根据需求)

9.systemctl list-unit-files | grep mysql 查看自动动是否设置成功


关于主配置文件:/etc/mysql/mysql.conf.d/mysqld.cnf

其中datadir是存放我们创建数据库的地方

这里面有些关键属性没写,因为已经内置了,默认也不需要手动配置,不过想配置可以通过修改该文件进行配置;默认配置可以通过mysql相关指令查到

查看默认端口号:3306

查看默认字符集:utf8mb4(更完整的 UTF-8)

查看默认存储引擎:innodb


二、SQL语句

1.SQL语句分类:

  • DDL 【 data definition language 】数据定义语言,用来维护存储数据的结构;
    代表语句:create ,drop ,alter
  • DML【data manipulation language】数据操纵语言,用来对数据进行操作;
    代表指令: insert,delete,update
  • DQL【Data Query Language】,DML中单独分了一个DQL,数据查询语言;
    代表指令: select
  • DCL【Data Control Language】数据控制语言,主要负责权限管理和事务;
    代表指令: grant,revoke,commit

2.基础语句

 连接MySQL指令:mysql -h 127.0.0.1 -P 3306 -u root -p

功能:以root用户身份连接本机 MySQL 数据库,需要输入密码

选项:

        -h:指明登录部署了mysql服务的主机ip,这里使用本地环回地址,表明登录自己的主机

        -P:指明我们要访问的端口号

        -u:指明登录的用户,这里使用的是root超级用户

        -p:后跟密码,不建议后面直接跟密码,建议回车进行不回显输入

(注意:当 MySQL 部署在你当前的机器上时,-h-P 这两个参数是可以省略的)


2.1库的操作

1.创建数据库
语法:create database db_name;

功能:本质就是再 /var/lib/mysql 下创建一个目录

语法:create database if not exists db_name;

功能:如果创建的数据库存在,会抛出错误警告,不会导致已存在的数据库被覆盖,能更安全的创建数据库

语法:create database d1 charset=utf8mb4 collate utf8mb4_general_ci;

功能:创建一个字符集为utf8mb4,校验集为utf8mb4_general_ci的数据库

(注意:不设置的就会使用默认字符集和校验集,或者配置文件中设置的字符集和校验集)字符集(Character Set):决定了数据库可以存储哪些字符,以及这些字符如何被编码成二进制数据,比如utf8mb4支持包括 Emoji 在内的所有 Unicode 字符。校验集(Collation):定义了字符的比较和排序规则,比如是否区分大小写、是否区分重音,它直接影响ORDER BYWHERE条件的匹配结果

注意:在较新的 MySQL 版本中,collate也可以直接用 = 符号赋值

2.查看数据库
语法:show databases;

功能:查看已创建的数据库

语法:show create database db_name;

功能:显示创建语句;/*!40100 default.... */这个不是注释,表示当前mysql版本大于4.01版本,就执行这句话,可以看到数据库创建时指定的字符集和是否启用加密(ENCRYPTION='N'表示没有启用加密)

语法:show processlist;

功能:可以查看有哪些人连接了我们当前的MySQL,以及具体的工作数据库

(注意:这个 event_scheduler 不是普通的用户,它是 MySQL 内置的事件调度器守护进程)
3.删除数据库
语法:drop database db_name;

功能:本质就是再 /var/lib/mysql 下删除一个目录,对应的数据库文件夹被删除,级联删除,里面的数据表全部被删;也可以在databdase后加上if exists以此删除前判断是否存在该数据库
4.修改数据库
语法:alter database d1 charset=gbk collate gbk_chinese_ci;

功能:修改数据库d1的字符集和校验集
5.切换当前工作数据库
语法:use db_name;

功能:用来切换当前工作数据库的核心命令;执行这条命令后,后续所有的 SQL 操作(比如 CREATE TABLESELECTINSERT 等)都会默认在 db_name 这个数据库里进行,无需每次都显式指定数据库名。

补充语句:select database();

功能:可以查看当前工作数据库
6.数据库的备份与还原
备份指令:mysqldump -P3306 -u root -p 密码 -B 数据库名 > 数据库备份存储的文件路径

示例:mysqldump -P3306 -uroot -p -B database1 > mytest.sql

还原语句:source 路径

示例:source /root/MySQL/mytest.sql

注意事项如果备份的不是整个数据库,而是其中的一张表,怎么做?
mysqldump -u root -p 数据库名 表名1 表名2 > D:/mytest.sql同时备份多个数据库
mysqldump -u root -p -B 数据库名1 数据库名2 ... > 数据库存放路径如果备份一个数据库时,没有带上-B参数, 在恢复数据库时,需要先创建空数据库,然后使用数据 库,再使用source来还原;(如果改变创建数据库的名称,这个过程也能完成对数据库重命名操作)

2.2表的操作

1.创建表
语法:create table table_name (

                field1 datatype,

                field2 datatype,

                field3 datatype

        ) character set=字符集 collate=校验规则 engine=存储引擎;field 表示列名datatype 表示列的类型;参考下文数据类型character set 字符集,如果没有指定字符集,则以所在数据库的字符集为准collate 校验规则,如果没有指定校验规则,则以所在数据库的校验规则为准engine 存储引擎同上table后面可以跟if not exists,可以避免将已有同名表覆盖的风险

注意:定义列时,最后一列的后面不跟逗号;另外最后一行的 = 号也可以用空格代替)

示例:create table users(
                id int,        
                name varchar(20) comment '用户名',
                password char(32) comment '密码',
                birthday date comment '生日'
         )character set=utf8mb4 collate=utf8mb4_general_ci;(comment后面跟的是备注)

注意:不同的存储引擎,创建表的文件后缀和数量不一样(还和mysql版本有关)
2.查看表结构
语法:show tables;

功能:可以查看当前数据库中有哪些表

语法:desc 表名;

功能:查看详细的表结构

语法:show create table 表名 \G;

功能:可以查看建表时的语句(\G可以调整格式)
3.修改表
语法:alter table 表名 add 字段 字段类型 comment '备注' after 位于哪个字段后面;

功能:在指定表里新增一个字段,也就是新增列;如果想在表最前面新增字段可以把after以及后面的替换成first;如果不写after或first,新字段默认会添加到表结构的最后

示例:alter table users add image_path varchar(100) comment '图片路径' after birthday;

语法:alter table 表名 modify 字段 要修改的字段类型 comment '要修改的备注';

功能:修改字段的类型和备注,也可以只修改一部分

示例:alter table users modify name varchar(60);

语法:alter table 表名 drop 要删除的字段;

功能:删除表的指定字段(注意:删除字段及其对应的列数据都没了)

示例:alter table users drop password;

语法:alter table 表名 rename 新表名;

功能:修改表名

示例:alter table users rename to user;

语法:alter table 表名 change 旧字段名 新字段名 字段类型 [其他属性];

功能:对字段重命名,注意新字段后面必须跟着字段类型;而其它属性如comment备注,如果不写,备注会保持原样

示例:alter table employee change name xingming varchar(60);
4.删除表
语法:drop table 表名;

功能:删除指定的表table后跟if exists可以避免删除表不存在的报错一次性删除多张表,表之间用逗号分隔

2.3表数据的插入

1.插入数据
语法:insert into 表名 values(1,'张三','2000-01-04','a'),(2,'李四','2004-01-04','b');

功能:在指定表中新增两条记录,注意添加的数据类型和数量都要匹配上;表名后面可以加上括号(),在括号里面可以指定要插入数据的字段,默认不加就是全列插入;

语法:insert into 表名(字段,...) values (数据,...) on duplicate key update 字段=更新数据,...;

功能:插入否则更新;插入数据时如果出现数据冲突则更新为on duplicate key update后面的数据;
插入结果有以下三种情况:0 row affected: 表中有冲突数据,但冲突数据的值和 update 的值相等,相当于无事发生1 row affected: 表中没有冲突数据,数据被插入,正常插入2 row affected: 表中有冲突数据,并且数据已经被更新,相当于对已有数据进行了修改

示例:第三种情况以上是现有数据,经过插入否则更新操作后,如下图:“Query OK, 2 rows affected (0.01 sec)”就对应着第三种情况,将冲突数据更新了

语法:replace into stu (字段,...) values (字段,...);

功能:主键 或者 唯一键 没有冲突,则直接插入;主键 或者 唯一键 如果冲突,则删除后再插入;

成功有两种情况:1 row affected: 表中没有冲突数据,数据被插入2 row affected: 表中有冲突数据,删除后重新插入

示例:之前的'赵六'被删除了并且重新插入了'王五'
2.插入查询结果
语法:insert into [要插入的表名] select [查询语句];

作用:将查询的结果插入表中

案例:删除表中的重复记录 --- 表去重操作要去重的表结构和数据如下:我们先创建一张空表 no_duplicate_table,结构和 duplicate_table 一样,然后将 duplicate_table 的去重数据插入到 no_duplicate_table:语法:insert into no_duplicate_table select distinct * from duplicate_table;最后通过重命名表,实现原子的去重操作:
第一步:将原表 duplicate_table 重命名为 old_no_duplicate_table;
第二步:紧接着将原表 no_duplicate_table 重命名为 duplicate_table;语法:rename table duplicate_table to old_no_duplicate_table, no_duplicate_table to duplicate_table;最后查询 duplicate_table 数据就被去重了

2.4基本查询

1.select
我们先创建一张成绩表,以及插入数据,如下图:

全列查询语法:select * from 表名;

指定列查询语法:select 字段,... from 表名;

查询字段为表达式语法:select 字段,... 表达式 as 重命名 from 表名;重命名前的as可以省略,如果重命名和as都省略默认以表达式作为查询的列名

查询结果去重语法:select distinct 字段,... from 表名;
2.where 条件子句
比较运算符:

逻辑运算符:

案例:接着select中的表结构查询(修改了数据)

1.英语不及格的同学及英语成绩 < 60语法:select name,english from exam_result where english < 60;2.语文成绩在 [80, 90] 分的同学及语文成绩语法1:select name,chinese from exam_result where chinese >= 80 and chinese <= 90;语法2:select name,chinese from exam_result where chinese between 80 and 90;3.数学成绩是 52 或者 59 或者 98 或者 99 分的同学及数学成绩语法1:select name,math from exam_result where math = 52 or math = 59 or math = 98 or math = 99;语法2:select name,math from exam_result where math in(52,58,98,99);4.姓孙的同学 及 孙某同学(孙某是指两字,姓孙是两字及以上)%匹配多个字符语法:select name from exam_result where name like '孙%';_严格匹配一个字符语法:select name from exam_result where name like '孙_';5.语文成绩好于英语成绩的同学语法:select name,chinese,english from exam_result where chinese > english;6.总分在 220 分以下的同学语法:select name, chinese+math+english 总分 from exam_result where chinese+math+english < 220;注意:这里where子句不能使用别名'总分'与220进行比较,这和实际语句执行顺序有关,where执行靠前识别不到重命名7.语文成绩 > 80 并且不姓孙的同学语法:select name,chinese from exam_result where chinese > 80 and name not like '孙%';8.查孙某同学,否则要求总成绩 > 200 并且 语文成绩 < 数学成绩 并且 英语成绩 > 80语法:select name,chinese,math,english,chinese+math+english as 总分 from exam_result where name like '孙_' or ( chinese
+ math + english > 200 and chinese < math and english > 80 );

NULL相关查询,查询如下这张表:

查询所有名字为空的数据语法:select * from test where name is null; (注意不能直接用=,可以用<=>)从结果上看很明显 id=4 的name=空串不属于null查询名字为空串语法:select * from test where;查询所有名字不为null语法:select * from test where name is not null;
3.order by结果排序
语法:select 字段,... from 表名 order by 要排序的字段 [asc/desc];

功能:将查询到的结果根据要排序的字段进行排序,asc 为升序(从小到大),desc 为降序(从大到小),默认不写为asc升序

示例:依旧是2.4的成绩表查询同学和其数学成绩,升序/降序排序升序:select name, math from exam_result order by math asc;降序:select name, math from exam_result order by math desc;默认(升序):select name, math from exam_result order by math;查询同学及总分,由高到低语法:select name,chinese+math+english as 总分 from exam_result order by 总分 desc;注意:order by 支持使用重命名,因为它实际执行顺序靠后,能识别到重命名
4.limit筛选分页结果
语法:在查询语句的末尾添加 limit,有三种常用写法:limit n:从结果的第 1 条开始,取前 n 条数据limit s, n:从结果的第 s+1 条开始,取 n 条数据(s 是起始位置的偏移量,从 0 开始计数)limit n offset s:和 limit s, n 效果完全相同,语义更清晰,推荐使用;注意这里n在前,s在后,意思还是跳过前s条数据,从s+1开始去n条数据

作用:当查询结果数据量很大时,通过分页只加载当前需要的少量数据,避免一次性查询大量数据导致的数据库性能问题,同时提升前端页面的加载速度和用户体验

示例:查询数学成绩前3名同学语法1:select name,math from exam_result order by math desc limit 3;语法2:select name,math from exam_result order by math desc limit 0,3;语法3:select name,math from exam_result order by math desc limit 3 offset 0;

2.5表数据的更新

1.update数据更新
语法:update [要更新的表名] set [更新的字段] = [新数据] (where/order/limit查询结果);

作用:对查询的结果进行列值更新

注意:若不跟where等条件子句,会默认对整张表的指定字段执行全表更新,将表中所有行的该字段数据统一变更为 set 后指定的值

示例:还是上面那张成绩表案例:将孙悟空同学的数学成绩变更为 80 分语法:update exam_result set math = 80 where name = '孙悟空';案例:将孙七同学的数学成绩变更为 60 分,语文成绩变更为 70 分语法:update exam_result set math = 60, chinese = 70 where name = '孙七';案例:将总成绩倒数前三的 3 位同学的数学成绩加上 10 分语法:update exam_result set math = math + 10 order by chinese + math + english limit 3;注意:增加或者减少某个字段的数值,只能使用类似 math = math + 10 这样的语法,而不能使用 += 或 -= 这样的编程语法

2.6表数据删除

1.delete删除数据
语法:delete from 表名(where/order/limit查询语句);

注意:不跟查询子句默认就是删除整张表的数据

示例:成绩表案例:删除孙悟空同学的考试成绩语法:delete from exam_result where name = '孙悟空';案例:删除整张表数据注意:删除整张表操作要慎用,这里另建表演示,新表如下图:语法:delete from for_delete;注意:因为我们id字段是设置了自增长,虽然我们删除了所有数据,但是下次重新插入name时,id是会从之前的数据继续递增的,我们通过查看建表语句就可以看到,如下图:修改自增长语法:alter table for_delete auto_increment = 1;
2.truncate截断表
语法:truncate 表名;

特点:只能对整表操作,不能像 delete 一样针对部分数据操作;实际上 mysql 不对数据操作,所以比 delete 更快,但是 truncate 在删除数据的时候,并不经过真正的事务,所以无法回滚会重置 auto_increment 项,所以我们不需要像delete那样重新设置

示例:以上是准备要删除的表结构和数据;删除语法:truncate for_truncate;通过插入查询,可以看到 auto_increment 项被重置了

2.7聚合函数



案例:以上面成绩表为例1.统计班级共有多少同学语法:select count(*) from exam_result;注意:使用 * 做统计,不受 NULL 影响,也可以是某个字段;2.统计本次考试的数学成绩分数个数语法:select count(math) from exam_result;3.统计数学成绩总分语法:select sum(math) from exam_result;4.统计总分的平均分语法:select avg(chinese + math + english) 平均总分 from exam_result;5.返回英语最高分语法:select max(english) from exam_result;6.返回 > 70 分以上的数学最低分语法:select min(math) from exam_result where math > 70;

(聚合函数后面也可以跟名称重命名)

三、多种查询方法

1.分组查询 group by

group by:SQL 中用于对查询结果按指定字段进行分组聚合的核心子句,核心作用是将查询结果中字段值相同的行归为一个分组,把原本按单条记录展示的结果,聚合为按 “分组维度” 展示的组级结果;它必须配合聚合函数使用,实现对每个分组单独做统计计算,以此完成从 “单条数据查询” 到 “分类统计分析” 的转换,是实现各类分组统计需求的基础。

案例:创建一个雇员信息表(来自oracle 9i的经典测试表)EMP员工表:DEPT部门表:SALGRADE工资等级表:1.如何显示每个部门的平均工资和最高工资解释:只有emp员工表中同时有部门号和工资信息,所以在emp表中做分组查询,这里要查询每个部门,所以我们对部门deptno进行分组;语法:select deptno,avg(sal),max(sal) from emp group by deptno;注意:一般只有 group by 后面指定分组的字段,以及聚合函数能出现在select的左侧; 2.显示每个部门的每种岗位的平均工资和最低工资解释:group by 后面可以指定多个分组字段,这里我们可以分组部门deptno和岗位job语法:select deptno,job,avg(sal),min(sal) from emp group by deptno,job;因为对两个字段进行了分组,所以不同部门相同岗位这样的就不是一组,只有相同部门和相同岗位才会被归为一组3.显示平均工资低于2000的部门和它的平均工资我们可以先统计各个部门的平均工资:select deptno,avg(sal) 平均工资 from emp group by deptno;再使用 having 配合 group by 进行进一步查询过滤:语法:select deptno,avg(sal) 平均工资 from emp group by deptno having avg(sal) < 2000;

关于 having 和 where 的区别:where是对具体的任意列做条件筛选having是对分组聚合之后的结果进行条件筛选 where 不能用聚合函数(如 avg、count),having 可以基于聚合函数筛选where 必须在 group by 之前,having 必须在 group by 之后

2.单表查询练习

案例:使用上面的emp员工表1.查询工资高于500或岗位为manager的雇员,同时还要满足他们的姓名首字母为大写的j语法:select * from emp where (sal>500 or job='manager') and ename like 'j%';2.按照部门号升序而雇员的工资降序排序语法:select * from emp order by deptno asc, sal desc;解释:会先满足deptno升序,然后在deptno相同的情况下以sal降序3.使用年薪进行降序排序语法:select ename, sal*12 + ifnull(comm,0) as '年薪' from emp order by 年薪 desc;解释:使用ifnull判断有没有奖金,ifnull使用介绍在下文其他函数中4.显示工资最高的员工的名字和工作岗位语法:select ename, job from emp where sal = (select max(sal) from emp);(子查询)5.显示工资高于平均工资的员工信息语法:select ename, job, sal from emp where sal > (select avg(sal) from emp);(子查询)

3.多表查询

实际开发中往往数据来自不同的表,所以需要多表查询

(1)笛卡尔积

以上面的oracle 9i的经典测试表为例,假如我们要查的数据包括员工名和其所在部门的部门名,那么部门名就只能去部门表中查了;当我们直接查两张表会出现下面的效果:select * from emp,dept;这里表显示太多了,截取一部分,我们可以看到查出来的两张表,其实是将两张表进行穷举组合形成一张新表,比如红色框内一个员工与4个部门的组合;这种组合的计算方式就叫做 ---- 笛卡尔积笛卡尔积结果集行数 = 表 A 的总行数 × 表 B 的总行数 × … × 表 N 的总行数

注意:因为不同表有不同或相同字段名,因此在多表查询时,使用类似c++对象.成员的方式区分不同表的字段,例如emp表的ename字段就表示为:emp.ename

(2)多表查询案例

1.显示雇员名、雇员工资以及所在部门的名字语法:select emp.ename, emp.sal, dept.dname from emp, dept where emp.deptno = dept.deptno;解释:我们只需要在两者表的组合表中使用where自己过滤查询到两张表部门号相同的行信息即可;2.显示部门号为10的部门名,员工名和工资语法:select ename, sal, dname from emp, dept where (emp.deptno=dept.deptno) and (dept.deptno = 10);3.显示各个员工的姓名,工资,及工资级别语法:select ename, sal, grade from emp, salgrade where emp.sal between losal and hisal;

4.自连接

自连接是指在同一张表连接查询

用法:在有些情况下,需要对自身表进行多次查询,为了一条语句解决,因此我们可以将自身表与自身表进行笛卡尔积组合

注意:自身笛卡尔积组合时,要重命名

案例:还是上面的oracle 9i的经典测试表例:显示员工ford的上级领导的编号和姓名(mgr是员工领导的编号--empno)解释:因为员工表emp既包含了普通员工也包含了领导,所以我们必须对这张表进行两次查询,这时候就可以用自连接了语法:select leader.empno, leader.ename from emp as leader, emp as worker where (leader.empno = worker.mgr) and (worker.ena= 'ename = 'ford');语法解释:将插入的两张相同员工表分别重命名为 leader 和 worker,然后条件筛选员工名为ford的,并且其mgr与领导表的员工号empno相等的

当然也可以用子查询:select empno,ename from emp where emp.empno=(select mgr from emp where ename='FORD');这样就不用自连接了

5.子查询

概念:子查询是将一个 SELECT 查询嵌套在另一个 SQL 语句的 WHERE/FROM/HAVING 等子句中,先执行内层嵌套查询,再将其结果作为外层语句的筛选、关联或计算依据的查询方式。

(以下案例还是使用oracle 9i的经典测试表)

(1)单行子查询

概念:内层只返 1 行结果,能直接跟 > < =用;

示例:显示与smith同一部门的员工语法:select * from emp where deptno = (select deptno from emp where ename = 'smith');

(2)多行子查询

概念:内层返≥2 行结果,必须搭in/all/any才能用,直接用=就报错。

关键字:in/all/any是多行子查询中,外层查询与内层多行结果做条件匹配的关键字,其中in匹配任意一个,all匹配全部,any匹配任意一个(与in等效,仅语法场景有差异)1.in关键字;查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的语法:select ename,job,sal,deptno from emp where job in (select distinct job from emp where deptno=10) and deptno != 10;2.all关键字;显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号语法:select ename,sal,deptno from emp where sal > all(select sal from emp where deptno = 30);3.any关键字;显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)语法:select ename,sal,deptno from emp where sal > any(select sal from emp where deptno = 30);

(3)多列子查询

概念:单行子查询是指子查询只返回单列单行数据;多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询则是指查询返回多个列数据的子查询语句案例:查询和smith的部门和岗位完全相同的所有雇员,不含smith本人语法:select ename from emp where (deptno, job) = (select deptno, job from emp where ename = 'smith') and ename != 'smith';

(4)在from子句中使用子查询

概念:子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用

案例:1.显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资语法:select ename, deptno, sal, format(asal,2) from emp, (select avg(sal) as asal, deptno as dt from emp group by deptno) as tmp where emp.sal > tmp.asal and emp.deptno = tmp.dt;2.查找每个部门工资最高的人的姓名、工资、部门、最高工资语法:select emp.ename, emp.sal, emp.deptno, ms from emp, (select max(sal) as ms, deptno from emp group by deptno) as tmp where emp.deptno = tmp.deptno and emp.sal = tmp.ms;3.显示每个部门的信息(部门名,编号,地址)和人员数量语法:select dept.deptno, dname, mycnt, loc from dept, (select count(*) as mycnt, deptno from emp group by deptno) as tmp where dept.deptno = tmp.deptno;

6.合并查询

在实际应用中,为了合并多个select的执行结果,可以使用集合操作符 union,union all

(1)union

概念:该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。案例:将工资大于2500或职位是manager的人找出来语法:select ename, sal, job from emp where sal > 2500 union select ename, sal, job from emp where job = 'manager';

(2)union all

概念:该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。案例:将工资大于25000或职位是manager的人找出来语法:select ename, sal, job from emp where sal > 2500 union all select ename, sal, job from emp where job = 'manager';

7.表的内连和外连

(1)内连接

概念:内连接是通过关联条件(ON)只保留多张表中匹配关联条件的记录,不匹配的记录会被过滤掉的联表查询方式;内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。

语法:select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件;案例:显示smith的名字和部门名称语法:select ename, dname from emp inner join dept on emp.deptno = dept.deptno and ename = 'smith';

(2)外连接

外连接分为左外连接和右外连接

2.1左外连接

概念:左外连接以左侧表为基准,保留左表所有记录,右表仅匹配关联条件的记录会显示,不匹配的字段填充 NULL 的联表查询方式;如果联合查询,左侧的表完全显示我们就说是左外连接。

语法:select 字段名  from 表名1 left join 表名2 on 连接条件;2.2右外连接

概念:右外连接以右侧表为基准,保留右表所有记录,左表仅匹配关联条件的记录会显示,不匹配的字段填充 NULL 的联表查询方式;如果联合查询,右侧的表完全显示我们就说是右外连接。

语法:select 字段 from 表名1 right join 表名2  on 连接条件;
案例:oracle 9i的经典测试表列出部门名称和这些部门的员工信息,同时列出没有员工的部门左外连接:select d.dname, e.* from dept as d left join emp e on d.deptno = e.deptno;右外连接:select d.dname, e.* from emp as e right join dept as d on d.deptno = e.deptno;可以看到operations部门信息都为空


四、理解数据库

1.为什么要有数据库?文件也能储存数据啊

文件保存数据有以下几个缺点:文件的安全性问题文件不利于数据查询和管理文件不利于存储海量数据文件在程序中控制不方便

数据库存储介质:磁盘内存

所以,为了解决上述问题,专家们设计出更加利于管理数据的东西——数据库,它能更有效的管理数据

2.服务器、数据库、表之间的关系

所谓安装数据库服务器,只是在机器上安装了一个数据库管理系统程序,这个管理程序可以管理多 个数据库,一般开发人员会针对每一个应用创建一个数据库为保存应用中实体的数据,一般会在数据库中创建多个表,以保存程序中实体的数据数据库服务器、数据库和表的关系如下:


3.数据类型

(1)数值类型

数据类型说明
bit(m)位类型;m 指定位数,默认值 1,m范围 1-64;查询时默认以ASCII值显示
tinyint [unsigned]1字节整数;带符号的范围 - 128~127,无符号范围 0~255;默认有符号
bool使用 0 和 1 表示真和假;占1字节
smallint [unsigned]2字节整数;带符号是 - 2^15 到 2^15-1,无符号是 2^16-1
int [unsigned]4字节整数;带符号是 - 2^31 次方 到 2^31-1,无符号是 2^32-1
bigint [unsigned]8字节整数;带符号是 - 2^63 次方 到 2^63-1,无符号是 2^64-1
float(m,d)[unsigned]m 指定显示长度,d 指定小数位数,占用 4 字节
double(m,d) [unsigned]表示比 float 精度更大的小数,占用空间 8 字节
decimal(m,d) [unsigned]定点数 m 指定总长度,d 表示小数点的位数;底层字符串精确存储,占用空间动态,每 9 位数字占用 4 字节,不足 9 位也按 4 字节计算

(2)文本、二进制类型

数据类型说明
char(size)固定长度字符串,最大长度 255字节;
varchar(size)可变长度字符串,最大长度 65535字节;编码不同实际可设置的最大值不同
blob二进制数据
text大文本,不支持全文索引,不支持默认值

(3)时间日期

数据类型说明
date/datetime/timestamp日期类型(yyyy-mm-dd)/yyyy-mm-dd hh:mm:ss)/ timestamp 带时间戳 每次修改能够自动更新时间

(4)String类型

数据类型说明
enumenum 是一个字符串对象,其值来自表创建时在规定中显示枚举的一列值;相当于单选,如选性别enum('男','女');插入对应值时必须是设置的选项或者下标(从0开始)
setset 是一个字符串对象,可以有零或多个值,其值来自表创建时规定的允许的一列值。指定多个 set 成员的 set 列值时各成员之间用逗号间隔开。该 set 成员值本身不能包含逗号;相当于多选,如选兴趣爱好set('爱好1', '爱好2' ...);set可以一次插入多个选项,用单引号括起来,逗号分隔;也可以把所有选项看作比特位,最左边选项对应比特位右边最低位,比特位对应的十进制数字可以一次选多个选项

数据类型是对字段的约束,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性


4.表的约束

表的约束:表中一定要有各种约束,通过约束,让我们未来插入数据库表中的数据是符合预期的。约束木质是通过技术手段,倒逼程序员,插入正确的数据。反过来,站在 mysql 的视角,凡是插入进来的数据,都是符合数据约束的!



约束的最终目标:保证数据的完整性和可预期性

约束有很多,这里介绍如下几个:

(1)空属性

两个值:null 和 not null

作用:约束该字段能否为空,null可以为空,null不用特意设置,默认字段就是可以为空;not null不可以为空;

示例:创建一个简单班级表,class_name 和 class_room 字段不能为空,other字段可以为空,表结构如下图:如图框住部分就是我们设置的空属性约束,NO就是不能为空,YES就是可以为空;此时我们往表里面分别插入完整数据和缺省数据看看效果:可以看到,前两次插入数据class_name和class_room都插入了具体数据,没有问题,other字段也可以省略;第三次是当我们不给class_room插入具体数据时就会报错;这就是空约束的效果

(2)默认值

关键字:default

默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候, 用户可以选择性的使用默认值;相当于c++中的缺省值;

示例:创建一张表,name字段不能为空,age字段默认值为18,sex字段默认男;如图可以从框住部分看到默认值;当我们插入数据时,不给有默认值的插入就会自动使用默认值插入;

关于默认值和空属性:

结论:从主观感受上,default 和 not null 好像有点不搭,但其实这两者并不冲突,而是互相补充;如果一个字段同时设置的 not null 和 default,那么当用户插入数据时忽略这一列,mysql就会自动使用default的值插入一个字段只有数据类型,没有手动设置任何约束时,它的默认值default其实是NULL,也就是可为NULL空

验证:如上面这张表,当我们插入数据时忽略name字段,就会使用默认值:通过查看建表语句,就可以看到age字段其实是带有默认值,这是mysql自动补全的

(3)列描述

关键字:comment

列描述:没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA 来进行了解;简单来说就是对字段的一种备注说明,在上面创建表时已经演示过了,这里不再演示;列描述不显示在 desc 的表结构中,查看需要show查看建表语句;



如何理解comment是一种约束:它可以看成是对程序员的一种软约束,当我们看到该字段的描述时,就能知道该字段的含义,以及应该插入什么样的数据;

(4)zerofill

zerofill:是所有数值类型(整数 / 浮点 / 定点)通用属性,核心功能为按字段定义的显示宽度对数值左侧补 0(仅作用于查询显示,不改变实际存储值),使用时会自动为字段添加unsigned无符号属性,无法存储负数。

示例:如图,创建表t3时,a字段后面没有跟括号数字,但是desc显示是10,这个数字是指整形的显示宽度(默认不指定就是10),对实际存储大小无影响,但是搭配zerofill,就能指定左侧补0的最大长度了;并且zerofill会自动将a字段设置为unsigned无符号整形;插入数据的效果如上图所示,会在左侧剩余显示宽度处补0,如果超过设置的显示宽度就不会补0了;

(5)主键

关键字:primary key

主键:primary key 是一张表中唯一且不能为空的标识字段,能唯一确定表中的每一行数据,自带唯一索引加速查询,一张表只能有一个 primary key,用于保证数据不重复、不缺失,是数据定位与关联表的核心依据;主键所在的列通常是整数类型。

注意:主键一张表仅能定义一个,并非限制仅一个字段能作为主键组成部分,该主键既可是单个字段的单字段主键,也可是多个字段联合组成的复合主键

(1)两种建表时设置主键的方法:第一种就是在字段类型后面跟上 primary key,表结构中 PRI 所在的行就是主键通过建表语句我们就能看到第二种设置主键方式,就是在建表的最后一行使用 primary key(字段...) 进行设置,然后我们也能看到设置主键的字段会自动设置为 not null 约束;

(2)主键的特性、删除操作、建表后添加操作:可以看到,当插入数据的 id 不重复时,可以正常插入,可是一旦插入重复的,就会报错,这就是一张表中主键唯一的特性;通过该特性,我们可以很轻易通过where子句查询到主键对应的一列数据,如下图:如何删除主键约束:使用 alter table 表名 drop primary key; 如下图:后续如何设置主键:alter table 表名 add primary key(字段列表); 如下图:

(3)关于复合主键,简单点说就是两个及以上的字段都设置为主键,这些主键字段只要插入的数据组合不是完全一样的就没有问题;如下:我们创建一个存储学生课程及其成绩的表,因为学生可以选多个课程,一个课程又可能被多个学生选,所以这种场景我们就可以把学生id和课程id都设置为主键;当我们插入数据时,只要不是插入相同的学生id和课程id就不会报错:一旦插入与历史主键数据一样的就会报错:

(6)自增长

自增长:auto_increment;当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值 +1操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。

自增长的特点:任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)也就是主键自增长字段必须是整数一张表最多只能有一个自增长

示例:我们将id字段设置为主键并且自增,后面我们插入时可以忽略id字段直接插入name字段,id自动则会从0开始自增;如下图:如果我们显示的给id插入一个较大的值,那么下次自增长将会从这个较大值开始递增;如下图:为什么设置了auto_increment的字段可以根据最新插入的值进行递增呢?原因我们可以通过查看建表语句看到:如图,红色框内就是该表下次自增的值,我们也可以手动修改设置这个值,来控制下一次从多少开始自增;手动修改语法:alter table 表名 auto_increment = 起始数值;

(7)唯一键

唯一键:unique key;一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题。

唯一键和主键的区别:主键一张表只能有一个,并且不能为空;唯一键一张表可以设置多个,并且可以为空;主键是表中行数据的唯一标识,用于精准定位单条数据、关联其他表(外键关联常用);唯一键仅用于保证数据唯一性,无行标识的核心作用;

用途:我们可以简单理解成,主键更多的是标识唯一性的。而唯一键更多的是保证在业务上,不要和别的信息出现重复;主键和唯一键是互相补充的;

示例:如上图,我们创建一张表stu,id字段设置为主键,而telephone字段设置为唯一键;唯一键的效果上看和主键差不多,都是不准插入重复值,如下图:

(key可以省略直接写unique效果一样)

(8)外键

外键:外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或 unique 唯一键约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null。

语法:foreign key (当前从表字段名) references 主表名(主表字段)

举例解释:现在有一张班级表,班级表包括班级id和班级名字name;还有一张学生表,学生表包括学号id,姓名name,还有所属班级class_id;很明显主观上这两张表就有关系,就是学生表中的class_id字段与班级表中的id字段;所以这里学生表就是从表,班级表就是主表;学生表就是通过class_id与班级表进行关联;示意图如下:

演示:我们先定义主表,班级表class,并插入一些数据,如下图:然后,再定义学生表,并设置外键class_id,如下图:我们再往学生表里插入数据,如下图:很明显,外键我们可以插入已有班级id,也可以插入NULL,但是不能插入不存在的班级id;另外如果我们删除班级表中id=1的数据,我们会发现删除不了,如下图:删除不了是因为对应班级id里关联了学生表中的数据,这就是外键的约束,能使表操作更加科学合理;

5.内置函数

(1)日期函数



示例:语法:select current_date();语法:select current_time();语法:select current_timestamp();语法:select date_add('2025_1_1', interval 10 day); 加10天语法:select date_sub('2026_1_1', interval 10 day); 减10天语法:select datediff('2026-1-1','2025-1-1'); 日期差date和now:

(2)字符串函数

与left(string2, length)对应的还有一个right:案例:将上面成绩表以成绩单的形式打印出来语法:select concat(name, ' 语文成绩:', chinese, ' 数学成绩:', math, ' 英语成绩:', english) as '成绩单' from exam_result;

(3)数学函数

绝对值:select abs(-100);向上取整:select ceiling(5.001);向下取整:select floor(-3.1);随机生成0-100数字:select format(rand()*100, 0);

(4)其他函数

user() 查询当前用户语法:select user();md5(str)对一个字符串进行md5摘要,摘要后得到一个32位字符串(加密)语法:select md5('abc');database()显示当前正在使用的数据库语法:select database();password()函数,MySQL数据库使用该函数对用户加密注意:高版本已移除,无法使用,可以使用sha2()sha2(str, hash):第二个参数是指定 SHA-2 加密算法的哈希长度,MySQL 仅支持224、256、384、512这四个有效值如:select sha2('abc', 256);ifnull(val1, val2) 如果val1为null,返回val2,否则返回val1的值;与C语言的 ? : 表达式效果类似

6.索引

6.1概念和原理

1.什么是索引:索引是 MySQL 中可提升数据库检索性能的数据库对象,是一种空间换时间的设计,无需额外加内存、改程序或调 SQL,仅通过create index即可创建,本质是对数据表字段按特定数据结构组织的目录,用于快速定位数据。MySQL 中的索引包含主键索引(primary key)、唯一索引(unique)、普通索引(index)和全文索引(fulltext)这四类。

2.索引有什么用:核心作用是成百上千倍提升海量数据的检索速度,通过减少 MySQL 与磁盘的 IO 交互次数实现查询优化;但会以增加插入、更新、删除等写操作的 IO 开销为代价,仅适用于海量数据的检索场景。

3.索引的底层数据结构和底层原理:索引底层核心数据结构为B + 树,InnoDB/MyISAM 引擎均采用该结构,MEMORY 引擎同时支持 HASH 和 B + 树;MySQL 与磁盘交互的基本单位是16KB 的 page(页),也是 B + 树的基本组成单元,page 分为存储用户实际数据的数据页和存储下级页最小键值 + 指针的目录页,多个 page 通过双向链表连接。底层原理为:MySQL 会将数据按主键自动排序后组织在 page 中,以 page 为单位加载到内存的 Buffer Pool 中,利用局部性原理减少 IO 次数;B + 树以多层目录页和数据页构建,非叶子节点仅存键值和 page 指针,叶子节点存储实际数据(聚簇索引)或主键值(辅助索引)且叶子节点彼此相连,查找时自顶向下通过目录页快速定位目标数据页,大幅减少磁盘 IO 的 page 加载次数;辅助索引查询需先通过索引获取主键,再通过主键索引查询数据,该过程为回表查询。

4.InnoDB 主键索引将表转为 B + 树的过程(全程以 16KB 的 page 为核心单位):排数据,装入数据页:将表中所有数据按主键值从小到大排序,分批存入一个个 16KB 的数据页(这是 B + 树的叶子节点);数据页之间通过双向链表连接,页内也会按主键建立小型目录,提升页内行数据的查找效率,数据页中存储完整的表行数据。建目录页,管理数据页:当数据页数量增多,MySQL 会自动生成目录页(这是 B + 树的非叶子节点);每个目录页仅存储「下级数据页 / 子目录页的最小主键值 + 对应 page 的指针」,目录页也按主键排序、双向链表连接,专门用来快速定位目标数据页。叠层生成 B + 树:若单级目录页无法管理所有下级 page,会向上生成更高层的目录页,最顶层为根目录页;最终形成「根目录页→中间目录页→数据页」的多层 B + 树,所有叶子节点(数据页)始终保持双向相连,仅数据页存完整行数据,所有目录页只存主键值 + page 指针。

5.同一张表设置多种索引,是否共用同一颗 B + 树?答:不共用;每张表的每个辅助索引(唯一、普通、全文等)都会单独创建一棵独立的 B + 树,和主键索引的 B + 树彼此分离,不会共用。且 InnoDB、MyISAM 两大主流引擎均遵循此规则,仅不同引擎的辅助索引 B + 树叶子节点存储内容有差异:InnoDB:主键索引 B + 树(聚簇索引)叶子节点存完整行数据;每个辅助索引 B + 树叶子节点仅存索引列值 + 对应行主键值,查询需回表。MyISAM:主键索引和所有辅助索引的 B + 树结构一致,叶子节点均只存数据行的磁盘地址,无回表概念,但依旧是一棵索引对应一棵独立 B + 树。简单说:一张表有多少个索引(含主键),就有多少棵独立的 B + 树。

6.2索引操作

1.索引创建:
(1)创建主键索引

所谓创建主键索引就是设置主键约束第一种方式:create table user1(id int primary key, name varchar(30)); 第二种方式:create table user2(id int, name varchar(30), primary key(id));第三种方式:alter table user3 add primary key(id);创建表以后再添加主键

主键索引的特点:一个表中,最多有一个主键索引,当然可以使符合主键主键索引的效率高(主键不可重复)创建主键索引的列,它的值不能为null,且不能重复主键索引的列基本上是int
(2)创建唯一索引

就是设置唯一键约束第一种方式:create table user4(id int primary key, name varchar(30) unique);第二种方式:create table user5(id int primary key, name varchar(30), unique(name));第三张方式:alter table user6 add unique(name); 建表后再添加唯一键

唯一索引的特点:一个表中,可以有多个唯一索引查询效率高如果在某一列建立唯一索引,必须保证这列不能有重复数据如果一个唯一索引上指定not null,等价于主键索引
(3)创建普通索引第一种方式:create table user8 (
                          id int primary key,
                          name varchar(20),
                          email varchar(30),
                          index(name) -- 在表的定义最后,指定某列为索引
                     );第二种方式:alter table user9 add index(name); 创建完表以后指定某列为普通索引第三种方式:create index idx_name on user10(name); 创建一个索引名为 idx_name 的索引,同理第二种方式,也是在建表后再设置普通索引,不过这个可设置索引名

普通索引的特点:一个表中可以有多个普通索引,普通索引在实际开发中用的比较多如果某列需要创建索引,但是该列有重复的值,那么我们就应该使用普通索引
(4)全文索引适用于大文字 / 文章字段检索,仅 MyISAM 引擎支持,默认仅支持英文,中文需借助 coreseek;不能用 like 模糊查询触发,需用 MATCH...AGAINST 语法。create table articles (
    id int unsigned auto_increment not null primary key,
    title varchar(200),
    body text,
    fulltext (title,body) -- 全文索引
)engine=myisam;使用语法:select * from articles where match (title,body) against ('检索关键词');
2.查询索引
第一种方法: show keys from 表名第二种方法: show index from 表名; 效果同上,只是语法区别第三种方式:desc 表名; 信息比较简略
3.删除索引
第一种方法--删除主键索引: alter table 表名 drop primary key;第二种方法--其他索引的删除: alter table 表名 drop index 索引名;索引名就是show keys from 表名 中的 Key_name 字段第三种方法方法: drop index 索引名 on 表名

6.3索引创建原则

比较频繁作为查询条件的字段应该创建索引唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件更新非常频繁的字段不适合作创建索引不会出现在where子句中的字段不该创建索引

7.事务

7.1事务的概念

1.什么是事务?事务(Transaction)是 MySQL 中由一组具有逻辑相关性的 DML 语句构成的操作整体,MySQL 通过专属机制保证这组语句要么全部执行成功,要么全部执行失败;同时事务会规定不同客户端可看到不同的数据状态,主要用于处理操作量大、复杂度高的数据库数据操作。

2.事务有什么用?事务核心用于解决数据库多并发操作下的数据不一致问题,通过commit 提交实现事务执行结果的持久化存储,通过rollback 回滚(可回滚至事务开始或指定保存点)及操作异常时的自动回滚,保障数据库操作的原子性,避免部分语句执行导致的数据混乱;同时结合不同隔离级别设置实现事务间的隔离性,通过提交、回滚的操作规则确保事务执行前后数据库的一致性,大幅简化应用层的数据库编程模型,让开发者无需额外处理网络异常、服务器宕机、多操作并发冲突等潜在问题,稳定支撑复杂的数据库批量操作。

3.一个完整的事务,绝对不是简单的 sql 集合,还需要满足如下四个属性:原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中 间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个 事务从来没有执行过一样。一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完 全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务 并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括:读未提交(Read uncommitted)、读提交( read committed)、可重复度(repeatable read)、串行化(Serializable)持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

(上面四个属性,可以简称为 ACID )

7.2事务的版本支持

在 MySQL 中只有使用了 lnnodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持。可通过 show engines \G 查看支持数据库事务的引擎

7.3事务的提交方式

事务的提交方式常见的有两种:自动提交、手动提交查看事务提交方式:show variables like 'autocommit';红框内是 ON 就是自动提交、OFF就是手动提交改变提交方式:set autocommit=0;设置 autocommit=0 就是手动提交,设置 autocommit=1 就是自动提交;

自动提交和手动提交的区别:自动提交(默认 autocommit=1):每条 DML 语句自动构成独立事务并即时提交,事务中若单条语句异常,仅该语句回滚,其他已提交语句不受影响。手动提交(autocommit=0 或用 begin/start transaction 开启):需显式执行 commit 才会持久化事务修改,事务中若出现异常,整个未提交的事务会自动回滚至初始状态。

注意:我们之前执行的插入、更新、删除等 DML 操作,其实本质上都是一次独立的事务,只不过 mysql 默认开启 autocommit=1 的自动提交模式,因此每一条单次执行的 DML 语句都会被 mysql 自动封装成一个完整事务并隐式完成开启与提交,而查询类的 select 语句仅遵循事务隔离级别,不会触发事务提交。

7.4事务的基本操作

基本操作:开启一次事务语法:begin 或者 start transaction创建一个保存点:savepoint 保存点名; 回滚:rollback to 保存点; (可以撤回操作到该保存点)
或者直接 rollback; 直接回滚到事务开始时提交和结束一次事物:commit

自动提交+begin开启事物 与 手动提交+begin开启事物 的区别:自动提交+begin开启事物:begin 会临时暂停自动提交机制,此时多条 DML 语句会被纳入同一个事务,需显式执行 commit 提交 /rollback 回滚;事务完成(commit/rollback)后,autocommit 会自动恢复为 1,后续单条 DML 语句又会回到 “执行即提交” 的默认状态;若事务中出现异常,仅当前未提交的事务整体回滚,不影响 autocommit 的自动恢复。手动提交+begin开启事物:autocommit 被永久修改为手动提交模式(直至主动改回 1 或会话断开),无需额外 begin,第一条 DML 语句就会自动开启事务;所有后续 DML 语句都会持续纳入当前事务,必须显式 commit/rollback 才能结束当前事务,且事务结束后 autocommit 仍为 0,下一条 DML 会自动开启新事务;若事务中出现异常,未提交的事务整体回滚,且 autocommit 不会自动恢复为 1。从执行效果来看,手动提交(autocommit=0)+begin 开启事务,和自动提交(autocommit=1)+begin 开启事务,除了提交方式的改变外,事务内部的执行效果是完全一致的换句话说,只要输入begin或者start transaction,事务便必须要通过commit提交,才会持久化,与是否设置set autocommit无关。

简单操作演示:创建测试表:插入一些数据:开始创建一个事务,创建保存点,插入数据,然后回滚一次:插入数据并commit提交:

(ctrl + \ 可以触发mysql异常终止 Aborted,在事务中如果发生异常终止,MySQL 会自动回滚该事务中所有未提交的 DML 操作,不会将任何修改持久化到数据库。)

7.5事务隔离级别

(1)概念
事务隔离存在的意义和作用:一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶段。而所谓的原子性,其实就是让用户层,要么看到执行前,要么看到执行后。执行中出现问题, 可以随时回滚。所以单个事务,对用户表现出来的特性,就是原子性。但,毕竟所有事务都要有个执行过程,那么在多个事务各自执行多个SQL的时候,就还是有可能会出现互相影响的情况。比如:多个事务同时访问同一张表,甚至同一行数据。所以在数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别

隔离级别:读未提交【Read Uncommitted】: 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复读等读提交【Read Committed】:该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果。可重复读【Repeatable Read】:这是 MySQL 默认的隔离级别,它确保同一个事务,在执行中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题(幻读是数据库事务并发时,同一个事务内多次执行完全相同的范围查询语句,却得到行数不一致的结果(仿佛凭空多了 / 少了记录)的并发问题,区别于针对单条记录值修改的不可重复读。)串行化【Serializable】:这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争 (这种隔离级别太极端,实际生产基本不使用)

(隔离级别如何实现:隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。常见有,表锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等)
(2)操作
查看隔离级别:1.查看全局隔离级别:select @@global.transaction_isolation; (低于8.0版本使用 select @@global.tx_isolation;)可以看到默认的全局隔离级别为可重复度2.查看当前会话隔离级别:select @@session.transaction_isolation; (低于8.0版本使用 select @@session.tx_isolation;)可以看到默认的当前会话隔离级别与全局隔离级别保持一致3.查看当前连接的隔离级别(与session级别一致):select @@transaction_isolation; (低于8.0版本使用 select @@tx_isolation;)

设置隔离级别:1.设置全局读未提交:set global transaction isolation level read uncommitted;2.设置当前会话读提交:set session transaction isolation level read committed;3.设置全局可重复读:set global transaction isolation level repeatable read;4.设置当前会话串行化:set session transaction isolation level serializable;

事务隔离操作的辅助注意事项:所有隔离级别测试均需结合事务开启(BEGIN/START TRANSACTION),未开启事务的单条 SQL 为 InnoDB 默认自动提交,无隔离特性;若事务未提交(commit),客户端异常终止后,MySQL 会自动回滚事务,隔离级别设置失效;RR 级别是 MySQL 默认隔离级别,一般不建议修改,兼顾并发性能和数据一致性;隔离级别仅对 InnoDB 引擎有效,MyISAM 引擎无事务及隔离级别相关操作。

8.视图

概念:视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表,基表的数据变化也会影响到视图。创建视图语法:create view 视图名 as select语句;

示例:使用oracle 9i的经典测试表案例:用视图显示所有的员工名和其所在的部门名修改视图会影响基表,如修改clark名字为CLARK:修改了基表,对视图有影响,如改回CLARK为clark:删除视图:drop view 视图名;

视图的规则和限制:与表一样,必须唯一命名(不能出现同名视图或表名)创建视图数目无限制,但要考虑复杂查询创建为视图之后的性能影响视图不能添加索引,也不能有关联的触发器或者默认值视图可以提高安全性,必须具有足够的访问权限order by 可以用在视图中,但是如果从该视图检索数据 select 中也含有 order by ,那么该视图中的 order by 将被覆盖视图可以和表一起使用

9.用户管理

9.1用户信息

MySQL中的用户,都存储在系统数据库mysql的user表中select * from user \G; 能看到user表中的所有信息:也可以只看用户名,登录主机和密码:select user,host,authentication_string from user;前三个以mysql开头的用户是 MySQL 的系统内置用户:mysql.infoschema:用于访问information_schema(存储数据库元数据的系统库),支撑元数据查询等系统操作;mysql.session:用于 MySQL 内部进程的会话连接(比如系统后台线程与数据库的交互);mysql.sys:用于管理sys模式(MySQL 5.7 + 的性能监控 / 管理工具库),提供简化的性能统计视图。

字段解释:host:表示这个用户可以从哪个主机登陆,如果是localhost,表示只能从本机登陆user:用户名authentication_string: 用户密码通过password函数加密后的*_priv:用户拥有的权限

9.2创建用户

语法:create user '用户名'@'登陆主机/ip' identified by '密码'; 密码会自动加密%代表可以从任意地方登录,注意一般不建议这样设置

9.3删除用户

语法:drop user '用户名'@'主机名'

9.4修改用户密码

自己改自己密码:set password=password('新的密码');root修改指定用户密码:set password for '用户名'@'主机名'=password('新的密码');注意:8.0版本移除了password函数,可以使用以下语法:set password for '用户名'@'主机名' = '新密码'; 会自动加密alter user '用户名'@'主机名' identified by '新密码';

9.5给用户授权

刚创建的用户没有任何权限。需要给用户授权。语法:grant 权限列表 on 库.对象名 to '用户名'@'登陆位置' [identified by '密码']权限列表:多个权限用逗号分开,常见权限如下示例:给用户txp赋予user_db数据库下所有文件的select权限此时该用户只能查看表,如果执行删除等操作就会被禁止:回收权限语法:revoke 权限列表 on 库.对象名 from '用户名'@'登陆位置';


五、总结

        访问mysql除了linux上这样纯命令行外,在语言中可以直接使用相关库和方法操作数据库,或者直接在电脑本地使用带图形化界面的客户端访问数据库,当然这些都是后话了;

        以上就是本文的全部内容,感谢你的支持!!!

Read more

计算机毕业设计java基于Java的小区物业管理系统 基于B/S架构的智慧小区综合物业服务平台设计与实现 面向多角色的小区缴费、报修与改造一体化管理系统开发

计算机毕业设计java基于Java的小区物业管理系统 基于B/S架构的智慧小区综合物业服务平台设计与实现 面向多角色的小区缴费、报修与改造一体化管理系统开发

计算机毕业设计java基于Java的小区物业管理系统n2gzw9 (配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。 随着城市化进程的加快和住宅小区的规模化发展,物业管理已成为保障居民生活质量、维护社区秩序的重要环节。传统的物业管理多依赖于人工登记、纸质台账或分散的Excel表格,存在业主信息混乱、缴费流程繁琐、报修处理不及时、改造项目难以追踪、多部门协作困难等问题,难以满足现代小区对高效、透明、协同化物业管理的需求。基于Java的小区物业管理系统应运而生,它通过互联网技术将业主管理、物业管理、施工方管理、住建委监督、住户信息、缴费管理、报修处理、改造项目等功能进行数字化整合,为小区物业管理提供了全流程的线上化协同平台。该系统不仅提升了物业管理的效率与服务质量,也为业主、物业公司、施工方、监管部门等多方角色提供了透明、便捷的信息共享渠道,成为智慧社区建设的重要组成部分。 系统核心功能概览: * 用户注册与登录:支持业主、物业、施工方、住建委、管理员五类角色的注册与登录。 * 个人中心:用户可查看和修改个人资

By Ne0inhk
IDEA报错内存溢出解决(java.lang.OutOfMemoryError)

IDEA报错内存溢出解决(java.lang.OutOfMemoryError)

目录 1.优化项目构建配置 2.调整java启动参数 编辑 编辑 3.调整Gradle/MAVEN配置 4.其他措施 IDEA在启动项目后报错内存溢出,有时直接修改JVM内存并不能全部解决问题,遇到这个问题并解决后总结了下自己的解决过程,放在这里以供有需要时查阅。 1.优化项目构建配置 在IDEA设置中增加可用内存: 在File > Settings > Build, Execution, Deployment > Compiler中,增加Shared heap size 这里不做修改,直接修改JVM虚拟机内存可能不会生效 2.调整java启动参数 在运行设置中调整JVM的Heap内存大小: 在Run > Edit Configurations中,调整 VM options。若没有此设置,可以在Modify options > Add VM options处添加。

By Ne0inhk

基于Java:同城理发预约高效服务系统

Java赋能同城理发预约:开启高效服务新时代 在快节奏的都市生活中,传统理发店的预约方式逐渐暴露出诸多弊端。电话预约效率低下,常常遭遇占线或沟通失误;到店排队不仅浪费时间,还可能因技师繁忙而等待许久。消费者对便捷、高效理发服务的需求日益迫切,而商家也急需一套能提升运营效率、优化客户体验的解决方案。基于Java开发的同城理发预约高效服务系统应运而生,为解决这些痛点提供了完美答案。 强大技术支撑,铸就系统卓越性能 Java作为功能强大且稳定可靠的编程语言,为同城理发预约系统筑牢了坚实根基。其“一次编写,到处运行”的跨平台特性,让系统能在不同操作系统和设备上无缝运行。无论是消费者使用的手机、平板,还是商家使用的管理终端,都能流畅访问系统,极大地拓宽了使用范围和用户群体。 Java的面向对象特性提供了丰富的类库和框架,帮助开发者快速构建复杂且可维护的系统。通过将用户管理、理发师管理、预约调度、支付结算等功能模块封装成独立对象,代码结构更清晰,复用性和可扩展性更强。例如,创建“用户”对象,包含基本信息、预约记录、评价反馈等属性和方法,方便不同模块管理操作。 面对理发预约高峰时段大量用

By Ne0inhk