一、基础查询
SELECT
SELECT * FROM weather;
INSERT INTO
插入数据
INSERT INTO weather VALUES ('San Francisco', 46, 50, 0.25, '1994-11-27');
UPDATE
更新数据
//语法
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
ALTER TABLE
修改表,用于增加,修改,删除列
//ADD COLUMN添加一个列
ALTER TABLE celebs ADD COLUMN twitter_handle TEXT;
//DROP COLUMN删除一个列
ALTER TABLE celebs DROP COLUMN twitter_handle;
DELETE
删除表记录
DELETE FROM test WHERE id = '1';
DROP
删除表
DELETE table test;
DISTINCT
过滤重复的数据
SELECT DISTINCT(name) FROM movies;
GROUP BY
将一列中相同值的列分成一组
//按照价格进行分组,并统计每组元素的个数
SELECT price, COUNT(*) FROM fake_apps GROUP BY price;
MAX()/SUM()/MIN()/AVG()
都是数学中的意思
SELECT name, MAX(downloads) FROM fake_apps;
二、高级查询
1、排序
依据某一列进行排序,ASC是升序排序,DESC是降序排序。
select * from 表名 order by 列1 asc/desc [,列2 asc/desc,...]
说明:先按照列1进行排序,如果列1的值相同时,则按照列2排序
示例:
查询所有学生信息,先按年龄从大到小排序,年龄相同时按身高由高到低排序:
select * from students order by age desc,height desc;
2、分页查询
select * from 表名 limit start,count
说明:
limit 是分页查询关键字
start 表示开始行索引,默认是0
count 表示查询条数
示例:
//直接取前三条数据
select * from students where sex='男' limit 3;
//从第二条开始取3条数据,即取第2、3、4条。
select * from user limit 1,3;
//表示取1后面第2,3,4三条条数据
select * from user limit 3 offset 1;
说明:offset表示偏移量,当limit和offset组合使用的时候,limit后面只能有一个参数,表示要取的的数量,offset表示要跳过的数量 。
3、聚合函数
聚合函数又叫组函数,通常是对表中的数据进行统计和计算,一般结合分组(group by)来使用,用于统计和计算分组数据。
常用的聚合函数:
- count(col):表示求指定列的总行数
- max(col):表示求指定列的最大值
- min(col):表示求指定列的最小值
- sum(col):表示求指定列的和
- avg(col):表示指定列的平均值
//求总行数
select count(height) from students;
//求最大值
select max(id) from students where sex='男';
//求最小值
select min(id) from students where is_del=0;
//求和
select sum(height) from students where sex='男';
//求平均值
select avg(height) from students where sex='男';
4、分组查询
group by 列名 [having 条件表达式] [with rollup]
说明:
列名:是指按照指定字段的值进行分组
having 条件表达式:用来过滤分组后的数据
with rollup:在所有记录的最后加上一条记录,显示select查询时聚合函数的统计和计算结果
//根据单字段来分组
select gender from students group by sex;
//根据多字段来分组
select name,sex from students group by name,sex;
group by + 聚合函数的使用:
//统计不同性别的人的平均年龄
select sex,avg(age) from students group by sex;
//统计不同性别的人的个数
select sex,count(*) from students group by sex;
group by + having的使用:
having作用和where类似都是过滤数据的,但having是过滤分组数据的,只能用于group by
//根据sex字段进行分组,统计分组条数大于2的
select sex,count(*) from students group by sex having count(*)>2;
group by + with rollup的使用:
//根据sex字段进行分组,汇总总人数
select sex,count(*) from students group by sex with rollup;
5、连接查询
1)内连接查询
查询两个表中符合条件的共有记录(取交集)
select 字段 from 表1 inner join 表2 on 表1.字段1 = 表2.字段2
示例:
select * from students s inner join classes c on s.c_id = c.id;
2)左连接查询
以左表为主根据条件查询右表数据,如果根据条件查询右表数据不存在则使用null值填充
select 字段 from 表1 left join 表2 on 表1.字段1 = 表2.字段2
示例:
select * from students s left join classes c on s.c_id = c.id;
3)右连接查询
以右表为主根据条件查询左表数据,如果根据条件查询左表数据不存在则使用null值填充
select 字段 from 表1 right join 表2 on 表1.字段1 = 表2.字段2;
示例:
select * from students s right join classes c on s.c_id = c.id;
4)自连接查询
左表和右表是同一个表,根据连接查询条件查询两个表中的数据
示例:
select c.id, c.title, c.pid, p.title from areas c inner join areas p on c.pid = p.id;
6、子查询
在一个select语句中,嵌入了另外一个select语句,那么被嵌入的select语句称之为子查询语句,外部的那个select语句则称为主查询;
SELECT * FROM employee WHERE summary > (SELECT MAX(summary) FROM employee where dept = 'sale')
三、自定义函数
1、函数定义
CREATE
[DEFINER = { user | CURRENT_USER }]
FUNCTION functionName ( varName varType [, ... ] )
RETURNS returnVarType
[characteristic ...]
routine_body
functionName:函数名,同MySQL内置函数一样,大小写不敏感
varName: 形参名
varType: 形参类型,其与varName配对使用。形参数量不限( ≥ 0 \geq 0≥0)
returnVarType: 返回值类型。函数必须有且只能有一个返回值
characteristic:函数特性,下将详述
routine_body:函数体。函数体中必须含有 return 语句,当函数体为复合结构时,需要使用begin … end 语句
示例:
CREATE DEFINER=`root`@`%` FUNCTION `myf3_byId`() RETURNS varchar(45) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci
RETURN
(SELECT NAME FROM tb_projects WHERE id = 3)
注意:RETURN VALUE 语句中包含 SELECT 语句时,SELECT 语句的返回结果只能是一行且只能有一列值
2、函数执行
SELECT <自定义函数名> ([<参数> [,...]])
3、变量
可以在存储程序(存储过程和函数)中使用变量,变量分为局部变量与用户变量。
局部变量
定义在sql语句块中的变量,常见于存储过程和函数的 begin … end 中,语句块执行完后局部变量则结束生命周期
declare var_name[,var_name] … date_type [default value];
赋值有2种方式:
- Set var_name = expr[,var_name = expr]…;
- Select col_name[,…] into var_name[…] table_expr;
DROP FUNCTION if exists `myfunTest` $$
create function `myfun`(idx int) returns int
begin
declare res int; # 声明定义1个变量, 初值默认为 null
declare num1, num2 int default 27; # 声明定义多个变量,初值全部为27
declare data1, data2 int; # 声明定义多个变量,初值全部默认为 null
set num2 = 23, res = num1 + num2; # 使用set语句, = 操作符赋值
set data1 = 1, data2 = 1;
select num, price into data1, data2 from test2 where num = idx; # 使用 select into 语句
set res := res * (data1 + data2); # 使用set语句, := 操作符赋值
return (res);
end$$
DELIMITER ;
注意: sql下的 = 操作符是比较(判定是否相等)操作符,只有在set语句中可作为赋值操作符使用。故在其他语句中,赋值操作应该使用 := 操作符
用户变量
定义在当前客户端的连接下的变量,其作用域在当前客户端连接下均有效,当当前客户端断开连接后则该变量结束生命周期。其对其他客户端连接不可见。
用户变量无需先行声明创建,直接赋值使用即可
-- 通过set赋值
set @varName = val; # 对名为 @varName 用户变量赋值
set @varName := val; # 对名为 @varName 用户变量赋值
select @varName; # 查看名为 @varName 用户变量的值
-- 通过 select 赋值
select @varName:=field [as field] [, ...] from tableName where condition;
select @varName:=Val;
4、语句
1)If分支语句
语法格式:
if condition then
……;
[elseif condition then]
……;
[else]
…;
end if;
示例:
CREATE DEFINER=`root`@`%` FUNCTION `myf`(score int(15)) RETURNS varchar(255) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci
begin
declare level VARCHAR(255);
IF(score>=90) THEN
SET LEVEL = '优秀';
ELSE
SET LEVEL = '一般';
end if;
return level;
end
2)case分支语句
语法格式:
case case_expr
when when_value then statement_list;
[when when_value then statement_list;]…
[else statement_list;]
end case;
或
case
when expr_condition then statement_list;
[when expr_condition then statement_list;]…
[else statement_list;]
end case;
示例:
CREATE DEFINER=`root`@`%` FUNCTION `myf3`(score int(15)) RETURNS varchar(255) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci
BEGIN
DECLARE LEVEL VARCHAR(255);
CASE
WHEN score>=90 AND score <=100 THEN SET LEVEL = '优秀';
WHEN score>=60 THEN SET LEVEL = '合格';
ELSE SET LEVEL = '不合格';
END CASE;
RETURN LEVEL;
END
3)while循环语句
语法格式:
[while_label:]while condition do
…
End while[while_libe];
4)loop循环语句
语法格式:
[loop_label:]loop
Statement_list;
End loop [loop_label];
leave语句用来跳出循环,语法格式:leave label;
5)repeat循环语句
该语句执行一次循环体,之后判断condition条件是否为真,为真则退出循环,否则继续执行循环体
语法格式:
[repeat_label:] repeat
…;
until expr_condition
end repeat [repeat_label:];
5、函数间调用
DELIMITER $$
CREATE FUNCTION user_main_fn2(v_id INT)
RETURNS VARCHAR(100)
BEGIN
#定义变量
DECLARE v_userNameNew VARCHAR(50);
#使用函数
SELECT user_main_fn(v_id) INTO v_userNameNew FROM DUAL;
#返回函数处理结果
RETURN CONCAT('***',v_userNameNew);
END $$
DELIMITER;
user_main_fn函数为已经存在的函数,之后在创建新的函数user_main_fn2时可以调用之前的函数
6、函数相关的操作
查看函数状态
查看函数的相关信息
show function status [like functionName];
查看函数定义
show create function functionName;
修改函数特性
实现对函数特性characteristic的修改,注意,不是对函数定义内容的修改
alter function functionName [characteristic ...]
删除自定义函数
DROP FUNCTION [ IF EXISTS ] <自定义函数名>
语法说明如下:
<自定义函数名>:指定要删除的自定义函数的名称。
IF EXISTS:指定关键字,用于防止因误删除不存在的自定义函数而引发错误
四、存储过程
事先经过编译并存储在数据库中的一段SQL语句的集合,调用存储过程可以减少在数据库和应用服务器之间的传输,很大程度上提高数据处理效率。
1、创建存储过程
create procedure 存储过程名称(in/out/inout 参数名 参数类型(长度))
begin
SQL语句;
end;
说明:
in:该类型参数作为输入,也就是需要调用时传入值
out:该类型参数作为输出,也就是该参数可以作为返回值
inout:既可以作为输入参数,也可以作为输出参数
参数类型长度:不指定长度时mysql会默认一个长度,如int会默认int(11)。
示例:
CREATE DEFINER=`root`@`%` PROCEDURE `NewProc`()
BEGIN
SELECT * FROM tb_projects;
END
2、调用存储过程
--调用的时候需要加上括号,因为可能存在参数
CALL NewProc();
3、查看存储过程
--查看指定数据库的存储过程及状态信息
select * from information_schema.routines where routine_schema = 'django_test';
--或
select * from mysql.proc where db='django_test';
--查询存储过程的状态信息
SHOW PROCEDURE STATUS;
--查看某个存储过程的定义sql语句
show create procedure NewProc;
4、删除
drop procedure [if exists] 存储过程名字;
5、语法结构
1)变量的声明以及赋值
-- 注意:声明变量的时候可以一次性声明多个,使用逗号隔开
DECLARE 变量名[,...] type [DEFAULT value]
delimiter $
create procedure proc_student()
begin
--变量的声明
declare num int default 5;
--SET赋值
--SET 变量名 = 变量值 [,变量名 = 变量值] ...
set name = 'MySQL';
declare count_num int(10);
-- select...into 赋值
select count(*) into count_num from student;
select count_num;
end $
delimiter ;
2)循环和条件
if
语法:
# 只有满足差选条件才会执行 then 后面的SQL语句
if search_condition(查询条件) then statement_list(SQL语句)
[else if search_condition(查询条件) then statement_list(SQL语句)]...
[else statement_list(SQL语句)]
end if;
示例:
CREATE DEFINER=`root`@`%` PROCEDURE `NewProc`(IN score INT(11))
BEGIN
#Routine body goes here...
DECLARE result VARCHAR(50);
-- SET result = 'A';
if score>=90 THEN SET result = '优秀';
elseif score>=60 THEN SET result = '合格';
else SET result = '不及格';
end if;
SELECT result;
END
case
语法:
# 方式一
case case_value(判断的值)
when when_value(比较的值) then statement_list(SQL语句)
[when when_value(比较的值) then statement_list(SQL语句)]...
[else statement_list(SQL语句)]
end case;
# 方式二
case
when search_condition(查询条件) then statement_list(SQL语句)
[when search_condition(查询条件) then statement_list(SQL语句)]...
[else statement_list(SQL语句)]
end case;
示例:
delimiter $
create procedure pro_quarter(in mon int(11))
begin
# 定义存储季度的变量
declare result varchar(10);
case
when mon >= 1 and mon <= 3 then
set result = '第一季度';
when mon >= 4 and mon <= 6 then
set result = '第一季度';
when mon >= 7 and mon <= 9 then
set result = '第一季度';
else
set result = '第四季度';
end case;
# 输出结果
select result;
end $
delimiter ;
while循环
语法:
# 只要查询条件一直成立就会一直指定do后面的SQL语句,当查询条件不成立的时候直接跳出while循环
while search_condition(查询条件) do
statement_list(SQL语句)
end while;
示例:
delimiter $
create procedure pro_sum(in num int(11))
begin
# 定义存储总数的变量
declare total int(255) default 0;
# 定义存储循环次数的数量
declare number int(255) default 1;
while number <= num do
set total = total + number;
set number = number + 1;
end while;
select total;
end $
delimiter ;
repeat循环
语法:
repeat
statement_list(SQL语句)
until search_condition(查询添加)
end repeat;
示例:
delimiter $
create procedure pro_sum(in num int(11))
begin
# 定义存储总数的变量
declare total int(255) default 0;
repeat
set total = total + number;
set num = num - 1;
# 注意:这个 unti 后的查询条件不要加分号,加分号会报错。
until num = 0
end repeat;
select total;
end $
delimiter ;
loop循环
[begin_label:] loop
statement_list
end loop [end_label]
leave语句
delimiter $
create procedure pro_sum(in num int(11))
begin
# 定义存储总数的变量
declare total int(255) default 0;
c(该循环的别名):loop
set total = total + num;
set num = num - 1;
# 借助leave组织退出条件
if num <= 0 then
leave c;
end if;
end loop c;
select total;
end $
delimiter ;
3)传递参数
delimiter $
# 我们可以不指定 [in/out/inout] , 默认为 in,输入参数
create procedure pro_name([in/out/inout]参数名 参数类型)
begin
-- sql语句
end $
delimiter ;
IN - 输入参数
CREATE DEFINER=`root`@`%` PROCEDURE `NewProc`(IN id_s INT(11))
BEGIN
#Routine body goes here...
DECLARE `o_name` VARCHAR(50);
SELECT leader INTO o_name FROM tb_projects WHERE id =id_s;
SELECT o_name;
END
out - 输出参数
CREATE DEFINER=`root`@`%` PROCEDURE `NewProc`(IN score INT(11) ,OUT result VARCHAR(50))
BEGIN
if score>=90 THEN SET result = '优秀';
elseif score>=60 THEN SET result = '合格';
else SET result = '不及格';
end if;
END
调用
# @标识符:在MySQL中代表的就是用户定义的一个变量,这里我们使用这个变量来接收这个存储过程的返回值
CALL NewProc(1,@result);
# 查看存储过程返回的结果
select @result;
@标识符的作用
@figure :这种在变量名前面加上”@“符号,叫做用户会话变量,代表整个会话过程他都是有作用的,这个类似于全局变量一样。当前会话就是代表的,比如我们在命令提示窗口中给好多带有 @ 符号变量进行赋值,此时这些变量的值只作用于当前的会话,当我们把这个窗口关闭的时候,此时这些变量的值就会释放掉。
@@global : 这种在变量名前加上 “@@” 符号,叫做系统变量
最后
自定义函数与存储过程之间存在几点区别:
自定义函数不能拥有输出参数,这是因为自定义函数自身就是输出参数;而存储过程可以拥有输出参数。
自定义函数中必须包含一条 RETURN 语句,而这条特殊的 SQL 语句不允许包含于存储过程中。
可以直接对自定义函数进行调用而不需要使用 CALL 语句,而对存储过程的调用需要使用 CALL 语句。
五、游标
在 MySQL 中,存储过程或函数中的查询有时会返回多条记录,而使用简单的 SELECT 语句,没有办法得到第一行、下一行或前十行的数据,这时可以使用游标来逐条读取查询结果集中的记录。
其实游标也可以理解编程语言中的下标,用来标识数据取到了什么地方。
游标只局限于存储过程中,存储过程处理完成后,游标就消失了
1、声明游标
使用DECLARE关键字声明游标,并定义相应的 SELECT 语句,根据需要添加 WHERE 和其它子句。
DECLARE cursor_name CURSOR FOR select_statement;
说明:
- cursor_name 表示游标的名称;
- select_statement 表示 SELECT 语句,可以返回一行或多行数据。
示例:
CREATE DEFINER=`root`@`%` PROCEDURE `NewProc2`()
BEGIN
DECLARE name_cursor CURSOR
FOR
SELECT NAME FROM tb_projects;
END
2、打开游标
声明游标之后,如果想从游标中提取数据,必须要打开游标,语法如下:
OPEN cursor_name;
说明:
- cursor_name 表示游标的名称;
需要注意的是,打开一个游标时,游标并不指向第一条记录,而是指向第一条记录的前边(按下标处理,第一条记录的下标是0)。
在程序中,一个游标可以打开多次。用户打开游标后,其他用户或程序可能正在更新数据表,所以有时会导致用户每次打开游标后,显示的结果都不同。
3、使用游标
游标顺利打开后,可以使用 FETCH…INTO 语句来读取数据
FETCH cursor_name INTO var_name [,var_name]...
将游标cursor_name中的select执行结果保存到变量var_name(需提前定义)中;
MySQL 的游标是只读的,也就是说,你只能顺序地从开始往后读取结果集,不能从后往前,也不能直接跳到中间的记录
4、关闭游标
游标使用完毕后,要及时关闭。
CLOSE cursor_name;
CLOSE 释放游标使用的所有内部内存和资源,因此每个游标不再需要时都应该关闭
在一个游标关闭后,如果没有重新打开,则不能使用它。但是,使用声明过的游标不需要再次声明,用 OPEN 语句打开它就可以了。
5、游标实例
游标的使用, 把tb_projects表数据复制到另一个表tb_user_pro中
CREATE DEFINER=`root`@`%` PROCEDURE `NewProc2`()
BEGIN
DECLARE befoe_name VARCHAR(20);
DECLARE befoe_leader VARCHAR(20);
DECLARE cur_test CURSOR FOR SELECT name,leader FROM tb_projects;
--条件处理程序,当下面while循环时游标的数据为空时就不会报错了。
declare exit handler for NOT FOUND close cur_test;
DROP TABLE IF EXISTS `tb_projects_pro`;
CREATE table tb_projects_pro(
id int(11) PRIMARY KEY auto_increment,
a_name varchar(10),
a_leader varchar(100)
);
OPEN cur_test;
WHILE TRUE DO
FETCH cur_test INTO befoe_name,befoe_leader;
INSERT INTO tb_projects_pro VALUES(NULL,befoe_name,befoe_leader);
END WHILE;
CLOSE cur_test;
END
六、视图
视图(View)是一个虚拟存在的表,可以理解为一个逻辑表,本身不包含数据,作为一个select语句保存在数据字典中。
1、创建视图
CREATE VIEW <视图名> [ (视图字段列表) ] AS <SELECT语句>
说明:
- <视图名>:指定视图的名称。该名称在数据库中必须是唯一的,不能与其他表或视图同名。
- [ (视图字段列表) ]:可以指定视图字段。
- <SELECT语句>:指定创建视图的 SELECT 语句,可用于查询多个基础表或源视图。
对于创建视图中的 SELECT 语句的指定存在以下限制:
a.用户除了拥有 CREATE VIEW 权限外,还具有操作中涉及的基础表和其他视图的相关权限。
b.SELECT 语句不能引用系统或用户变量。
c.SELECT 语句不能包含 FROM 子句中的子查询。
d.SELECT 语句不能引用预处理语句参数。
创建基于单表的视图
--创建视图
CREATE VIEW v_project(s_id,s_name,d_leader,s_tester,s_programmer,s_publish_app,s_desc,s_create_time,s_update_time)
AS SELECT id,name,leader,tester,programmer,publish_app,`desc`,create_time,update_time
FROM tb_projects;
--查看视图数据
SELECT * FROM v_project
新创建的视图v_project,与原tb_projects表的数据相同,因此用户在使用视图的时候不用考虑表的结构,也接触不到表的数据,从而保证了数据的安全。
创建基于多表的视图
--创建视图
CREATE VIEW v_project_inter(p_id,p_name,p_leader,i_name,i_desc)
AS SELECT p.id,p.name,p.leader,i.name,i.desc
FROM tb_projects p
JOIN tb_interfaces i on p.id=i.project_id;
--查看视图内容
SELECT * FROM v_project_inter;
通过这个视图可以很好地保护基本表中的数据。
2、查看视图
查询视图列表
-- 查询所有的表和视图
show tables;
-- 查询所有视图
show table status where comment ='view';
查询视图定义
通过 DESCRIBE 语句查看视图的定义
DESCRIBE 视图名;
查询视图数据
视图一经定义之后,就可以如同查询数据表一样,使用 SELECT 语句查询视图中的数据,语法和查询基础表的数据一样。
SELECT * FROM 视图名;
3、修改视图
修改视图是指修改 MySQL 数据库中存在的视图,当基本表的某些字段发生变化时,可以通过修改视图来保持与基本表的一致性。
ALTER VIEW <视图名> AS <SELECT语句>
修改视图内容
视图中的数据实际来源于基本表,所以通过插入、修改和删除操作更新视图中的数据,实质上是在更新视图所引用的基本表的数据。
注意:对视图的修改就是对基本表的修改,因此在修改时,要满足基本表的数据定义。
某些视图是可更新的。也就是说,可以使用 UPDATE、DELETE 或 INSERT 等语句更新基本表的内容。对于可更新的视图,视图中的行和基本表的行之间必须具有一对一的关系.
还有一些特定的其他结构,这些结构会使得视图不可更新。更具体地讲,如果视图包含以下结构中的任何一种,它就是不可更新的:
- 聚合函数 SUM()、MIN()、MAX()、COUNT() 等。
- DISTINCT 关键字。
- HAVING 子句。
- UNION 或 UNION ALL 运算符。
- 位于选择列表中的子查询。
- FROM 子句中的不可更新视图或包含多个表。
- WHERE 子句中的子查询,引用 FROM 子句中的表。
- ALGORITHM 选项为 TEMPTABLE(使用临时表总会使视图成为不可更新的)的时候。
4、通过视图更新基本表数据
INSERT语句通过视图添加数据
insert [into] 视图名 [(字段名1, 字段名2, …)] values | value (值1, 值2, …);
DELETE语句通过视图删除数据
delete from 视图名 [where 条件语句]
UPDATE语句通过视图更新数据
update 视图名 set 字段名=值 [where 更新条件]
5、删除视图
DROP VIEW <视图名1> [ , <视图名2> …]
视图用于查询主要应用在以下几个方面:
使用视图重新格式化检索出的数据。
使用视图简化复杂的表连接。
使用视图过滤数据。
七、事务
只简单介绍下事务,基本定义和特性。
1、定义
事务:事务是一个最小的不可在分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务是一个最小的工作单元),多个操作同时进行,那么同时成功,那么同时失败。这就是事务。
一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成(事务只和DML语句有关,或者说DML语句才有事务)。
2、特性
1)原子性:事务是一个不可分割的工作单位,要么同时成功,要么同时失败。例:当两个人发起转账业务时,如果A转账发起,而B因为一些原因不能成功接受,事务最终将不会提交,则A和B的请求最终不会成功。
- 当最终的因为操作不成功而发生事务回滚时,会从undo log日志里面先前存好的数据,重新对数据库的数据进行数据的回退。
2)持久性:一旦事务提交,他对数据库的改变就是永久的。注:只要提交了事务,将会对数据库的数据进行永久性刷新。
- redo log日志,对于用户将对发生了修改而为提交的数据存入了redo log日志中,当此时发生断电等其他异常时,可以根据redo log日志重新对数据做一个提交,做一个恢复。
3)隔离性:多个事务之间相互隔离的,互不干扰
4)一致性:事务执行接收之后,数据库完整性不被破坏
一致性、持久性、原子性、隔离性