第1章 数据库和SQL 13
1-1 数据库是什么 15
1、我们身边的数据库 15
- 像这样将大量数据保存起来,通过计算机加工而成的可以进行高效访问的数据集合称为数据库(Database,DB)。
- 用来管理数据库的计算机系统称为数据库管理系统(Database Management System,DBMS)
2、为什么DBMS那么重要 16
文本文件或者电子制表软件来管理数据的方法非常简便,但也有不足:
- 无法多人共享数据
- 无法提供操作大量数据所需的格式
- 实现读写自动化需要编程能力(需要了解数据结构,以及一定的编程技术)
- 无法应对突发事故 (造成数据丢失等)
DBMS 可以克服这些不足,实现多个用户同时安全简单地操作大量数据
3、DBMS的种类 18
DBMS 主要通过数据的保存格式(数据库的种类)来进行分类。目前主要有5种:
- 层次数据库(Hierarchical Database,HDB):它把数据通过层次结构(树形结构)的方式表现出来,曾经是主流数据库,
现在已经很少使用。
- 关系数据库(Relational Database,RDB):采用由行和列组成的二维表来管理数据,同时,它还使用专门的 SQL(Structured
Query Language,结构化查询语言)对数据进行操作。是目前应用最广泛的数据库。
这种类型的 DBMS 称为关系数据库管理系统(Relational DatabaseManagement System,RDBMS)。
比较具有代表性的 RDBMS 有如下 5 种。
● Oracle Database:甲骨文公司的RDBMS
● SQL Server:微软公司的RDBMS
● DB2:IBM公司的RDBMS
● PostgreSQL:开源的RDBMS
● MySQL:开源的RDBMS
- 面向对象数据库(Object Oriented Database,OODB):把数据以及对数据的操作集合起来以对象为单位进行管理
- XML数据库(XML Database,XMLDB):XML 数据库可以对 XML 形式的大量数据进行高速处理。
- 键值存储系统(Key-Value Store,KVS):这是一种单纯用来保存查询所使用的主键(Key)和值(Value)的组合的数据库。
具有编程语言知识的读者可以把它想象成关联数组或者散列(hash)。
1-2 数据库的结构 20
一、RDBMS的常见系统结构 20
使用 RDBMS 时,最常见的系统结构就是客户端 / 服务器类型(C/S类型):
- 服务器:服务器指的是用来接收其他程序发出的请求,并对该请求进行相应处
理的程序(软件),或者是安装了此类程序的设备(计算机)。类似受托方。
- 客户端:向服务器发出请求的程序(软件),或者是安装了该程序
的设备(计算机)称为客户端。类似委托方。
二、表的结构 22
用来管理数据的二维表在关系数据库中简称为表。
根据 SQL 语句的内容返回的数据同样必须是二维表的形式,否则无法执行SQL语句
列(字段):列的约束非常严格,只能输入列定义的类型
行(记录): 关系数据库必须以行 为单位进行数据读写
单元格:只能输入一个数据
1-3 SQL概要 25
一、标准SQL 25
SQL 是用来操作关系数据库的语言
国际标准化组织(ISO)所制定的SQL 标准称为标准SQL .
二、SQL语句及其种类 26
SQL 用关键字、表名、列名等组合而成的一条语句(SQL 语句)来描述操作的内容
SQL根据功能不同可以分为三类,其中使用最多的是DML:
1、DDL(Data Definition Language,数据定义语言) 用来创建或者删除存储
数据用的数据库以及数据库中的表等对象。
CREATE : 创建数据库和表等对象
DROP : 删除数据库和表等对象
ALTER : 修改数据库和表等对象的结构
2、DML(Data Manipulation Language,数据操纵语言) 用来查询或者变更
表中的记录。
SELECT :查询表中的数据
INSERT :向表中插入新数据
UPDATE :更新表中的数据
DELETE :删除表中的数据
3、DCL(Data Control Language,数据控制语言) 用来确认或者取消对数据
库中的数据进行的变更。还可以修改用户权限
COMMIT : 确认对数据库中的数据进行的变更
ROLLBACK : 取消对数据库中的数据进行的变更
GRANT : 赋予用户操作权限
REVOKE : 取消用户的操作权限
三、SQL的基本书写规则 27
- SQL语句要以分号( ; )结尾
- SQL 不区分关键字的大小写 。
- 常数(字符串,日期或者数字)的书写方式是固定的:字符串、日期:' '
- 单词需要用半角空格或者换行来分隔
1-4 表的创建 30
一、表的内容的创建 30
二、数据库的创建( CREATE DATABASE 语句) 31
- 创建数据库的 CREATE DATABASE 语句:
create database < 数据库名称 > ;
三、表的创建( CREATE TABLE 语句) 31
- 创建表的 CREATE TABLE 语句
create table< 表名 >
( < 列名 1> < 数据类型 > < 该列所需约束 >,
< 该表的约束 1> , < 该表的约束 2> ,……);
四、命名规则 33
- 我们只能使用半角英文字母、数字、下划线(_)作为数据库、表和列的名称 。
- 名称必须以半角英文字母开头
- 名称不能重复。
注:这只是标准sql的规则,不同的RDBMS规则可能有些不一样。
五、数据类型的指定 34
- 所有的列都必须指定数据类型,数据类型表示数据的种类,包括数字型、字符型和日期型等
- INTEGER 型:
用来指定存储整数的列的数据类型(数字型),不能存储小数
- CHAR 型:
字符型,其中为定长字符串,会用半角空格自动填充长度。,
- VARCHAR 型:
字符串型,其中为可变长字符串,不会自动填充长度
- DATE 型
用来指定存储日期(年月日)的列的数据类型(日期型)。
MySQL的数据类型:[https://blog.csdn.net/sanwe3333/article/details/105024247/](https://blog.csdn.net/sanwe3333/article/details/105024247/)
主要包括以下五大类:
整数类型:BIT、BOOL、TINY INT、SMALL INT、MEDIUM INT、 INT、 BIG INT
浮点数类型:FLOAT、DOUBLE、DECIMAL
字符串类型:CHAR、VARCHAR、TINY TEXT、TEXT、MEDIUM TEXT、LONGTEXT、TINY BLOB、BLOB、MEDIUM BLOB、LONG BLOB
日期类型:Date、DateTime、TimeStamp、Time、Year
其他数据类型:BINARY、VARBINARY、ENUM、SET、Geometry、Point、MultiPoint、LineString、MultiLineString、Polygon、GeometryCollection等
六、约束的设置 35
约束是对列中存储的数据进行限制或者追加条件的功能
product_id CHAR(4) NOT NULL:非空约束
PRIMARY KEY (product_id) :主键约束
所谓键,就是在指定特定数据时使用的列的组合。键种类多样,主键(primary key)就是可
以特定一行数据的列且不能为空。
1-5 表的删除和更新 37
一、表的删除( DROP TABLE 语句) 37
- 删除表时使用的 DROP TABLE 语句
DROP TABLE < 表名 > ;
二、表定义的更新( ALTER TABLE 语句) 38
- 添加列的 ALTER TABLE 语句
ALTER TABLE < 表名 > ADD COLUMN < 列的定义 > ;
- 删除列的 ALTER TABLE 语句
ALTER TABLE < 表名 > DROP COLUMN < 列名 > ;
- 变更表名:
RENAME TABLE Poduct to Product;
三、向 Product 表中插入数据 39
sql基础教程——demo1
第2章 查询基础 43
2-1 SELECT 语句基础 45
一、列的查询 45
SELECT < 列名 > ,…… FROM < 表名 >
子句:组成SQL语句的组成要素,如上两个子句(select,from)
二、查询出表中所有的列 47
SELECT * FROM < 表名 >;
三、为列设定别名 48
使用AS 或者 空格 ,中文别名用 " " 包裹起来
四、常数的查询 50
SELECT 子句中不仅可以书写列名,还可以书写常数。
:SELECT "商品编号" from product; //查询数字 日期都行
五、从结果中删除重复行 50
使用 distinct;
//删除此列中的重复数据 select distinct product_type from product;
如果重复列的值为null ,那么全部null都会合为一条Null。
- 将多个列的数据进行组合,将重复的数据合并为一条:
SELECT DISTINCT <列名1>, <列名2>FROM <表名>;
- 规则:DISTINCT关键字只能用在第一个列名之前
六、根据 WHERE 语句来选择记录 53
SELECT < 列名 >, ……FROM < 表名 >WHERE < 条件表达式 >;
where 子句用来指定查询数据的条件,从查询中选取符合条件表达式的行所对应的列
首先通过WHERE 子句查询出符合指定条件的记录,然后再选取出 SELECT 语句指定的列
SQL 中子句的书写顺序是固定的,不能随意更改 WHERE 子句必须紧跟在 FROM 子句之后,
七、注释的书写方法 55
单行注释: -- MySQL中需要在“ -- ”之后加入半角空格(如果不加的话就不会被认为是注释)。
多行注释 : /* */
2-2 算术运算符和比较运算符 57
运算符就是使用其两边的值进行四则运算或者字符串拼接、数值大小比较等运算,并返回结果的符号。
一、算术运算符 57
可以对列进行四则运算,括号内的运算表达式优先被计算。sql语句同理
select sale_price,(sale_price*2) as 'sale_price*2' from product ;
二、需要注意 NULL 58
所有包含 NULL 的四则计算,结果肯定是 NULL
5/null 结果还是null
在select语句中,可以省略from 子句 。这样会得到一行临时数据
三、比较运算符 60
像符号 = 这样用来比较其两边的列或者值的符号称为比较运算符,
符号<> :不相等的意思 ,在mysql中也可以使用 != 达到一样的效果(属于特定sql)
在使用大于等于( >= )或者小于等于( <= )作为查询条件时,一定要注意不等号( < 、 > )和等号( = )的位置不能颠倒。
一定要让不等号在左,等号在右。
四、对字符串使用不等号时的注意事项 62
字符串类型的数据原则上按照字典顺序进行排序,不能与数字的大小顺序混淆。
像姓名那样,按照条目在字典中出现的顺序来进行排序。(比如10比11小,2比222小,222比3小)
该规则最重要的一点就是,以相同字符开头的单词比不同字符开头的单词更相近。
五、不能对 NULL 使用比较运算符 65
如果想判断是否为null,无法使用=null /<>null ,需要使用is null / is not null
2-3 逻辑运算符 68
一、NOT 运算符 68
用来翻转某一条件
NOT sale_price >= 1000 等于sale_price <1000
二、AND 运算符和 OR 运算符 70
WHERE 子句中使用 AND 运算符或者 OR 运算符,可以对多个查询条件进行组合。
AND 运算符在其两侧的查询条件都成立时整个查询条件才成立,其意思相当于“并且”。
:SELECT * from product WHERE product_type =' 厨房用具 ' and sale_price<900;
OR 运算符在其两侧的查询条件有一个成立时整个查询条件都成立,其意思相当于“或者”
SELECT * from product WHERE regist_date =' 2009-09-20 ' or regist_date =' 2009-09-22'
三、通过括号强化处理 72
SELECT product_name, product_type, regist_date FROM Product WHERE product_type = ' 办公用品 ' AND regist_date = '2009-09-11' OR regist_date = '2009-09-20' ;
这里是想查询 '打孔器'这一列(唯一满足是办公用品且时间为2者之一的物品) ,但是由于 AND 运算符优先于 OR 运算符 导致查询出了所有的9-11日的办公用品。
这时候可以用括号优先运行or运算符
WHERE product_type = ' 办公用品 ' AND ( regist_date = '2009-09-11' OR regist_date = '2009-09-20' ) ;
四、逻辑运算符和真值 74
比较运算符会返回真假值,逻辑运算符对真值进行操作。and两侧都为真返回真,or只要其中一条不为假就返回真。
AND 运算的结果与乘法运算(积),(即 假*任何数都为假)。
OR 运算的结果与加法运算(和)的结果却是一样的(其中一个为真便合为真)。
因此,使用 AND运算符进行的逻辑运算称为逻辑积,使用 OR 运算符进行的逻辑运算称为逻辑和。
五、含有 NULL 时的真值 76
sql中的逻辑运算被称为三值逻辑,即包含true,false ,不确定(UNKNOWN)三种值。
但是使用 不确定 会让条件判断更麻烦,所以一般会设置 not null的约束
练习题 78
第3章 聚合与排序 79
3-1 对表进行聚合查询 81
一、聚合函数 81
通过 SQL 对数据进行某种操作或计算时需要使用函数
COUNT : 计算表中的记录数(行数)
SUM : 计算表中数值列中数据的合计值
AVG : 计算表中数值列中数据的平均值
MAX : 求出表中任意列中数据的最大值
MIN : 求出表中任意列中数据的最小值
如上所示,用于汇总的函数称为聚合函数或者聚集函数,本书中统称
为聚合函数。所谓聚合,就是将多行汇总为一行。
二、计算表中数据的行数 82
SELECT COUNT(*)FROM Product;//查询全部行数
三、计算 NULL 之外的数据的行数 83
SELECT COUNT(*) FROM product; SELECT COUNT(purchase_price)FROM Product;
COUNT 函数的结果根据参数的不同而不同。 COUNT (*) 会得到包含 NULL 的数据
行数,而 COUNT (< 列名 >) 会得到 NULL 之外的数据行数。
四、计算合计值 84
SELECT sum(sale_price) from product;
聚合函数会将 NULL 排除在外。但 COUNT (*)例外,并不会排除 NULL
五、计算平均值 86
SELECT avg(sale_price),avg(purchase_price) FROM product;
这里注意:因为会排除Null,所以分母也会相应的减少。如果想将null也计算进去。这里暂时的解决方法是:
sum/avg 只适用于数值类型
六、计算最大值和最小值 87
SELECT MAX(regist_date),MIN(product_type) from product;
max,min与sum/avg 不同,不仅可以比较数值,还可以对日期和字符串类型操作。
七、使用聚合函数删除重复值(关键字 DISTINCT ) 89
SELECT sum(distinct sale_price),sum(sale_price) from product;
在聚合函数的参数中使用 DISTINCT ,可以删除重复数据。
3-2 对表进行分组 91
一、GROUP BY 子句 91
SELECT product_type,count(*) from product GROUP BY product_type;
使用 GROUP BY 子句进行汇总 SELECT < 列名 1>, < 列名 2>, < 列名 3>, …… FROM < 表名 > GROUP BY < 列名 1>, < 列名 2>, < 列名 3>, ……
不使用 GROUP BY 子句时,是将表中的所有数据作为一组来对待的
。而使用 GROUP BY 子句时,会将表中的数据分为多个组进行处理
在 GROUPBY 子句中指定的列称为聚合键或者分组列。
▲子句的书写顺序(暂定)
1\. SELECT → 2\. FROM → 3\. WHERE → 4\. GROUP BY
二、聚合键中包含 NULL 的情况 93
SELECT purchase_price, COUNT(*) FROM Product GROUP BY purchase_price; //会将Null也单独计算成一组。
三、使用 WHERE 子句时 GROUP BY 的执行结果 94
使用 WHERE 子句和 GROUP BY 子句进行汇总处理 SELECT < 列名 1>, < 列名 2>, < 列名 3>, …… FROM < 表名 > WHERE GROUP BY < 列名 1>, < 列名 2>, < 列名 3>, …… ;
GROUP BY 和 WHERE 并用时, SELECT 语句的执行顺序如下所示。
▲GROUP BY 和 WHERE 并用时 SELECT 语句的执行顺序(和书写顺序不同)
FROM(表名) → WHERE(限制条件) → GROUP BY (分组)→ SELECT(查询)
、
四、与聚合函数和 GROUP BY 子句有关的常见错误 96、
① ——在 SELECT 子句中书写了多余的列
- 把聚合键之外的列名书写在 SELECT 子句之中
SELECT product_name, purchase_price, COUNT(*) //product_name,不是聚合建列。 FROM Product GROUP BY purchase_price;
不过,只有MySQL认同这种语法,所以能够执行,不会发生错误
(在多列候补中只要有一列满足要求就可以了)。
但是MySQL以外的DBMS都不支持这样的语法,
因此请不要使用这样的写法。
② ——在 GROUP BY 子句中写了列的别名
- 由于执行顺序的原因,GROUP BY 在select前执行,因此无法知道定义的别名
(在mysql,PGSQL中可以执行。)
③ —— GROUP BY 子句的结果能排序吗
- GROUP BY 子句结果的显示是无序的。
④ ——在 WHERE 子句中使用聚合函数
- where的限制条件是针对行的,不是组
- 只有 SELECT 子句和 HAVING 子句(以及 ORDER BY 子句)中能够使用聚合函数
注:DISTINCT 和 GROUP BY 都有删除重复数据的功能(都会将重复Null独立为一列)。执行速度也差不多
3-3 为聚合结果指定条件 101
一、HAVING 子句 101
作用:对分组指定条件。可以使用聚合函数
SELECT < 列名 1>, < 列名 2>, < 列名 3>, …… FROM < 表名 > GROUP BY < 列名 1>, < 列名 2>, < 列名 3>, …… HAVING < 分组结果对应的条件 >
having 子句必须group by子句后面,这时的书写顺序为:
▲SELECT → FROM → WHERE → GROUP BY → HAVING
SELECT product_type,count(*) from product GROUP BY product_type HAVING count(*)=2;
二、HAVING 子句的构成要素 104
- 目前只能包含常数,聚合函数,GROUP BY子句中指定的列名(即聚合键)
- HAVING可以理解为GROUP BY分组之后,对于组的SELECT语句(所以自然就无法使用非聚合键的列)
三、相对于 HAVING 子句,更适合写在 WHERE 子句中的条件 105
这2个子句都可以使用的一个共同条件:聚合键
WHERE 子句 = 指定行所对应的条件(更适合使用聚合键,且速度比HAVING 快)
HAVING 子句 = 指定组所对应的条件
3-4 对查询结果进行排序 108
一、ORDER BY 子句 108
SELECT < 列名 1>, < 列名 2>, < 列名 3>, …… FROM < 表名 > ORDER BY < 排序基准列 1>, < 排序基准列 2>, ……
ORDER BY子句中书写的列名称为排序键。
▲子句的书写顺序
1\. SELECT 子句 → 2\. FROM 子句 → 3\. WHERE 子句 → 4\. GROUP BY 子句 →
5\. HAVING 子句 → 6\. ORDER BY 子句
二、指定升序或降序 110
使用 DESC 关键字进行降序 ASC进行升序。默认升序
ORDER BY < 排序基准列 1> desc/asc
三、指定多个排序键 111
- 有多个排序基准列时,规则是优先使用左侧的键,如果该列存在相同值的话,再接着参考右侧的值
四、NULL 的顺序 111
null根据DBMS不同,会汇集在开头或者末尾,mysql规则是在开头
五、在排序键中使用显示用的别名 112
排序键中使用别名是可行的,原因在于内部执行顺序:
FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY
六、ORDER BY 子句中可以使用的列 114
- 在 ORDER BY 子句中可以使用 SELECT 子句中未使用的列和聚合函数
七、不要使用列编号 114
列编号是指 SELECT 子句中的列按照从左到
右的顺序进行排列时所对应的编号(1, 2, 3, …)。不建议使用
练习题 116
第4章 数据更新 117
4-1 数据的插入( INSERT 语句的使用方法) 119
一、什么是 INSERT 119
二、INSERT 语句的基本语法 120
INSERT INTO < 表名 > ( 列 1 , 列 2 , 列 3 , …… ) VALUES ( 值 1 , 值 2 , 值 3 , …… );
将列名和值用逗号隔开,分别括在 () 内,这种形式称为清单 (分为列清单,值清单。二者的值必须相对应)。
多行插入:
INSERT INTO < 表名 > ( 列 1 , 列 2 , 列 3 , …… ) VALUES ( 值 1 , 值 2 , 值 3 , …… ),( 值 1 , 值 2 , 值 3 , …… );
三、列清单的省略 123
-- 省略列清单 INSERT INTO ProductIns VALUES ('0005', ' 高压锅 ', ' 厨房用具 ', 6800, 5000, '2009-01-15');
一般不这么写,因为这样插入的顺序是固定的
四、插入 NULL 123
- 可以插入Null
五、插入默认值 124
通过default约束,向表中插入默认值。
CREATE TABLE ProductIns (sale_price INTEGER default 0, -- 销售单价的默认值设定为 0; 。。。。。。 )
设置约束后,可以通过2种方式插入默认值:
■通过显式方法插入默认值:
在 VALUES 子句中指定 DEFAULT 关键字
VALUES ('0007', ' 擦菜板 ', ' 厨房用具 ', DEFAULT, 790, '2009-04-28');/用关键字代替值
■通过隐式方法插入默认值
直接不写该列名和数据(包括default)
六、从其他表中复制数据 126
INSERT into ProductCopy(新表) SELECT * from product(源表)); //注意2表的字段要一一对应
还可以在select中使用 WHERE 子句或者 GROUP BY 子句等任何SQL语法 (但使用 ORDER BY 子句并不会产生任何效果)。:
例如下面这个继承分组:
-- 根据商品种类进行汇总的表; CREATE TABLE ProductType (product_type VARCHAR(32) NOT NULL, sum_sale_price INTEGER , sum_purchase_price INTEGER , PRIMARY KEY (product_type));
insert into ProductType SELECT product_type,sum(sale_price),SUM(purchase_price) from product GROUP BY product_type;
效果图:
4-2 数据的删除( DELETE 语句的使用方法) 129
一、DROP TABLE 语句和 DELETE 语句 129
- ① DROP TABLE < 表名 > 语句可以将表完全删除
- ② DELETE FROM < 表名 >:会留下表(容器),而删除表中的全部数据 (行)
二、DELETE 语句的基本语法 129
三、指定删除对象的 DELETE 语句(搜索型 DELETE ) 130
- 删除部分数据行的搜索型 DELETE
DELETE FROM < 表名 >WHERE < 条件 >;
- truncate < 表名 >:删除全部数据,执行速度比delete快。属于特定sql
4-3 数据的更新( UPDATE 语句的使用方法) 133
一、UPDATE 语句的基本语法 133
- 改变表中数据的 UPDATE 语句
UPDATE < 表名 >SET < 列名 > = < 表达式 >;
二、指定条件的 UPDATE 语句(搜索型 UPDATE ) 134
- 更新部分数据行的搜索型 UPDATE
UPDATE < 表名 >SET < 列名 > = < 表达式 > WHERE < 条件 >;//条件一般都是主键
三、使用 NULL 进行更新 135
- 使用 UPDATE 语句可以将值清空为 NULL (但只限于未设置 NOT NULL 约束的列)。
四、多列更新 136
//使用逗号进行分隔 update productins set sale_price =sale_price*10, purchase_price = purchase_price*10 WHERE product_name='T 恤衫 '; //将列用 () 括起来的清单形式:mysql中无法使用 UPDATE Product SET (sale_price, purchase_price) = (sale_price * 10, purchase_price / 2) WHERE product_type = ' 厨房用具 ';
4-4 事务 138
一、什么是事务 138
- 事务就是 需要在同一个处理单元中执行的一系列更新处理的集合
- 事务并没有标准的开始指令存在,而是根据 DBMS 的不同而不同
二、创建事务 139
事务开始语句 ; DML 语句① ; DML 语句② ; DML 语句③ ; 事务结束语句( COMMIT 或者 ROLLBACK ).
- 事务开始语句:
BEGIN TRANSACTION
START TRANSACTION :mysql特有
- 事务结束语句:
COMMIT :提交事务包含的全部更新处理的结束指令。一旦提交。将无法恢复到事务开始前的状态
ROLLBACK:是取消事务包含的全部更新处理的结束指令,一旦回滚。数据库将会恢复到事务开始前的状态
START TRANSACTION; -- 将运动 T 恤的销售单价降低 1000 日元 UPDATE Product SET sale_price = sale_price - 1000 WHERE product_name = ' 运动 T 恤 '; -- 将 T 恤衫的销售单价上浮 1000 日元 UPDATE Product SET sale_price = sale_price + 1000 WHERE product_name = 'T 恤衫 '; commit/rollback;
注:事务有2种模式:
1、手动提交事务:直到回滚或者提交为止算一个事务。
2、自动提交事务:每一条sql语句就是一个事务。
mysql 默认采用2。即每一条语句都括在隐式的事务开始语句,结束语句间
但是如果使用自动提交 进行delete。删除后将无法恢复。无法进行回滚
三、ACID特性 144
DBMS 的事务都遵循四种特性,将这四种特性的首字母结合起来统称为 ACID 特性。
1、原子性(Atomicity):事务的全部操作是一个整体,要么全部执行,要么全部不执行。
2、一致性(Consistency):事务开启后,数据表中的数据状态没有变化,因为还没有提交;
(也就是说事务中包含的处理要满足数据库提前设置的约束,不合法的sql会被回滚)。
3、隔离性(Isolation):多个事务间相互隔离,互不干扰
4、持久性(Durability):事务一旦提交(无论回滚,成功)数据都会发生永久改变。