一、事务的并发问题
在实际应用中,数据库是要被I多个用户共同访问的,在多个事务同时使用相同的数据时,可能会发生并发的问题,具体为:
- 脏读:一个事务读取到另一个事务未提交的数据。
- 不可重复读:一个事务对同一行数据重复读取两次,但是得到了不同的结果。
- 虚读:一个事务连续两次在数据库进行同样条件的查询,但是第二次查询结果包含了第一次查询中未出现的数据。(注意与不可重复读的区别)
- 更新丢失:两个事物同时更新一行数据,后提交(或撤销)的事务将前面事务提交的数据都覆盖了。
(1)第一类丢失更新:是由于后面事务撤销将前面事务修改的数据覆盖了
(2)第二类丢失更新:是由于后面事务更新将前面事务修改的数据覆盖了
二、事务的隔离级别
1、读未提交(1级,可防止更新丢失):当一个事务进行写(更新)数据,则另外一个事务不允许同时进行写(更新)数据,但允许其他事务进行读数据,即使是未提交的 (但这个不能防止脏读)
更新丢失是因为一个事务开始进行写事务,另一个事务也可以进行写事务导致的。
2、读已提交(2级,可防止更新丢失、脏读):读取数据的事务允许其他事务继续读取该数据,但是未提交的写事务将会禁止其他事务访问改行。
脏读是由于读到未提及的数据
3、可重复读(4级,可防止不可重复读、脏读):读取数据的事务禁止写事务,写事务将禁止其他任何事务。
不可重复读是一个事务对一行数据重复读取两次,但是得到不同的结果;
脏读是读到未提交的数据
4、序列化(8级,防止一切并发问题):提供严格的事务隔离。事务只能一个接着一个执行,不能并发执行
简单总结:
事务并发问题:
(1)脏读
(2)不可重复读
(3)虚读
(4)更新丢失
事务隔离级别:
(1)读未提交
(2)读已提交
(3)可重复读
(4)序列化
三、Hibernate的事务配置
在hibernate.cfg.xml的标签配置:
使用本地事务还是全局事务,参数是:
hibernate.current_session_context_class
值:thread(本地事务)、jta(全局事务)
设置事务隔离级别,参数是:
hibernate.connection.isolation
四、Hibernate事务处理方式之悲观锁和乐观锁
当多个事务同时访问数据库中的相同数据时,如果没有采取必要的隔离措施,那么可以采用悲观锁或者是乐观锁对其进行控制。
悲观锁:悲观地认为总是会有其他事务回来操作同一数据,因此在这个数据处理过程中,将会把数据处于锁定状态。比如读取数据时:
User user = (User)session.get(User.class, "1212312", LockMode.UPGRADE)
乐观锁:认为事务同时操作同一个数据的情况很少发生,所以乐观锁不做数据库层次的锁定,而是基于数据版本标识实现应用程序级别上的锁定机制。
原理:数据版本标识,是指通过为数据表增加一个“version”字段,实现在读取数据时,将版本号一同独处,之后更新次数据时,将此版本号加一;在提交数据时,将现有的版本号与数据表对应的记录的版本号进行对比,如果提交数据的版本号大于数据表中的版本号,则允许更新数据,否则禁止更新数据。