前往顾页
以后地位: 主页 > 收集编程 > Php实例教程 >

MySQL与事件 概述

时候:2015-01-23 20:36来源:知行网www.zhixing123.cn 编辑:麦田守望者

先来明白一下事件触及的相关知识:

事件都应当具有ACID特性。所谓ACID是Atomic(原子性),Consistent(分歧性),Isolated(隔离性),Durable(持续性)四个词的首字母所写,下面以“银行转帐”为例来别离申明一下它们的含义:

原子性:构成事件措置的语句构成了一个逻辑单位,不克不及只履行此中的一部分。换句话说,事件是不成豆割的最小单位。比如:银行转帐过程中,必须同时从一个帐户减去转帐金额,并加到另外一个帐户中,只改变一个帐户是不公道的。

分歧性:在事件措置履行前后,数据库是分歧的。也就是说,事件应当精确的转换体系状况。比如:银行转帐过程中,要么转帐金额从一个帐户转入另外一个帐户,要么两个帐户都不变,没有其他的环境。

隔离性:一个事件措置对另外一个事件措置没有影响。就是说任何事件都不成能看到一个处在不完整状况下的事件。比如说,银行转帐过程中,在转帐事件没有提交之前,另外一个转帐事件只能处于等候状况。

持续性:事件措置的结果可以或许被永久保存上去。反过去讲,事件该当可以或许接受所有的失败,包含办事器、过程、通信和媒体失败等等。比如:银行转帐过程中,转帐后帐户的状况要能被保存上去。

再来看看哪些问题会用到事件措置:

这里不说“银行转帐”的例子了,说一个年夜家实际更容易碰到的“网上购书”的例子。先假定一下问题的被页竞网上购书,某书(数据库编号为123)只剩最后一本,而这个时候,两个用户对这本书几近同时发出了采办请求,让我们看看全部过程:

在详细阐发之前,先来看看数据表的定义:

-------------------------------------------------------------------------------

create table book
(
book_id unsigned int(10) not null auto_increment,
book_name varchar(100) not null,
book_price float(5, 2) not null, #我假定每本书的代价不会超越999.99元
book_number int(10) not null,
primary key (book_id)
)
type = innodb; #engine = innodb也行

-------------------------------------------------------------------------------

对用户甲来讲,他的行动略微比乙快一点点,其采办过程所触发的行动年夜致是如许的:

-------------------------------------------------------------------------------

1. SELECT book_number FROM book WHERE book_id = 123;

book_number年夜于零,确认采办行动并更新book_number

2. UPDATE book SET book_number = book_number - 1 WHERE book_id = 123;

购书成功

-------------------------------------------------------------------------------

而对用户乙来讲,他的行动略微比甲慢一点点,其采办过程所触发的行动和甲不异:

-------------------------------------------------------------------------------

1. SELECT book_number FROM book WHERE book_id = 123;

这个时候,甲方才进行完第一步的操纵,还没来得及做第二步操纵,所以book_number必然年夜于零

2. UPDATE book SET book_number = book_number - 1 WHERE book_id = 123;

购书成功

-------------------------------------------------------------------------------

大要上看甲乙的操纵都成功了,他们都买到了书,但是库存只需一本,他们怎样可能都成功呢?再看看数据表里book_number的内容,已变成 “-1”了,这当然是不克不及许可的(实际上,声明如许的列范例应当加上unsigned的属性,以包管其不克不及为负,这里是为了申明问题所以没有如许设置)

好了,问题陈述清楚了,再来看看怎样操纵事件来处理这个问题,翻开MySQL手册,可以看到想用事件来庇护你的SQL精确履行其实很简朴,根基就是三个语句:开端,提交,回滚。

-------------------------------------------------------------------------------

开端:START TRANSACTION或BEGIN语句可以开端一项新的事件

提交:COMMIT可以提交以后事件,是变动成为永久变动

回滚:ROLLBACK可以回滚以后事件,打消其变动

别的,SET AUTOCOMMIT = {0 | 1}可以禁用或启用默许的autocommit形式,用于以后连接。

-------------------------------------------------------------------------------

那是不是是只需用事件语句包一下我们的SQL语句就可以包管精确了呢?比以下面代码:

-------------------------------------------------------------------------------

BEGIN;

SELECT book_number FROM book WHERE book_id = 123;

// ...

UPDATE book SET book_number = book_number - 1 WHERE book_id = 123;

COMMIT;

-------------------------------------------------------------------------------

答案是不是定了,如许仍然不克不及避免问题的产生,如果想避免如许的环境,实际应当以下:

-------------------------------------------------------------------------------

BEGIN;

SELECT book_number FROM book WHERE book_id = 123 FOR UPDATE;

// ...

UPDATE book SET book_number = book_number - 1 WHERE book_id = 123;

COMMIT;

-------------------------------------------------------------------------------

因为插手了FOR UPDATE,所以会在此条记录上加上一个行锁,如果此事件没有完整结束,那么其他的事件在利用SELECT ... FOR UPDATE请求的时候就会处于等候状况,直到上一个事件结束,它才气继续,从而避免了问题的产生,需求重视的是,如果你其他的事件利用的是不带FOR UPDATE的SELECT语句,将得不到这类庇护。

最后看看PHP + MySQL事件操纵的代码演示:

实际LAMP利用中,一般PHP利用AdoDB操纵MySQL,下面给出AdoDB呼应的代码便利年夜家查阅:

-------------------------------------------------------------------------------

<?php
// ...

$adodb->startTrans
();

//实际,getOne所调用的查询也能够直接放到rowLock来进行,这里只是为了演示结果能更较着些。

$adodb->rowLock('book', 'book_id = 123'
);

$bookNumber = $adodb->getOne("SELECT book_number FROM book WHERE book_id = 123"
);

$adodb->execute("UPDATE book SET book_number = book_number - 1 WHERE book_id = 123"
);

$adodb->completeTrans
();

// ...
?>

-------------------------------------------------------------------------------

此中,rowLock的体例就是调用的FOR UPDATE来实现的行锁,你可能会想把“FOR UPDATE”直接写到$adodb->getOne()调用的那条SQL语句内里去实细葱锁的服从,不错,那样确切可以,但是其实不是所有的数据库都利用“FOR UPDATE”语法来实细葱锁服从,比如Sybase利用“HOLDLOCK”的语法来实细葱锁服从,所以为了你的数据库笼统层保持可移植性,我还是劝你用rowLock来实细葱锁服从,至于可移植性就交给AdoDB好了,嗯,有点扯远了,今儿就说到这里了。

-------------------------------------------------------------------------------

附:

AdoDB中存在一个setTransactionMode()体例,可以或许设置事件的隔离级别,以下:

SetTransactionMode allows you to pass in the transaction mode to use for all subsequent transactions for that connection session. Note: if you have persistent connections and using mysql or mssql, you might have to explicitly reset your transaction mode at the beginning of each page request. This is only supported in postgresql, mssql, mysql with InnoDB and oci8 currently. For example:

$db->SetTransactionMode("SERIALIZABLE");
$db->BeginTrans();
$db->Execute(...); $db->Execute(...);
$db->CommiTrans();

$db->SetTransactionMode(""); // restore to default
$db->StartTrans();
$db->Execute(...); $db->Execute(...);
$db->CompleteTrans();

Supported values to pass in:

* READ UNCOMMITTED (allows dirty reads, but fastest)
* READ COMMITTED (default postgres, mssql and oci8)
* REPEATABLE READ (default mysql)
* SERIALIZABLE (slowest and most restrictive)

You can also pass in database specific values such as 'SNAPSHOT' for mssql or 'READ ONLY' for oci8/postgres.

顶一下
(0)
0%
踩一下
(0)
0%
------分开线----------------------------
标签(Tag):数据库 MYSQL mysql数据库
------分开线----------------------------
颁发评论
请自发遵循互联网相关的政策法规,严禁公布色情、暴力、革命的谈吐。
评价:
神色:
考证码:点击我更换图片
猜你感兴趣