MySQL 学习笔记
MySQL 学习笔记
lololowe数据库
认识数据库系统
数据库的发展历程:人工管理、文件管理、数据库管理
数据库的基本概念:数据库系统、数据库、数据库应用系统、数据库管理系统、数据库管理员
数据库的应用模式:C/S、B/S
数据模型:层次数据模型、网状数据模型、关系数据模型、面向对象数据模型
数据模型三要素:数据结构、数据操作、数据完整性约束
结构化查询语言(SQL)的组成:数据定义语言、数据操作语言、数据控制语言、事务控制语言
主流数据库:Oracle数据库、DB2数据库、SQL Server数据库、MySQ数据库
免安装版(5.7.19)的安装及简单配置
将MySQL解压到指定目录(下载链接)
将
bin
目录添加到环境变量中在MySQL根目录中创建配置文件:
my.ini
1
2
3
4
5
6
7
8
9
10
11[client]
port=3306
default-character-set=utf8
[mysqld]
basedir=D:\\mysql\mysql-5.7.19-winx64 # 安装目录
datadir=D:\\mysql\mysql-5.7.19-winx64\data # 数据目录
bind-address=127.0.0.1
port=3306
character-set-server=utf8
# skip-grant-tables #跳过安全检查在安装目录中使用管理员终端安装MySQL服务:
mysqld --install
若提示找不到msvcr120.dll,则需要安装运行库(https://www.ghxi.com/visualcppredist.html)
删除已安装的mysql服务:sc delete mysql
使用管理员终端初始化MySQL并复制临时密码:
mysqld --initialize --console
如果报错安装时报错,则删除data文件夹(
D:\\mysql\mysql-5.7.19-winx64\data
)重新初始化修改注册表中的MySQL服务路径:
注册表路径:
\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MySQL
将 ImagePath 的数值数据修改为:"D:\mysql-5.7.9-winx64\bin\mysql.exe" MySQL
启动MySQL服务并设置开机自启:
管理员终端执行:
net start mysql && sc config mysql start= auto
或者打开服务管理器services.msc
后再手动启动MySQL服务
查看服务状态:net query mysql
; 手动启动模式:sc config mysql start= demand
登录MySQL服务:
mysql -u root -p
或者使用默认的本地主机和端口号连接:
mysql -h localhost -P 3306 -u root -p
注意:-p密码不要有空格、-p后面没有写密码,回车会要求输入密码(隐藏)、如果没有写-h主机,默认就是本机、如果没有写-p端口,默认就是3306、在实际工作中,3306一般会修改修改root用户密码:
SET PASSWORD FOR root@localhost='666';
重置密码的过程:
在
my.ini
文件中添加以下2行内容:1
2[mysqld]
skip-grant-tables执行命令
net stop mysql && net start mysql
(重启 MySQL 服务)执行命令
mysql -u root
(以 root 用户身份登录到 MySQL)执行命令
use mysql;
(选择mysql
数据库)执行命令
UPDATE user SET authentication_string = PASSWORD('新密码') WHERE User = 'root';
(将 root 用户的密码设置为 “新密码”)执行命令
FLUSH PRIVILEGES;
(刷新权限)执行命令
exit
(退出 MySQL)根据需要,注释掉
skip-grant-tables
并重启 MySQL
- 退出服务器:
quit
或exit
使用图形化管理工具
Navicat
SQLyog
MySQL三层结构
数据库管理系统(DBMS)
数据库(Database)
表(Table)
普通表的本质仍然是文件
数据在数据库中的存储方式
按行(row)和列(col)来存储
表的一行称为一条记录,在Java程序中,一行记录往往使用对象表示
SQL语句分类
- DDL(Data Definition Language)数据定义语句[creat 表,库]
- DML(Data Manipulation Language)数据操作语句[增加 insert, 修改 updata, 删除 delete]
- DQL(Data Query Language)数据查询语句[select]
- DCL(Data Control Language)数据控制语句[管理数据库]
创建数据库
1 | CREAT DATABASE [IF NOT EXISTS] <数据库名>[CHARACTER SET <字符集名>] [COLLATE <排序规则名>] |
CHARACTER SET
指定数据库采用的字符集,如果不指定,则采用默认的字符集(UTF8)COLLATE
指定数据库字符集的排序规则,如果不指定,则采用默认不区分大小写的排序规则(utf8_general_ci)数据库名称必须以字母、下划线或美元符号开头。
练习:创建、查询数据库.sql
创建一个名称为
mkbk_db01
的数据库创建一个使用
utf8
字符集的mkbk_db02
数据库创建一个使用
utf8
字符集,并指定排序规则为utf8_bin
的mkbk_db03
数据库使用图形化工具在
mkbk_db03
数据库中创建一个名称为mkbk
的表, 并使用SELECT
语句查询该表中的内容,以验证排序规则是否正确。
1 | #1. 创建一个名称为mkbk_db01的数据库 |
查看、删除数据库语句
显示数据库语句:
1
SHOW DATABASES;
显示数据库创建语句:
1
SHOW CREATE DATABASE <数据库名>;
删除数据库语句:
1
DROP DATABASE <数据库名>;
练习:查看和删除数据库.sql
1 | #查看当前数据库服务器中的所有数据库 |
备份/恢复数据库
备份数据库(注意:在DOS执行)
mysqldump -u <用户名> -p -B 数据库1 数据库2 数据库n > 文件名.sql
恢复数据库(注意:进入Mysq命令行再执行)
Source 文件名.sql
练习 : 备份和恢复数据库.sql
- 备份 mkbk_db02 和 mkbk_db03 库中的数据,并恢复
1 | #备份, 要在 Dos 下执行, mysqldump 指令其实在 mysql 安装目录\bin\mysqldump.exe |
备份恢复数据库的表
备份命令:
1
mysqldump -u root -p密码 数据库 表1 表2 表n > d:\\文件名.sql
注意:在DOS下执行, 没进入mysql环境不算执行sql语句,所以不用在其后加分号
恢复命令:
1
mysql -u root -p密码 数据库 < d:\\文件名.sql
注意:在DOS下执行, 没进入mysql环境不算执行sql语句,所以不用在其后加分号
或者
1 | use 数据库; |
数据类型
MySQL 常用数据类型(列类型)
数值类型
BIT: 位类型,存储位值,取值范围为1到64位。
TINYINT:小整数类型,取值范围为-128到127。
SMALLINT:短整数类型,取值范围为-32768到32767。
MEDIUMINT:中等整数类型,取值范围是-8388608到8388607。
INT:整数类型,取值范围为-2147483648到2147483647。
BIGINT:大整数类型,取值范围为-9223372036854775808到9223372036854775807。
FLOAT:单精度浮点数类型,存储4字节的浮点数。
DOUBLE:双精度浮点数类型,存储8字节的浮点数。
DECIMAL:定点数类型,用于存储精确的小数,可以指定精度和小数位数。
字符串类型
- CHAR:固定长度字符串类型,最多可以存储255个字符。
- VARCHAR:可变长度字符串类型,最多可以存储65535个字符。
- TEXT:文本类型,用于存储较长的文本数据,最多可以存储65535个字符。
- ENUM:枚举类型,用于存储预定义的字符串值。
- SET:集合类型,用于存储多个预定义的字符串值。
日期和时间类型
- DATE:日期类型,格式为’YYYY-MM-DD’,范围为’1000-01-01’到’9999-12-31’。
- TIME:时间类型,格式为’HH:MM:SS’,范围为’-838:59:59’到’838:59:59’。
- DATETIME:日期和时间类型,格式为’YYYY-MM-DD HH:MM:SS’,范围为’1000-01-01 00:00:00’到’9999-12-31 23:59:59’。
- TIMESTAMP:时间戳类型,存储从’1970-01-01 00:00:01’到’2038-01-19 03:14:07’的秒数。
其他类型
- BLOB:二进制大对象类型,用于存储二进制数据,最多可以存储65535个字节。
- JSON:JSON数据类型,用于存储JSON格式的数据。
- BOOLEAN:布尔类型,存储true或false。
演示整型数值类型的使用方式
1 | #演示整型数值类型的使用方式 |
演示位(BIT)类型的使用方式
1 | #演示 BIT 类型使用 |
演示位小数类型的使用方式
1 | -- FLOAT/DOUBLE [UNSIGNED] : 单精度小数和双精度小数 |
演示字符串(文本)类型的使用方式
1 | #演示字符串类型使用 char varchar |
字符串(文本)类型的使用细节
细节1
- char(4) //这个4表示字符数(最大255),不是字节数,不管是中文还是字母都
是放四个, 按字符计算 - varchar(4) //这个4表示字符数,不管是字母还是中文都以定义好的表的编码
来存放数据 - 不管是中文还是英文字母,都是最多存放4个,是按照字符来存放的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#演示字符串(文本)类型的使用细节
#char(4) 和 varchar(4): 这个4表示的是字符,而不是字节, 不区分字符是汉字还是字母
CREATE TABLE t13(`name` CHAR(4));
INSERT INTO t13 VALUES('你好世界');
INSERT INTO t13 VALUES('你好世界!'); -- 报错,超出最大4个字符的范围
SELECT * FROM t13;
CREATE TABLE t14(`name` VARCHAR(4));
INSERT INTO t14 VALUES('你好世a') -- 中英混合
SELECT * FROM t14;
#如果 varchar 不够用,可以使用 mediumtext 或者 longtext,如果想简单点,可以直接使用 text
CREATE TABLE t15 (content TEXT, conten2 MEDIUMTEXT, content3 LONGTEXT);
INSERT INTO t15 VALUES('你好世界', '玛卡巴卡','唔西迪西唔西迪西');
SELECT * FROM t15- char(4) //这个4表示字符数(最大255),不是字节数,不管是中文还是字母都
细节2
- char(4)是定长(固定的大小),就是说,即使你插入’aa’,也会占用分配的
4个字符的空间 - varchar(4)是变长(变化的大小),就是说,如果你插入了’aa’,实际占用空
间大小并不是4个字符,而是按照实际占用空间来分配 - varchar本身还需要占用1-3个字节来记录存放内容长度:L = 实际数据大小 + (1~3)Byte
- char(4)是定长(固定的大小),就是说,即使你插入’aa’,也会占用分配的
细节3
- 什么时候使用char,什么时候使用varchar
- 1.如果数据是定长,推荐使用char,比如md5的密码,邮编,手
机号,身份证号码等.char(32) - 2.如果一个字段的长度是不确定,我们使用varchar,比如留
言,文章 - 查询速度:CHAR > VARCHAR
- 存储空间:CHAR < VARCHAR
细节4
- 在存放文本时,也可以使用Text数据类型.可以将TEXT列视为
VARCHAR列,注意Text不能有默认值.大小0 ~ 2^16 Byte - 如果希望存放更多字符,可以选择MEDIUMTEXT (0 ~ 2^24)或者LONGTEXT(0 ~ 2^32)
- 在存放文本时,也可以使用Text数据类型.可以将TEXT列视为
演示字日期类型的使用方式
1 | #演示时间相关的类型 |
表操作
创建表
1 | CREATE TABLE table_name |
示例
1 | #创建表时,要根据需保存的数据创建相应的列,并根据数据的类型定义相应的列类型。 |
创建表练习
创建一个员工表emp,选用适当的数据类型
字段 | 属性 |
---|---|
id(标识符) | 整形 |
name(名称) | 字符型 |
sex(性别) | 字符型 |
brithday(生日) | 日期型 |
entry_date(入职日期) | 日期型 |
job(工作) | 字符型 |
Salary(工资) | 小数型 |
resume(简历) | 文本型 |
1 | # 创建表练习 |
DML 数据操作语句
操作列
添加列
1
2
3ALTER TABLE table_name
ADD (column_name datatype [DEFAULT expr],
column_name datatype [DEFAULT expr]);修改列
1
2
3ALTER TABLE table_name
MODIFY (column_name datatype [DEFAULT expr],
column_name datatype [DEFAULT expr]);删除列
1
2ALTER TABLE table_name
DROP (column_name);修改列名
1
2ALTER TABLE table_name
CHANGE old_column_name new_column_name datatype;查看表的结构
1
DESC table_name;
1 | # 修改表的操作练习 |
数据操作: C[create]R[read]U[update]D[delete]语句
INSERT
、UPDATE
、DELETE
、SELECT
INSERT
1 | # insert 语句的细节 |
UPDATE
1 | -- 演示 update 语句 |
DELETE
1 | -- delete 语句演示 |
SELECT
SELECT语句是用于从数据库中检索数据的基本语句。其基本语法如下:
1 | SELECT 列名1, 列名2, ... FROM 表名 WHERE 条件; |
SELECT
关键字指示查询开始。列名1, 列名2, ...
是要返回的列名。可以使用 * 来返回所有列。FROM
关键字指定要查询的表名。WHERE
关键字用于指定可选的过滤条件。
可以用as
(alias)给查询结果集的列或表达式指定别名,以便在结果集中更清晰地标识或引用它们
1 | SELECT column_name AS alias_name |
实例:
1 | CREATE TABLE student ( |
SELECT 使用表达式对查询的列进行运算
1 | -- SELECT 使用表达式对查询的列进行运算 |
SELECT 使用 where 过滤条件
1 | -- SELECT 使用 where 过滤条件 |
函数
统计函数
COUNT(column)
: 计算某列的行数。SUM(column)
: 计算某列的总和。AVG(column)
: 计算某列的平均值。MAX(column)
: 找出某列的最大值。MIN(column)
: 找出某列的最小值。
COUNT()
1 | -- 演示 mysql 的统计函数的使用 |
SUM()
1 | -- 演示 sum 函数的使用 |
AVG()
1 | -- 演示 avg 的使用 |
MAX()
, MIN()
1 | -- 演示 max 和 min 的使用 |
ORDER BY
1 | -- 演示 order by 使用 |
GROUP BY
1 | /*部门表*/ |
字符串函数
CHARSET(str)
: 返回字符串的字符集。CONCAT (string2 [,... ])
: 将多个字符串连接成一个字符串。INSTR (string ,substring )
: 返回子字符串在原字符串中首次出现的位置。UCASE (string2 )
: 将字符串转换成大写。LCASE (string2 )
: 将字符串转换成小写。LEFT (string2 ,length )
: 从字符串的左边起取指定长度的字符。RIGHT (string2 ,length )
: 从字符串的右边起取指定长度的字符。LENGTH (string )
: 返回字符串的长度(按照字节计算)。REPLACE (str ,search_str ,replace_str )
: 在字符串中用指定字符串替换另一个字符串。STRCMP (string1 ,string2 )
: 逐字符比较两个字符串的大小。SUBSTRING (str , position [,length ])
: 从字符串的指定位置开始取指定长度的字符。LTRIM (string2 )
: 去除字符串左边的空格。RTRIM (string2 )
: 去除字符串右边的空格。TRIM(string)
: 去除字符串两端的空格。
1 | -- 演示字符串相关函数的使用 , 使用 emp 表来演示 |
数学相关函数
ABS(num)
: 返回一个数的绝对值。BIN(decimal_number)
: 将一个十进制数转换为二进制。CEILING(number2)
: 向上取整,返回不小于指定数的最小整数。CONV(number2, from_base, to_base)
: 进制转换,将一个数从指定的进制转换为另一个进制。FLOOR(number2)
: 向下取整,返回不大于指定数的最大整数。FORMAT(number, decimal_places)
: 格式化数字并保留指定的小数位数(四舍五入)。HEX(DecimalNumber)
: 将一个十进制数转换为十六进制。LEAST(number, number2 [,..])
: 返回指定数字中的最小值。MOD(numerator, denominator)
: 返回两个数相除的余数。RAND([seed])
: 返回一个随机数,范围在 0 到 1 之间。如果提供了种子(seed),那么每次调用都会返回相同的随机数。
1 | -- 演示数学相关函数 |
时间日期相关函数
CURRENT_DATE()
: 返回当前日期。CURRENT_TIME()
: 返回当前时间。CURRENT_TIMESTAMP()
: 返回当前的日期时间戳。DATE_ADD(datetime, INTERVAL n unit)
: 在日期时间上加上一段时间间隔。DATE_SUB(datetime, INTERVAL n unit)
: 在日期时间上减去一段时间间隔。DATEDIFF(date1, date2)
: 返回两个日期之间的天数差。TIMEDIFF(time1, time2)
: 返回两个时间之间的时间差。YEAR(date)
: 返回日期中的年份。MONTH(date)
: 返回日期中的月份。DAY(date)
: 返回日期中的天数。UNIX_TIMESTAMP()
: 返回从1970年1月1日以来的秒数(时间戳)。FROM_UNIXTIME(unix_timestamp, format)
: 将时间戳转换为指定格式的日期时间。
1 | -- 日期时间相关函数 |
系统函数和加密函数
USER()
: 返回当前用户和主机名。DATABASE()
: 返回当前正在使用的数据库名称。MD5(str)
: 计算字符串的 MD5 散列值,通常用于对用户密码进行加密。PASSWORD(str)
: MySQL特定的加密函数,用于加密用户的密码。在MySQL数据库中,用户密码就是使用PASSWORD()
函数加密后的密文。
1 | -- 演示加密函数和系统函数 |
流程控制函数
IF(expr1,expr2,expr3)
: 如果expr1
为真,则返回expr2
,否则返回expr3
。1
SELECT IF(TRUE, '北京', '上海') FROM DUAL; -- 返回 '北京'
IFNULL(expr1,expr2)
: 如果expr1
为NULL
则返回指定的替代值expr2
,如果不为NULL
则返回原始值expr1
。1
SELECT ename, IFNULL(comm, 0.00) AS 奖金 FROM emp;
CASE WHEN expr1 THEN expr2 WHEN expr3 THEN expr4 ELSE expr5 END
: 类似多重分支。如果expr1
为真,则返回expr2
,如果expr2
为真,则返回expr4
,否则返回expr5
。1
2
3
4
5
6
7
8SELECT ename,
CASE
WHEN job = 'CLERK' THEN '职员'
WHEN job = 'MANAGER' THEN '经理'
WHEN job = 'SALESMAN' THEN '销售人员'
ELSE job
END AS 职位
FROM emp;
1 | # 演示流程控制语句 |
DQL 数据查询语句
单表查询巩固练习
1 | -- 单表查询巩固练习 |
分页查询
语法:
1 | SELECT column1, column2, ... |
SELECT
:指定要查询的列或表达式。FROM
:指定要查询的表名或表的联接。WHERE
:可选项,用于指定筛选条件。ORDER BY
:可选项,用于指定排序的列和排序顺序。LIMIT
:offset表示偏移量,即从查询结果的第几条记录开始返回,count表示返回的记录数量。
1 | -- 分页查询 |
使用分组统计函数和分组子句 group by
1 | -- 增强 group by 的使用 |
多表查询
在默认情况下:当两个表查询时, 规则
- 从第一张表中,取出一行 和第二张表的每一行进行组合 , 返回结果[含有两张表的所有列]
- 一共返回的记录数为第一张表行数*第二张表的行数
- 这样多表查询默认处理返回的结果,称为笛卡尔积
- 解决这个多表的关键就是要写出正确的过滤条件 where
1 | -- 多表查询 |
多表查询的自连接
自连接:把一张表连接查询两次,查询的结果是两张表的记录的组合(将同一张表看作两张表)
1 | -- 多表查询的自连接 |
多表子查询
- 子查询是指嵌入在其它sql语句中的select语句,也叫嵌套查询
- 单行子查询:单行子查询是指只返回一行数据的子查询语句请
- 多行子查询:多行子查询指返回多行数据的子查询 使用关键字 IN
1 | -- 子查询的演示 |
子查询的临时表
1 | CREATE TABLE Orders( |
all
和 any
的使用
1 | -- all 和 any 的使用 |
多列子查询
1 | -- 多列子查询 |
子查询练习
1 | -- 子查询练习 |
自我复制数据(蠕虫复制)
- 为了对某个 sql 语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据
1 | -- 表的复制 |
合并查询 UNION
UNION ALL
UNION
用于合并两个查询的结果集,并去除重复的行。它的语法如下:1
2
3
4
5SELECT column1, column2, ...
FROM table1
UNION
SELECT column1, column2, ...
FROM table2;- 查询的列数和数据类型必须匹配,否则会出现错误。
UNION
自动去重,确保合并后的结果集中不会包含重复行。
UNION ALL
也用于合并两个查询的结果集,但不会去除重复的行。它的语法如下:1
2
3
4
5SELECT column1, column2, ...
FROM table1
UNION ALL
SELECT column1, column2, ...
FROM table2;UNION ALL
不去重,合并后的结果集可能包含重复的行。UNION ALL
的执行速度通常比UNION
快,因为它不需要进行去重的额外工作。
1 | -- 合并查询 |
外连接 LEFT/RIGHT JOIN ON
1 | -- 外连接 |
约束
主键约束 PRIMARY KEY
用于唯一的标示表行的数据,当定义主键约束后,该列不能重复
primary key(主键)-细节说明
- primary key:不能重复而且不能为null。
- 一张表最多只能有一个主键,但可以是复合主键
- 主键的指定方式有两种, 一种是直接在字段名后指定,一种是在表定义最后写primary key(列名):
- 使用desc表名,可以看到primary key的情况.
- 在实际开发中,每个表往往都会设定一个主键,而且主键一般都会是整数,并且主键一般都会是自增的。
1 | -- 主键使用 |
唯一约束 UNIQUE
当定义了唯一约束后,该列值是不能重复的。
unique细节(注意):
- 如果没有指定not null,则unique字段可以有多个null
- 一张表可以有多个unique字段
1 | -- unique的使用 |
外键约束 FOREIGN KEY
用于定义主表和从表之间的关系: 外键约束要定义在从表上,主表则必须具有主键约束或是unique约束,当定义外键约束后,要求外键列数据必须在主表的主键列存在或是为null
细节:
- 外键指向的表的字段,要求是primary key 或者是unique
- 表的类型是innodb,这样的表才支持外键
- 外键字段的类型要和主键字段的类型一致(长度可以不同)
- 外键字段的值,必须在主键字段中出现过,或者为null(前提是外键字段允许为null)
- 一旦建立主外键的关系,数据不能随意删除了
1 | -- 外键演示 |
检查约束 CHECK
1 | -- 演示 check 的使用 |
练习
1 | -- 使用约束的练习 |
自增长 AUTO_INCREMENT
自增长使用细节
- 一般来说自增长是和primary key配合使用的
- 自增长也可以单独使用[但是需要配合一个unique]
- 自增长修饰的字段为整数型的(虽然小数也可以但是非常非常少这样使用)
- 自增长默认从1开始,你也可以通过此命令修改
ater table 表名 auto increment = 新的开始值;
- 如果你添加数据时,给自增长字段(列)指定的有值,则以指定的值为准,如果指定了自增长,一般来说,就按照自增长的规则来添加数据.
1 | -- 演示自增长的使用 |
索引
原理
索引是帮助数据库高效获取数据的数据结构。
当我们没有索引时,默认进行全表扫描(索引),查询速度慢
思考如果我们比较了30次,覆盖的表的则是范围2^30
如果对表进行dml(修改,删除,添加),将会对索引进行维护,对速度有影响
1 | -- 在没有创建索引时,我们的查询一条记录 |
分类
- 主键索引(PRIMARY KEY):它是一种特殊的唯一索引,不允许有空值。
- 普通索引(INDEX):最基本的索引,没有任何限制。
- 唯一索引(UNIQUE):与普通索引类似,不同的就是索引列的值必须唯一,但允许有空值。
- 全文索3引(FULLTEXT)[适用于MyISAM]一般开发,不使用mysq自带的全文索引,而是使用:全文搜索框架Solr ElasticSearch (ES)
1 | CREATE TABLE t28( |
使用索引
1 | -- 演示 mysql 的索引的使用 |
使用规则
较频繁作为查询条件字段应该创建索引:这是索引的主要作用之一,可以加快查询速度。
唯一性太差的字段不适合单独创建索引:如果一个字段的唯一性非常差,比如大部分行都具有相同的值,那么在该字段上创建索引可能不会带来明显的性能提升。
更新非常频繁的字段不适合创建索引:当一个字段的值经常被更新时,维护索引会导致额外的开销,因此在这种情况下创建索引可能会降低性能。
不会出现在WHERE子句中的字段不应该创建索引:索引的目的是加速查询,如果一个字段不会被用于过滤或搜索条件,那么在其上创建索引通常没有实质性的帮助。
练习
1 | /*1.创建一张订单表order(id号,商品名,订购人,数量). |
事务
概念
事务用于保证数据的一致性,它由一组相关的dml(Data Manipulation Language,即数据操作语言)语句组成,该组的dml语句要么全部成功,要么全部失败。如:转账就要用事务来处理,用以保证数据的一致性。
使用
在介绍回退事务前,先介绍一下保存点(savepoint)。保存点是事务中的点,用于取消部分事务,当结束事务时(commit),会自动的删除该事务所定义的所有保存点,当执行回退事务时,通过指定保存点可以回退到指定的点。
使用commiti语句可以提交事务,当执行了commit语句子后,会确认事务的变化、结束事务、删除保存点、释放锁,数据生效。当使用commiti语句结束事务子后,其它会话[其他连接]将可以查着到事务变化后的新数据(所有数据就正式生效)。
1 | -- 演示 |
细节
- 如果不开始事务,默认情况下,dml操作是自动提交的,不能回滚
- 如果开始一个事务,没有创建保存点.可以执行rollback,默认就是回退到事务开始的状态.
- 也可以在这个事务中(还没有提交时),创建多个保存点.
- 你可以在事务没有提交前,选择回退到哪个保存点
- mysqlf的事务机制需要innodb的存储引擎才可以使用,myisam不好使.
- 开始一个事务
start transaction;
或set autocommit = off;
隔离级别
事务隔离级别是数据库管理系统(DBMS)用来控制不同事务之间相互影响程度的一种机制。在 MySQL 中,有四种事务隔离级别,分别是:
READ UNCOMMITTED(读未提交):
- 最低的隔离级别。
- 允许一个事务可以读取另一个事务未提交的数据。
- 可能会导致脏读、不可重复读、幻读等问题。
READ COMMITTED(读已提交):
- 允许一个事务只能读取另一个事务已经提交的数据。
- 避免了脏读问题,但仍然可能存在不可重复读和幻读的问题。
REPEATABLE READ(可重复读):
- 确保一个事务在执行期间看到的数据是一致的。
- 在同一个事务内的多次读取相同数据会得到相同的结果,不受其他事务的影响。
- 避免了脏读和不可重复读问题,但仍然可能存在幻读问题。
SERIALIZABLE(串行化):
- 提供最高级别的隔离。
- 确保事务之间完全隔离,不会发生任何并发问题,但可能会导致性能下降。
在 MySQL 中,默认的事务隔离级别是 REPEATABLE READ。
你可以在启动事务时通过以下语句来设置不同的隔离级别:
1 | SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; |
每种隔离级别都有其适用的场景,选择正确的隔离级别取决于具体的业务需求和数据一致性要求。需要根据实际情况来权衡隔离级别的选择。
隔离问题
脏读、不可重复读和幻读是在并发事务环境下可能出现的三种数据一致性问题。
脏读(Dirty Read):
- 脏读发生在一个事务读取了另一个事务未提交的数据。
- 例如,事务A修改了一行数据,但还未提交,此时事务B读取了这行数据。如果事务A回滚,那么事务B读取的数据就是无效的。
- READ UNCOMMITTED 隔离级别允许脏读。
不可重复读(Non-repeatable Read):
- 不可重复读发生在一个事务内两次读取同一行数据,但得到的结果不一致。
- 例如,事务A首先读取了一行数据,然后事务B修改了这行数据并提交。随后,事务A再次读取同一行数据,但得到了不同的结果。
- READ COMMITTED 隔离级别避免了脏读,但仍然可能发生不可重复读。
幻读(Phantom Read):
- 幻读发生在一个事务内两次查询同一范围的数据,但得到的结果集不一致。
- 例如,事务A首先查询了一个范围内的数据,然后事务B插入了一些新数据,符合范围条件。接着,事务A再次查询相同范围的数据,但结果集发生了变化,出现了新增的”幻影”行。
- REPEATABLE READ 和 SERIALIZABLE 隔离级别避免了幻读。
不同的事务隔离级别会导致不同程度的这些问题:
- READ UNCOMMITTED 允许脏读、不可重复读和幻读。
- READ COMMITTED 避免脏读,但仍可能发生不可重复读和幻读。
- REPEATABLE READ 避免了脏读和不可重复读,但仍可能发生幻读。
- SERIALIZABLE 提供了最高级别的隔离,可以避免脏读、不可重复读和幻读,但可能会影响性能。
选择合适的隔离级别取决于具体的业务需求和数据一致性要求。需要根据实际情况来权衡隔离级别的选择。
示例
1 | -- 查看当前会话隔离级别 |
存储引擎
- 介绍
如何选择
修改存储引擎
1 | ALTER TABLE table_name ENGINE = new_engine_name; |
- 示例
1 | -- 存储引擎 |
参考课程: