事务

  1   事务是用户定义的一个操作序列,这些操作要么全部成功要么全部失败,是一个不可分割的工作单位(构成单一逻辑工作单元的操作集合)
  2   事务主要用于处理操作量大,复杂度高的数据。
比如说,在人员管理系统中,你删除一个人员,你即需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
事务用来管理 insert,update,delete 语句,(DCL)

 I   事务的基本要素(ACID)

一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

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

  注意:
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。


II  MySQL事务控制语句

  • BEGINSTART TRANSACTION;显式地开启一个事务;
  • COMMIT也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改称为永久性的;
  • ROLLBACK;有可以使用ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
  • SAVEPOINT 节点名;SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;
  • RELEASE SAVEPOINT 节点名;删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
  • ROLLBACK TO 节点名;把事务回滚到标记点;
  • SET TRANSACTION;用来设置事务的隔离级别。InnoDB存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE


III  MySQL事务处理主要有两种方法

1、用 BEGIN, ROLLBACK, COMMIT来实现
BEGIN 开始一个事务
ROLLBACK 事务回滚
COMMIT 事务确认
案例实例
BEGIN
  UPDATE bank SET account = account-500 WHERE id = 1
  UPDATE bank SET account = account+500 WHERE id = 2
ROLLBACK
COMMIT

2、直接用 SET 来改变 MySQL 的自动提交模式:
    SET AUTOCOMMIT=0 禁止自动提交
    SET AUTOCOMMIT=1 开启自动提交

IV  事务的并发问题
       1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
  2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了
更新并提交,导致事务A多次读取同一数据时,结果 不一致。
  3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员
B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
  小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复
读的问题只需锁住满足条件的行,解决幻读需要锁表


V  MySQL事务隔离级别

事务隔离级别
脏读
不可重复读
幻读
读未提交(read-uncommitted)
读提交(read-committed)
可重复读(repeatable-read)
串行化(serializable)
案列语法

  查看MySQL默认的事务隔离级别
SELECT @@tx_isolation

 
在第一个客户端

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
BEGIN
  UPDATE bank SET account = account-500 WHERE id = 1
 
  UPDATE bank SET account = account+500 WHERE id = 2
ROLLBACK
COMMIT ----事务没有提交

在第二个客户端查看
SELECT * FROM bank
第一个客户端的事务还没有提交,所以第二个客户端并不能读取到第一个事务已经更新的数据,解决了脏读的问题

补充:
  1、SQL规范所规定的标准,不同的数据库具体的实现可能会有些差异
  2、mysql中默认事务隔离级别是可重复读时并不会锁住读取到的行
  3、事务隔离级别为读提交时,写数据只会锁住相应的行
  4、事务隔离级别为可重复读时,如果有索引(包括主键索引)的时候,以索引列为条件更新数据,会
存在间隙锁间隙锁、行锁、下一键锁的问题,从而锁住一些行;如果没有        索引,更新数据时会锁住整张表。
  5、事务隔离级别为串行化时,读写数据都会锁住整张表
  6、隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不
可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为 Read Committed,它能够
避免脏读取,而且具有较好的并发性能。 尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问
题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

   事务的并发控制
 
      当许多用户试图同时修改数据库内的数据时,必须控制系统以使某个用户所做的修改不会对他人产生负面影响,这称为并发控制
     
      并发控制理论因并发控制的方法不同分为两类

      悲观并发控制   锁定系统阻止用户以影响其它用户的方式修改数据,如果用户执行的操作导致了应用了某个锁,则直到这
个锁的所有者释放该锁,其它用户才能执行与该锁冲突的操作,该方法主要用于数据争夺激烈的环境中。

      乐观并发控制   在乐观并发控制中,用户读数据时不锁定数据,在执行更新时,系统进行检查,查看另一个用户读过数据后
是否更改了数据。如果另一个用户更新了数据,将产生一个错误,一般情况下,接收错误信息用户将回滚事务并重新开始。
该方法主要用在数据争夺少的环境内。



性能优化

1  在使用like关键字进行查询的查询语句中,如果匹配字符串的第一个字符为"%",索引不会起作用,只有 % 不在第一个位置,索引才会起作用

2  在MySQL中,可以使用连接(JOIN)查询来替代子查询,连接查询不需要建立临时表,其速度比子查询要快。

3  对于字段很多的表,可以将使用频率较低的字段分离出来形成新表,可以减少在查询时的数据量

4  可以根据实际情况增加冗余字段

5  插入数据时可以使用批量插入,可以提高速度

6  在插入大量数据之前禁用索引,数据插入完毕后再开启索引,会提高插入记录的速度

7  为了降低唯一性检查对查询速度的影响,可以再插入记录之前禁用唯一性检查,等到记录插入完毕再开启