什么是事务
估计有些读者对事务(transaction)这个词并不熟悉,它通常被用于 商务贸易或者经济活动中,但是在 RDBMS 中,事务是对表中数据进行更 新的单位。简单来讲,事务就是需要在同一个处理单元中执行的一系列更 新处理的集合。
如前几节所述,对表进行更新需要使用 INSERT、DELETe 或者 UPDATE 三种语句。但通常情况下,更新处理并不是执行一次就结束了, 而是需要执行一系列连续的操作。这时,事务就能体现出它的价值了。
现在,请大家把自己想象为管理 Product(商品)表的程序员或者 软件工程师。销售部门的领导对你提出了如下要求。
“某某,经会议讨论,我们决定把运动 T 恤的销售单价下调 1000 日元, 同时把 T 恤衫的销售单价上浮 1000 日元,麻烦你去更新一下数据库。”
由于大家已经学习了更新数据的方法 —— 只需要使用 UPDATE 进行 更新就可以了,所以肯定会直接回答“知道了,请您放心吧”。
此时的事务由如下两条更新处理所组成。
上述①和②的操作一定要作为同一个处理单元执行。如果只执行了① 的操作而忘记了执行②的操作,或者反过来只执行了②的操作而忘记了执 行①的操作,一定会受到领导的严厉批评。遇到这种需要在同一个处理单 元中执行一系列更新操作的情况,一定要使用事务来进行处理。
创建事务
事务的语法
使用事务开始语句和事务结束语句,将一系列 DML 语句(INSERT/ UPDATE/DELETE 语句)括起来,就实现了一个事务处理。
这时需要特别注意的是事务的开始语句。实际上,在标准 SQL 中 并没有定义事务的开始语句,而是由各个 DBMS 自己来定义的。比较有 代表性的语法如下所示。
例如使用之前的那两个 UPDATE(①和②)创建出的事务如代码清 单如下所示。
COMMIT——提交处理
COMMIT 是提交事务包含的全部更新处理的结束指令(下图),相当 于文件处理中的覆盖保存。一旦提交,就无法恢复到事务开始前的状态了。 因此,在提交之前一定要确认是否真的需要进行这些更新。
万一由于误操作提交了包含错误更新的事务,就只能回到重新建表、 重新插入数据这样繁琐的老路上了。由于可能会造成数据无法恢复的后 果,请大家一定要注意(特别是在执行 DELETE 语句的 COMMIT 时尤其 要小心)。
虽然我们可以不清楚事务开始的时间点,但是在事务结束时一定要仔细进行确认。
ROLLBACK——取消处理
ROLLBACK 是取消事务包含的全部更新处理的结束指令(下图), 相当于文件处理中的放弃保存。一旦回滚,数据库就会恢复到事务开始之 前的状态(代码清单 4-22)。通常回滚并不会像提交那样造成大规模的数 据损失。
上述事务处理执行之后,表中的数据不会发生任何改变。这是因为执 行最后一行的 ROLLBACK 之后,所有的处理都被取消了。因此,回滚执 行起来就无需像提交时那样小心翼翼了(即使是想要提交的情况,也只需 要重新执行事务处理就可以了)。
ACID特性
DBMS 的事务都遵循四种特性,将这四种特性的首字母结合起来统 称为 ACID 特性。这是所有 DBMS 都必须遵守的规则。
原子性(Atomicity)
原子性是指在事务结束时,其中所包含的更新处理要么全部执行,要 么完全不执行,也就是要么占有一切要么一无所有。例如,在之前的例 子中,在事务结束时,绝对不可能出现运动 T 恤的价格下降了,而 T 恤 衫的价格却没有上涨的情况。该事务的结束状态,要么是两者都执行了 (COMMIT),要么是两者都未执行(ROLLBACK)。 从事务中途停止的角度去考虑,就能比较容易理解原子性的重要性了。 由于用户在一个事务中定义了两条 UPDATE 语句,DBMS 肯定不会只执 行其中一条,否则就会对业务处理造成影响。
一致性(Consistency)
一致性指的是事务中包含的处理要满足数据库提前设置的约束,如主 键约束或者 NOT NULL 约束等。例如,设置了 NOT NULL 约束的列是 不能更新为 NULL 的,试图插入违反主键约束的记录就会出错,无法执行。 对事务来说,这些不合法的 SQL 会被回滚。也就是说,这些 SQL 处理会 被取消,不会执行。一致性也称为完整性(下图)。
隔离性(Isolation)
隔离性指的是保证不同事务之间互不干扰的特性。该特性保证了事务 之间不会互相嵌套。此外,在某个事务中进行的更改,在该事务结束之前, 对其他事务而言是不可见的。因此,即使某个事务向表中添加了记录,在 没有提交之前,其他事务也是看不到新添加的记录的。
持久性(Durability)
持久性也可以称为耐久性,指的是在事务(不论是提交还是回滚)结 束后,DBMS 能够保证该时间点的数据状态会被保存的特性。即使由于系 统故障导致数据丢失,数据库也一定能通过某种手段进行恢复。
如果不能保证持久性,即使是正常提交结束的事务,一旦发生了系统 故障,也会导致数据丢失,一切都需要从头再来。
保证持久性的方法根据实现的不同而不同,其中最常见的就是将事务 的执行记录保存到硬盘等存储介质中(该执行记录称为日志)。当发生故 障时,可以通过日志恢复到故障发生前的状态。
事务的特性
事务包括四大特性:ACID
A: 原子性:事务是最小的工作单元,不可再分。
C: 一致性:事务必须保证多条DML语句同时成功或者同时失败。
I:隔离性:事务A与事务B之间具有隔离。
D:持久性:持久性说的是最终数据必须持久化到硬盘文件中,事务才算成功的结束。
关于事务之间的隔离性
事务隔离性存在隔离级别,理论上隔离级别包括4个:
第一级别:读未提交(read uncommitted)
对方事务还没有提交,我们当前事务可以读取到对方未提交的数据。
读未提交存在脏读(Dirty Read)现象:表示读到了脏的数据。
指令(进入mysql后):set global transaction isolation level read uncommitted;
第二级别:读已提交(read committed)
对方事务提交之后的数据我方可以读取到。
这种隔离级别解决了: 脏读现象没有了。
读已提交存在的问题是:不可重复读。
指令(进入mysql后):set global transaction isolation level read committed;
第三级别:可重复读(repeatable read)
这种隔离级别解决了:不可重复读问题。
这种隔离级别存在的问题是:读取到的数据是幻象。
指令(进入mysql后):set global transaction isolation level repeatable read;
第四级别:序列化读/串行化读(serializable)
解决了所有问题。
效率低。需要事务排队。
指令(进入mysql后):set global transaction isolation level serializable;
查看事务隔离级别:
mysql >select @@global.tx isolation;
oracle数据库默认的隔离级别是:读已提交。
mysql数据库默认的隔离级别是:可重复读。
存储引擎
完整的建表语句
CREATE TABLE `t_x` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
注意:在MySQL当中,凡是标识符是可以使用飘号括起来的。最好别用,不通用。
建表的时候可以指定存储引擎,也可以指定字符集。
mysql默认使用的存储引擎是InnoDB方式。
默认采用的字符集是UTF8
什么是存储引擎呢
存储引擎这个名字只有在mysql中存在。(Oracle中有对应的机制,但是不叫做存储引擎。Oracle中没有特殊的名字,
就是“表的存储方式”)
mysql支持很多存储引擎,每一个存储引擎都对应了一种不同的存储方式。
每一个存储引擎都有自己的优缺点,需要在合适的时机选择合适的存储引擎。
查看当前mysql支持的存储引擎
show engines G
常见的存储引擎
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
MyISAM这种存储引擎不支持事务。
MyISAM是mysql最常用的存储引擎,但是这种引擎不是默认的。
MyISAM采用三个文件组织一张表:
xxx.frm(存储格式的文件)
xxx.MYD(存储表中数据的文件)
xxx.MYI(存储表中索引的文件)
优点:可被压缩,节省存储空间。并且可以转换为只读表,提高检索效率。
缺点:不支持事务。
-------------------------------------------------------------------------------------
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
优点:支持事务、行级锁、外键等。这种存储引擎数据的安全得到保障。
表的结构存储在xxx.frm文件中
数据存储在tablespace这样的表空间中(逻辑概念),无法被压缩,无法转换成只读。
这种InnoDB存储引擎在MySQL数据库崩溃之后提供自动恢复机制。
InnoDB支持级联删除和级联更新。
-------------------------------------------------------------------------------------
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
缺点:不支持事务。数据容易丢失。因为所有数据和索引都是存储在内存当中的。
优点:查询速度最快。
以前叫做HEPA引擎。
什么是索引?有什么用?
索引就相当于一本书的目录,通过目录可以快速的找到对应的资源。
在数据库方面,查询一张表的时候有两种检索方式:
第一种方式:全表扫描
第二种方式:根据索引检索(效率很高)
索引为什么可以提高检索效率呢?
其实最根本的原理是缩小了扫描的范围。
索引虽然可以提高检索效率,但是不能随意的添加索引,因为索引也是数据库当中
的对象,也需要数据库不断的维护。是有维护成本的。比如,表中的数据经常被修改
这样就不适合添加索引,因为数据一旦修改,索引需要重新排序,进行维护。
添加索引是给某一个字段,或者说某些字段添加索引。
创建索引对象:
create index 索引名称 on 表名(字段名);
删除索引对象:
drop index 索引名称 on 表名;
注意:主键和具有unique约束的字段自动会添加索引。
根据主键查询效率较高。尽量根据主键检索。
查看sql语句的执行索引计划:
mysql> explain select ename,sal from emp where sal = 5000;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
给薪资sal字段添加索引:
create index emp_sal_index on emp(sal);
mysql> explain select ename,sal from emp where sal = 5000;
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| 1 | SIMPLE | emp | ref | emp_sal_index | emp_sal_index | 9 | const | 1 | Using where |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
索引底层采用的数据结构是:B + Tree
索引的实现原理
通过B Tree缩小扫描范围,底层索引进行了排序,分区,索引会携带数据在表中的“物理地址”,
最终通过索引检索到数据之后,获取到关联的物理地址,通过物理地址定位表中的数据,效率
是最高的。
select ename from emp where ename = 'SMITH';
通过索引转换为:
select ename from emp where 物理地址 = 0x3;
索引的分类
单一索引:给单个字段添加索引
复合索引: 给多个字段联合起来添加1个索引
主键索引:主键上会自动添加索引
唯一索引:有unique约束的字段上会自动添加索引
索引什么时候失效?
select ename from emp where ename like '%A%';
模糊查询的时候,第一个通配符使用的是%,这个时候索引是失效的。