代码分享:https://github.com/mtdgclub/PDO
具体查看根目录下的pdoAffair.php文件代码
2. 事务的四大特性
- 原子性:事务必须是一个不可分割的整体,要么做完,要么不做。
- 一致性:事务执行前和执行后来源和去向保持平衡,数据不会被破坏。
- 隔离性:并发时每个事务是隔离的,相互不影响。
- 持久性:事务一旦成功提交,就会永久保存到数据库中。
原子性是基础,隔离性是手段,持久性是目的,真正的老大就是一致性。
3. 三类数据读问题
3.1 Dirty Read(脏读)
事务 A 读取了事务 B 未提交的数据,并在这个基础上又做了其他操作。
3.2 Unrepeatable Read(不可重复读)
事务 A 读取了事务 B 已提交的更改数据。
3.3 Phantom Read(幻读)
事务 A 读取了事务 B 已提交的新增数据。
3.4 不可重复读和幻读的区别
- 不可重复读的重点是修改,避免不可重复读需要锁行
- 幻读的重点在于新增或者删除,避免幻读需要锁表
4.两类数据更新问题
4.1 第一类丢失更新(撤销覆盖)
A事务撤销时,把已经提交的B事务的更新数据覆盖了。
4.2 第二类丢失更新(提交覆盖)
B事务覆盖A事务已经提交的数据,造成A事务所做操作丢失。
5.隔离的级别
5.1 MySQL
mysql默认的事务处理级别是"REPEATABLE-READ",也就是可重复读
- 查看当前会话隔离级别
select @@tx_isolation;
- 查看系统当前隔离级别
select @@global.tx_isolation;
- 设置当前会话隔离级别
set session transaction isolatin level repeatable read;
- 设置系统当前隔离级别
set global transaction isolation level repeatable read;
5.2 Oracle
oracle数据库支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别。默认系统事务隔离级别是READ COMMITTED,也就是读已提交。
- 查看系统默认事务隔离级别,也是当前会话隔离级别
--首先创建一个事务
declare
trans_id Varchar2(100);
begin
trans_id := dbms_transaction.local_transaction_id( TRUE );
end;
--查看事务隔离级别
SELECT s.sid, s.serial#,
CASE BITAND(t.flag, POWER(2, 28))
WHEN 0 THEN "READ COMMITTED"
ELSE "SERIALIZABLE"
END AS isolation_level
FROM v$transaction t
JOIN v$session s ON t.addr = s.taddr AND s.sid = sys_context("USERENV", "SID");
6.事务实现步骤
归纳以下几点重要步骤:
- 关闭自动提交功能
$mysqli->autocommit(false);
- 视情况创建回滚点
$mysqli->savepoint a;
- 执行失败则回滚
$mysqli->rollback();
- 执行成功则提交
$mysqli->commit();
7.实战事务回滚案例
7.1 数据库结构
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) DEFAULT NULL,
`mobile` varchar(13) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `FindUserId` (`mobile`,`password`)
) ENGINE=MyISAM AUTO_INCREMENT=35 DEFAULT CHARSET=utf8;
7.2 案例代码实战
//创建一个mysqli对象
$mysqli = new MySQLi("localhost", "root", "root");
$mysqli->select_db("myyaf");
//判断是否链接成功
if ($mysqli->connect_error) {
die($mysqli->connect_error);
}
//由于在事务提交中系统默认提交,故这里设置为FALSE先不提交
$mysqli->autocommit(false);
//其实这里系统已经相当在这里做个保存点,记录此时所有状态,回滚是回滚到这里
$mysqli->savepoint("a");
//写出对数据库的操作语句
for ($i = 0; $i <= 30; $i++) {
$sql = ".....";
//执行sql语句
$res = $mysqli->query($sql) or die ($mysqli->error."
".$sql);
//判断是否都执行成功
if ($res) {
//只要有一条失败便回滚,都不执行,若设置滚回点,如a,则回滚到a处
$mysqli->rollback();
} else {
//一旦提交无法回滚,成功则提交
$mysqli->commit();
}
}
//关闭资源
$mysqli->close();
8.总结
对于数据库的事务,其实当你能够理解事务的概念,再结合实际应用场景,就能很好地使用,一般来说,一些对数据高严谨的程序都会使用事务来执行CURD操作。