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 summmary=@A 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 INDEX
|
DROP DATABASE
|
DROP TABLE
|
RENAME TABLE
|
TRUNCATE
|
|
|
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
锁
被
释
放。
如果
这
在你的
应
用程序中会引起一个
严
重的
问题
,你
应该
考
虑
将你的某些
表
转换为
事
务
安全表。
注意,你不
应该
锁
定你正在
对
其使用
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 辅助功能函数
。
你可以使用
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
关键词为
当前
连
接所有将来
执
行的事
务设
置默
认
的事
务
隔离
级
。