什么存储引擎支持事务
1、查看数据库引擎是否支持事务(Innodb支持)? show engines; 2、查看MySQL当前默认的存储引擎? show VARIABLES LIKE ‘%storage_engine%’; 3、查看某张表的存储引擎? show create table 表名; 4、对于表的存储结构的修改? 建立Innodb表:Create table 表 type = Innodb;Alter table 表 type=Innodb;
事务的特性
事务应该具有四个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。 1、原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的诸多操作要么都做,要么都不做。 2、一致性(consistency):事务必须是使数据库从一个一致性状态变到另外一个一致性状态。一致性与原子性是密切相关的。 3、隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。 4、持久性(durability):也称为永久性,指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
原子性的例子: 小明给小红转账1000, 小明的账户就-1000, 小红的账户就+1000。 整个事务要么全部成功,要么全部失败。不可能扣了小明的钱,但不给小红加上,这不合理。
一致性的例子: 小明给小红转账1000, 小明的账户就-1000, 1、小红的账户增加1000, 2、小红的账户增加2000。 小明转账的过程中,发生了卡顿,系统以为没有给小红加上,又加了一次。这样银行就要找小红了。一致性就是小明扣多少,小红就只能加多少,两者相加等于0。
持久性的例子: 并不是数据库的角度完全能解决的。比如热备份、读写分离等。
隔离性级别
未提交读(READ UNCOMMITED) 导致脏读
已提交读(READ COMMITED)导致不可重复读
可重复读(REPEATABLE READ)
可串行话(SERIALIZABLE)
MySQL默认事务隔离级别为repeatable-read。 可通过语句查:show VARIABLES LIKE ‘%isolation%’
不同隔离性级别在并发环境下的问题
脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。比如小明的账户有5000,操作取钱1000,这时候小红又来取小明的钱,此时账户只有4000。但是小明回滚了账户,账户有5000。实际小红读的数据是脏数据。
不可重复读:事务A多次读取同一个数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一样。比如在同一个事务中,小红第一次查看小明的工资是五千,这时候小明从账户取出了1000块,并提交了自己的事务,这时候小红第二次查看小明的工资的时候变成了4千,导致了在同一个事务中读取同一个数据的值不同。
可重复读:事务A原来账户5000,在自己的事务中减去了1000,事务B去获取账户的时候还是5000,则时候A事务提交。事务B在去获取账户余额的时候还是5000。
幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发送了幻觉一样,就叫幻读。
注意: 不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需要锁住满足条件的行,解决幻读需要锁表(消耗性能)。
不同隔离性级别设置和操作
1、未提交读(READ UNCOMMITED) 脏读 set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITED;
例子: 一个session中,balance = 450 start TRANSACTION update account set balance = balance - 50 where id = 1;
另外一个session中查询,balance = 400 select * from account;
回到第一个session中 回滚事务 ROLLBACK
在第二个session中 update account set balance = balance - 50 where id = 1; 查询结果还是400。
2、已提交读(READ COMMITED)不可重复读 set SESSION TRANSACTION ISOLATION LEVEL READ COMMITED;
例子: 一个session中 start TRANSACTION update account set balance = balance - 50 where id = 1;
另外一个session中查询(数据并没改变) select * from account;
回到第一个session中提交事务 commit
在第二个session中 select * from account;(数据已改变)
3、可重复读(REPEATABLE READ) set SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
例子: 一个session中(account=450) start TRANSACTION update account set balance = balance - 50 where id = 1;
另外一个session中查询(数据并没改变,account=450) select * from account;
回到第一个session中提交事务 commit
在第二个session中 select * from account;(数据并未改变,balance=450)
4、可串行化(SERIALIZABLE) set SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
例子: 开启一个事务 BEGIN select * from account; select sum(a.balance) from account a;
在另外一个session中 BEGIN; insert into account values(2, 1000); commit;
回到第一个session中 select sum(a.balance) from account a;结果并没变化 提交 select sum(a.balance) from account a;结果并没变化
总结
事务隔离级别为可重复读时,如果有索引(包括主键索引)的时候,以索引列为条件更新数据,会存在间隙锁间、行锁、页锁的问题,从而锁住一些行;如果没有索引,更新数据时会锁住整张表。
事务隔离级别为串行化时,读写数据都会锁住整张表。
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为READ COMMITTED,它能够避免脏读取,而且具有较好的并发性能。
事务的语法
1、开启事务 A、begin B、start transaction(推荐) C、begin work
2、事务回滚 rollback
3、事务提交commit
4、还原点savepoint 比如在一个事务中,不想回滚整个事务的时候,可以添加多个还原点,当想回滚部分数据的时候,只需要回滚某个还原点就行了。
|