事务控制和锁定语句

  MySQL 支持对 MyISAM 和 MEMORY 存储引擎的表进行表级锁定,对 BDB 存储引擎的表进行页级锁定,对 InnoDB 存储引擎的表进行行级锁定。默认情况下,表锁和行锁都是自动获得的,不需要额外的命令。但是在有的情况下,用户需要明确地进行锁表或者进行事务的控制,以便确保整个事务的完整性,这样就需要使用事务控制和锁定语句来完成。

一、LOCK TABLE 和 UNLOCK TABLE

LOCK TABLES 可以锁定用于当前线程的表。如果表被其他线程锁定,则当前线程会等待,直到可以获取所有锁为止。

UNLOCK TABLES 可以释放当前线程获得的任何锁定。当前线程执行另一个 LOCK TABLES 时,或当与服务器的连接被关闭时,所有由当前线程锁定的表被隐含的解锁,具体语法如下

        LOCK TABLES

          tbl_name [AS alias] {READ [LOCAL]|[LOW_PRIORITY] WRITE}

          [,tbl_name [AS alias] {READ [LOCAL]|[LOW_PRIORITY] WRITE}] ...

        UNLOCK TABLES

我们来演示一个获得表锁和释放表锁的简单例子:

先创建一个表:

再插入点数据,查询得:

在当前会话给t_1表加read锁:

在当前会话记执行查询操作:

当前会话记为session1

另外开启一个会话,记为session2:执行查询

可以执行;

在session1中执行update操作:

在session2中执行update操作:

session2会处于等待状态。

在session1中:

执行完毕之后,session2中原来的update语句开始执行:

检查一下session2中:

session1中:

二、事务控制

默认情况下,MySQL中的事务是自动提交的,要是需要自动开启和提交的事务,在mysql中使用start transaction来开启事务,是要经commit来提交事务,使用rollback来回滚事务,使用chain来立即开启下一个事务,使用release来断开和客户端的连接,使用set autocommit来修改当前事务连接提交的方式。

要注意的是如果在锁表期间,使用start transaction开启一个新事务的时候,会包含一个隐式的unlock tables。因此,对使用lock方式加的表锁,不能通过rollback方式进行回滚。

在同一个事务中最好不要使用不同存储引擎的表,否则rollback需要对非事务类型的表进行特别的处理,因为事务的提交和回滚只能针对相同类型的表进行。通常,只对提交的事务进行记录到二进制的日志当中,这时,回滚操作也会把非事务类型的数据也记录到二进制文件中,以确保非事务类型的数据的更新也能被复制到数据库中。DDL语句是不能回滚的,在事务中可以定义savepoint来指定回滚事务的部分,但不能指定提交事务的部分,对于复杂的应用也可以定义不同的savepoint来在一定的条件的时候执行,但若savepoint重名的时候回自动覆盖前一个savepoint。删除savepoint的方式就是:release savepoint,经过删除之后的savepoint不能再进行rollback to savepoint操作。

三、分布式事务的使用

1)分布式事务通常采用2PC协议,全称Two Phase Commitment Protocol。该协议主要为了解决在分布式数据库场景下,所有节点间数据一致性的问题。在分布式事务环境下,事务的提交会变得相对比较复杂,因为多个节点的存在,可能存在部分节点提交失败的情况,即事务的ACID特性需要在各个数据库实例中保证。总而言之,在分布式提交时,只要发生一个节点提交失败,则所有的节点都不能提交,只有当所有节点都能提交时,整个分布式事务才允许被提交。当前支持分布式事务的存储引擎只有InnoDB。

分布式事务通过2PC协议将提交分成两个阶段

  1. prepare;
  2. commit/rollback

第一阶段的prepare只是用来询问每个节点事务是否能提交,只有当得到所有节点的“许可”的情况下,第二阶段的commit才能进行,否则就rollback。需要注意的是:prepare成功的事务,则必须全部提交。

在prepare阶段,所有的分支都被预备好,也就是所有的分支被事务管理器告知要进行提交(一个分布式事务的应用程序只包含一个事务管理器),这意味着用于管理分支的每个资源管理器(资源管理器可以有一个或多个)会记录对于被稳定保存的分支的行动,分支用来指示他们可以这么做,这些结果被用于提交/回滚阶段。在第二阶段,事务管理器会告知所有的资源管理器是要提交或者回滚。如果在与备份分支的时候,所有分支都显示它们能够提交,则所有分支都告知要提交,若在预备分支的时候有一个及以上分支指示它不能提交,则所有分支都会进行回滚。特别的,当一个分布式事务发现只有一个资源管理器(单一分支)的时候,则在第一阶段该资源就会被告知提交或者回滚。

2)分布式事务(XA事务)的语法规则

启动一个分布式事务:XA {START|BEGIN} xid [JOIN|RESUME]

XA START xid 用于启动一个带给定 xid 值的 XA 事务。每个 XA 事务必须有一个唯一的 xid 值,因此该值当前不能被其他的 XA 事务使用。xid 是一个 XA 事务标识符,用来唯一标识一个分布式事务。xid 值有客户端提供,或由 MySQL 服务器生成。xid 值包含 1~3个部分:

xid: gtrid[, bqual[, formatID]]

        gtrid是一个分布式事务标识符,相同的分布式事务应该使用相同的 gtrid,这样可以明确知道 XA 事务属于哪个分布式事务。

   bqual 是一个分支限定符,默认值是空串。对于一个分布式事务中的每个分支事务,bqual 值必须是唯一的。

   formatID 是一个数字,用于标识由 gtrid 和 bqual 值使用的格式,默认值是1。

下面分布式事务的语法的xid值都必须和启动XA事务一样,表示对启动这个XA事务的操作:

使XA进入prepare状态:

XA END xid [SUSPEND [FOR MIGRATE]]

XA PREPARE xid

使XA进入第二阶段:

XA COMMIT xid [ONE PHASE]

XA ROLLBACK xid

返回当前数据库中处于prepare状态的分支事务的详细信息:

XA RECOVER

3)分布式事务的总结

①分布式的关键在于如何确保分布式事务的完整性,以及在某个分支出现问题时的故障解决。XA 的相关命令就是提供给应用如何在多个独立的数据库之间进行分布式事务的管理,包括启动一个分布式事务、使事务进入准备阶段以及事务的实际提交回滚操作等。

②虽然 MySQL 支持分布式事务,但是如果分支事务在达到 PREPARE 状态时,数据库异常重新启动,服务器重新启动以后,可以继续对分支事务进行提交或回滚操作,但是提交的事务没有写 binlog,存在一定的隐患,可能导致使用 binlog 恢复丢失部分数据。如果存在复制的数据库,则有可能导致主从数据库的数据不一致。

③使用 mysqlbinlog 查看 binlog(一种二进制日志,二进制日志的主要目的是在恢复使能够最大可能地更新数据库,因为二进制日志包含备份后进行的所有更新),可以确认最后提交的这个分支事务并没有记录到 binlog 中,因为复制和灾难恢复都是依赖于 binlog的,所以 binlog 的确实会导致复制环境的不同步,以及使用 binlog 恢复丢失部分数据。





猜你喜欢

转载自blog.csdn.net/qq_32595453/article/details/80053602