一、什么是事物?
个人理解,sql中的事物就是给sql语句做一个分组,组内的sql语句要不然就全部执行成功,要不然就完全的不会执。或者说作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。
事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。一个逻辑工作单元要成为事务。
二、关于事物的示例,以及如何在mysql中开启事物。
start transaction;开启事务
Rollback 回滚事务,即撤销指定的sql语句(只能回退insert delete update语句),回滚到上一次commit的位置.
Commit 提交事务,提交未存储的事务.
savepoint 保留点 ,事务处理中设置的临时占位符 你可以对它发布回退(与整个事务回退不同).(也可以理解为回退到某个点,并不会完全回退到上次commit的位置。)
示例:
create table test2(id int PRIMARY KEY auto_increment,name VARCHAR(20)) engine=innodb;
INSERT INTO test2(name) VALUE ("user1"),("user2"),("user3");
start transaction; #创建事物。
insert into test2 (name)values(‘user4‘);
select * from test2;
commit; #提交后,真正的把数据写到数据库中。
-------------------------下面是关于保留点的示例-------------------------------
start transaction;
insert into test2 (name)values(‘wu‘);
savepoint insert_wu; #定义一个保留点
select * from test2;
delete from test2 where id=4;
savepoint delete1; #定义一个保留点
select * from test2;
delete from test2 where id=1;
savepoint delete2; #定义一个保留点
select * from test2;
rollback to delete1; #回滚到哪个保留点之后。
select * from test2;
python中调用数据库启动事务的方式:
import pymysql
#添加数据
conn = pymysql.connect(host=‘127.0.0.1‘, port=3306, user=‘root‘, passwd=‘‘, db=‘yyy‘)
cursor = conn.cursor()
try:
insertSQL0="INSERT INTO ACCOUNT2 (name,balance) VALUES (‘user1‘,4000)"
insertSQL1="UPDATE account2 set balance=balance-30 WHERE name=‘user2‘"
insertSQL2="UPDATE account2 set balance=balance+30 WHERE name=‘user3"
cursor = conn.cursor()
cursor.execute(insertSQL0)
conn.commit()
cursor.execute(insertSQL1)
raise Exception #触发异常,用来模拟第三条sql语句执行异常。
cursor.execute(insertSQL2)
cursor.close()
conn.commit()
except Exception as e:
conn.rollback()
conn.commit()
cursor.close()
conn.close()
三、事物特性的总结:
原子性:
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
隔离性:
事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
永久性:
事物一旦被提交,它对数据库中数据的改变就是永久性的。
事物的隔离性是非常重要的!!如果不考虑隔离性会出现以下问题。
脏读(读取脏数据)
脏读就是一个事物读取到了另外一个事物还没有提交的数据,这种情况在生产环境特别危险!!
假如说,现在事物1正在修改某一个数据,并且准备提交(还没有提交!),此时,事物2读取到了同一数据之后,事物1由于执行了某条sql语句没成功,突然回滚,此时的事物1已经把修改过的数据,变回了原来的值,事物2所读到的,是事物1之前修改过还没提交的数据,所以说,事物2所读到的数据和数据库中的数据根本不一致!!所以是不正确的数据。
关于脏读的示例:
a 1000
b 1000
a:
start transaction;
update set money=money+100 where name=b;
b:
start transaction;
select * from account where name=b;--1100
commit;
a:
rollback;
b: start transaction;
select * from account where name=b;--1000
2.不可重复读:
事物1读取了数据库中的数据后,事物2对这个数据进行了更新操作,导致事物1无法读取前一次的结果。
说的再简单一些,就是在一个事物内读取表中的某一行记录,多次读取的内容是不同的。
事务1读取某一数据后,事物2对其做了修改,当事物1再次读该数据后,得到与前一不同的值。
3.产生幽灵数据:
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。(一个事务读取到了另一个事务已经提交的数据—增加记录、删除记录),在某写情况下并不是问题,在另一些情况下就是问题。
b 1000
c 2000
d 3000
a:
start transaction
select sum(money) from account;---3000 3000
-------------------
d:start transaction;
insert into account values(d,3000);
commit;
-------------------
select count(*)from account;---3 3
3000/3 = 1000 1000
避免以上几种情况发生的隔离级别:
四个隔离级别:
Serializable:可避免脏读、不可重复读、虚读情况的发生。(串行化)
Repeatable read:可避免脏读、不可重复读情况的发生。(可重复读)不可以避免虚读
Read committed:可避免脏读情况发生(读已提交)
Read uncommitted:最低级别,以上情况均无法保证。(读未提交)
安全性考虑:Serializable>Repeatable read>Read committed>Read uncommitted
数据库效率:Read uncommitted>Read committed>Repeatable read>Serializable
一般情况下,我们会使用Repeatable read、Read committed mysql数据库默认的数据库隔离级别Repeatable read
mysql中设置数据库的隔离级别语句:
set [global/session] transaction isolation level xxxx;
如果使用global则修改的是数据库的默认隔离级别,所有新开的窗口的隔离级别继承自这个默认隔离级别如果使用session修改,则修改的是当前客户端的隔离级别,和数据库默认隔离级别无关。当前的客户端是什么隔离级别,就能防止什么隔离级别问题,和其他客户端是什么隔离级别无关。
mysql中设置数据库的隔离级别语句:
select @@tx_isolation;
本文出自 “reBiRTH” 博客,请务必保留此出处http://suhaozhi.blog.51cto.com/7272298/1934310
原文地址:http://suhaozhi.blog.51cto.com/7272298/1934310