Oracle的锁是行锁,实现方式是在块上进行标识锁状态,因此几乎没有相关的开销,锁定1行和锁定1百万行的开销几乎是一样的。
由于Oracle的并发和多版本的实现,存在丢失更新的文件,需要代码手工去避免,这也是出于性能的考虑,让Oracle天然具有读写分离的特性。
悲观锁: select for update nowait.
nowait的区别在于其他线程对于相同资源的访问并不会进行等待,而是立刻返回。
乐观锁: 表里面加上versionID来控制不同线程的修改。
或者使用虚拟列,这个虚拟列是Hash值,基本不会带来任何开销
select name, location, ora_hash(name||'\'||location) from people
死锁:
头号原因是: 外键没有加索引
父子表关系的情形中,删除主表的PrimaryKey行,子表会有升级到表锁。
Scenario:
先修改子表,锁住一行记录
先修改子表,锁住一行记录
然后修改父表,删除一行记录, 这时需要再次锁定子表全表, 由于子表已经锁住,这样就形成了死锁。
所以外键加索引是非常重要的。
第二原因: 位图索引遭遇到并发更新
位图索引是基于全表数据的索引, 所以更新任意一行都是锁住全部索引
整体来说, Oracle发生死锁一般都是被升级到了表锁
Latch
用于协调共享数据,对象和文件的多用户访问。 分配到了Latch才可以访问数据, 如果没有分配到,那么会话会睡眠一段时间,然后再次尝试。对Latch的竞争会导致性能下降。
对于Oracle来说,没有用prepareStatement而导致的硬解析会导致大量的Latch被占用,从而让数据库的整体性能下降数量级。