数据库事务与并发及锁的问题
对于事务与并发以前了解了下,也以为自己知道了是怎么回事。可是最近又被这事务及并发搞得晕乎了(最近脑袋很不好使,缺氧啊),事务为了解决什么?多个事务的并发又有什么问题?于是google了,做个笔记,以后忘记了好方便查看。
一直以来了解得并不清楚,平常我们用得最多的可能就是涉及到两个表数据操作时为了保证数据的一致性,就会在这些操作时加上事务,因为我们知道事务具有原子性、一致性。
原子性: 事务中的操作为一个整体, 要么都做, 要么都不做. 即一旦事务出错, 就回滚事务.
一致性: 事务开始前, 数据库中的数据具有一致性, 事务结束时, 数据库中的数据仍具有一致性.
隔离性: 一个事务不能被另一个事务干扰, 退一步讲, 一个事务被另一个事务干扰的话, 为了防止出错, 它就会回滚.
持久性: 事务完成后, 就不能再回滚了, 对数据库的改动是永久的.
事务所能解决也就是一致性,而不能解决多个事务并发带来的数据的不正确的问题。比如两个并发事务同时对一条记录进行操作,后提交的事务的更新会覆盖前提交的事务。比如购买扣费时我们得判断用户的金额大于物品的价格,然后扣除。
Select gold from use where id = 1000; //gold = 1000, price = 1000
If(gold >= price){//若两并发此时判断都为真,都会扣除最终数据会变成-1000
Update user set gold = gold – price where id = 1000;
}
当并发时这代码就会有问题。
可以用乐观锁与悲观锁来解决此问题。
1. 乐观锁将update语句更改为
update user set gold = gold – price where id = 1000 and gold = selectGold
当影响的行不为1时表示数据已经被其他事务更改过了。可以抛出异常,最好还得有页面提示用户。
不过一般的乐观锁都是每个数据行有一个版本号或更改的时间戳,每个更新操作前select 出来,更新时带上条件并要更改版本号或时间戳。
2. 悲观锁将select改为
select gold from user where id=1000 for update
这样多线程并发时就在阻塞在select上, 不会进行下一步的操作, 可这也加大的锁的区域影响了并发性能,一般不建议作用这种形式。