几种并发问题:
第一类丢失更新;
完全没有隔离事务;如果一个事务被提交,另一个撤销,那么连同第一个事务所做的更新也被撤销
脏读:
第二个事务查询到第一个事务未提交的更新数据,第二个事务依旧根据这个查询结果继续执行相关的操作,但接着第一个事务撤销了所做的更新,这会导致第二个事务操纵脏数据;脏读即没有读到最新更新的数据虚读:
事务查询到了另一个事务已提交的新插入的数据引起的不可重复读:
由一个事务查询到另一个事务已经提交的对数据的更新引起的;即第二个事务无法判断哪一时刻查询到的记录作为计算的基础;任何时候查询到的数据都可能立刻被其他事务更新;
第二类丢失更新:
当两个或多个事务查询同样的记录,各自基于该记录更新该记录时发生,最后一个事务对记录所做的更新将覆盖由其他记录对该记录的更新
hibernate锁
给选定的数据上锁,便无法被其他程序修改;
悲观锁:Pessimistic Locking;
设置了加锁后,lazy失效;
在进行操作的时候,将数据锁住,等自己操作完成了,才能被其他人操作。认为一定有人来抢资源。
例如list(),会把这个 对象映射的数据库表锁住,没有人能够操作。
锁一条记录的话可以考虑;
像oracle,锁的记录多了之后,锁会升级,会把整个表全都锁住;
使用get(xx,xx,LockModel),list().setLockModel
总体来说不建议;
乐观锁:Optimistic Locking;
增加一个版本标识,version字段;
读取数据时,将版本号一起读出
假如两个人同时操作,一个人操作成功,那么另外一个必然失败,此时就需要重读数据。
使用乐观锁,要在对象里面加一条字段
private long ver//乐观锁的版本号
并且数据库里面要加上一个字段 f_ver;
建立映射
改了哪些值,就把哪些值当前数据先查到,然后只有在这个数据状态下;
锁的使用如下
<class name="" table=""
optimistic-lock ="version">
<!--
optimistic-lock="dirty";
这样的话,就达到了先确认数据状态,然后再进行修改的状况;即脏数据检测字段,比较推荐使用version
-->
<version name="ver" column="f_ver" type="Integer"/>
</class>
<version name="ver" column="f_ver"></version>
把乐观锁类型设置为检测dirty模式
<class optimistic-lock="dirty" dynamic-update="true">
这样,当更新数据时,sql语句会先查询该数据的状态,假如有一个操作修改了这个状态,另外一个语句查出来的状态与想要的状态不符合,就会丢出一个错误;
Row was updated or deleted by another transaction
时间戳:
TimeStamp,
对应的,在配置里面
<timestamp name="ts" colomn="f_ts">
因为时间戳在随时变化,一般来说就是系统当前值,精确到秒
按时间来做并发精确度的话,并不是太好。
但是有个特性,使用时间戳更新数据会很快;
时间戳跟version差不多,修改后更新时间戳,更新成功后同时留下最后更新时间。
以上是短锁,有效时限不是太长。
长事务锁: 在编辑内容过程时,时间可能会很长,研究长锁;
抓取策略
fetch=”select”,查询出来的对象的子数据并不封装进对象里面,
“join” 把查询出来的数据顺便封装进对象里面,这样要读取对象的数据的时候,就不会再进行sql,但此时是进行的联表查询,联表查询效率较低,除非当这个数据已经存在了缓存中,那么速度就会很快,但假如对象的该数据内容比较多,反而可能会导致效率不高;
连接池:
获得连接需要耗费时间, 所以可以考虑先建立不少连接,放进连接池,需要的话就直接从连接池中取得连接;就节约了创立和结束连接的时间;
c3p0;
proxool;
Druid连接池(阿里巴巴);