MySQL 4.1.0 中文参考手册 --- 6.7 MySQL 事务与锁定命令
2024-07-24 12:54:51
供稿:网友
mysql 4.1.0 中文参考手册 --- 犬犬(心帆)翻译 mysql reference manual for version 4.1.0-alpha.
6.7 mysql 事务与锁定命令6.7.1 begin/commit/rollback 句法
缺省的,mysql 运行在 autocommit 模式。这就意味着,当你执行完一个更新时,mysql 将立刻将更新存储到磁盘上。
如果你使用事务安全表 (例如 innodb、bdb),通过下面的命令,你可以设置 mysql 为非 autocommit 模式:
set autocommit=0
在此之后,你必须使用 commit 来存储你的更改到磁盘上,或者使用 rollback ,如果你希望忽略从你的事务开始所做的更改。
如果你希望为一系列语句从 autocommit 模式转换,你可以使用 start transaction 或 begin 或 begin work 语句:
start transaction;select @a:=sum(salary) from table1 where type=1;update table2 set [email protected] where type=1;commit;
start transaction 在 mysql 4.0.11 中被加入;这是被推荐的开始一个特别(ad-hoc)事务的方式,因为这是 ansi sql 句法。
注意,如果你使用的是一个非事务安全表,更改会立刻被存储,不受 autocommit 模式状态的约束。
当你更新了一个非事务表后,如果你执行一个 rollback,你将得到一个错误 (er_warning_not_complete_rollback) 作为一个警告。所有事务安全表将被恢复,但是非事务安全表将不会改变。
如果你使用 start transaction 或 set autocommit=0,你应该使用 mysql 二进制日志做备份以代替老的更新日志。事务处理被以一个大块形式存储在二进制日志中,在 commit 上面,为了保护回滚的事务,而不是被存储的。查看章节 4.9.4 二进制日志。如果您使用起动事务处理或集autocommit=0 ,您应该使用mysql 二进制日志为备份代替更旧的更新日志。 事务处理存储在二进制登录一大块,做,保证, 滚的事务处理不存储。 参见部分4 。9.4 二进制日志。
下列命令自动的结束一个事务 (就好像你在执行这个命令之前,做了一个 commit):
命令 命令 命令 alter table begin create indexdrop database drop table rename tabletruncate
你可以使用 set transaction isolation level ... 改变事务的隔离级。查看章节 6.7.3 set transaction 句法。
6.7.2 lock tables/unlock tables 句法
lock tables tbl_name [as alias] {read [local] | [low_priority] write} [, tbl_name [as alias] {read [local] | [low_priority] write} ...]...unlock tables
lock tables 为当前线程锁定表。unlock tables 释放当前线程拥有的所有锁定。当线程发出另一个 lock tables,或当与服务器的连接被关闭时,被当前线程锁定的所有表将被自动地解锁。
为了在 mysql 4.0.2 使用 lock tables ,你必须拥有一个全局的 lock tables 权限和一个在相关表上的 select 权限。在 mysql 3.23 中,你对该表需要有 select、insert、delete 和 update 权限。
使用 lock tables 的主要原因是,仿效事务处理或在更新表时得到更快的速度。此后会有更详细的描述。
如果一个线程在一个表上得到一个 read 锁,该线程 (和所有其它线程) 只能从表中读取。如果一个线程在一个表上得到一个 write 锁,那么只有拥有这个锁的线程可以从表中读取和写表。其它的线程被阻塞。
read local 和 read 之间的不同就在于,当锁被加载时,read local 允许非冲突(non-conflicting) insert 语句执行。如果当你加载着锁时从 mysql 外部操作数据库文件,这将仍不能被使用。
当你使用 lock tables 是地,你必须锁定所有你将使用的表,并且必须使用与你的查询中将使用的别名相同!如果你在一个查询中多次使用一个表(用别名),你必须为每一个别名获得一个锁。
write 锁通过比 read 锁有更高的权限,以确保更新被尽快地处理。这就意味着,如果一个线程获得一个 read 锁,而同时另外一个线程请求一个 write 锁,并发的 read 锁请求将等待直到 write 线程得到了锁并释放了它。你可以使用 low_priority write 锁,当该线程在等待 write 锁时,它将允许其它的线程获得 read 锁。你应该只使用 low_priority write 锁,如果你确信这将是最后一次,当没有线程将拥有 read 锁。
lock tables 工作如下:以内部定义的次序排序所有被锁定的表 (从用户立场说,该次序是不明确的)。如果一个表被以一个读锁和一个写锁锁定,将写锁放在读锁之前。一次只锁定一个表,只到线程得到所有的锁定。
这个方案是为了确保,表锁定死锁释放。 对于这个模式你仍然有些其它事情需要知道:
如果你对一个表使用一个 low_priority write 锁定,这就意味着,mysql 将等待这个锁,直到没有线程请求一个 read 锁。当线程得到了 write 锁,并等待获得锁定表列表中的下一个表的锁定时,其它所有的线程将等待 write 锁被释放。如果这在你的应用程序中会引起一个严重的问题,你应该考虑将你的某些表转换为事务安全表。
你可以使用 kill 安全地杀死一个正在表锁定的线程。查看章节 4.5.5 kill 句法。
注意,你不应该 锁定你正在对其使用 insert delayed 的表。这是因为,在这种情况下,insert 是通过单独的线程完成的。
通常,你不需要锁定任何表,因为所有单 update 语句都是原子的;其它的线程无法干扰当前执行的 sql 语句。当你无论如何希望锁定表时,这里有一些情况:
如果你在一束表上运行许多操作,锁定你将要使用的表,这会更快一些。当然有不利的方面,其它线程将不能更新一个 read 锁的表,并且没有其它线程要以读取一个 write 锁的表。在 lock tables 下,某些事运行得更快一些的原因是,mysql 将不会转储清除被锁定表键高速缓冲,直到 unlock tables 被调用 (通常键高速缓冲在每个 sql 语句后都会被转储清除)。这将加速在 myisam 表上的插入、更新、删除。
如果你在 mysql 中正在使用一个不支持事务的存储引擎,如果你希望能确保没有其它的线程会出现在一个 select 和 一个 update 之间,你必须使用 lock tables 。下面的示例显示为了安全地执行,这里需要lock tables :
mysql> lock tables trans read, customer write;mysql> select sum(value) from trans where customer_id=some_id;mysql> update customer set total_value=sum_from_previous_statement -> where customer_id=some_id;mysql> unlock tables;
不使用 lock tables,将可能发生在 select 和 update 语句执行期间有另外一个线程可能在 trans 表中插入一行新记录。
通过使用递增更新 (update customer set value=value+new_value) 或 last_insert_id() 函数,你可以在很多情况下避免使用 lock tables。
你也可以使用用户级锁定函数 get_lock() 和 release_lock() 解决一些情况,这些锁被保存在服务器上的一个哈希表中,并以 pthread_mutex_lock() 和 pthread_mutex_unlock() 实现以获得高速度。查看章节 6.3.6.2 辅助功能函数。
查看章节 5.3.1 mysql 如何锁定表,以获取关于锁定方案的更多信息。
你可以使用 flush tables with read lock 命令以读锁锁定所有数据库中的所有表。查看章节 4.5.3 flush 句法。如果你有一个可以及时建立文件快照的文件系统,例如 veritas,这将是得到备份的非常方便方式。
注意:lock tables 不是事务安全的,在尝试锁定一个表之前,将自动地提交所有的活动事务。
6.7.3 set transaction 句法
set [global | session] transaction isolation level{ read uncommitted | read committed | repeatable read | serializable }
设置全局的、整个会话或下一个事务的事务隔离级。
缺省行为是设置下一个(未启动的)事务的隔离级。如果你使用 global 关键词,语句为所有在那个点上建立的新连接设置默认的全局事务隔离级。为了这样做,你需要有 super 权限。使用 session 关键词为当前连接所有将来执行的事务设置默认的事务隔离级。
你可以使用 --transaction-isolation=... 为 mysqld 设置默认的全局隔离级。查看章节 4.1.1 mysqld 命令行选项。