- 浏览: 16661 次
- 性别:
- 来自: 齐齐哈尔
最新评论
对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,若没有采用必要的隔离机制,就会导致各种问题,这些病发问题可归纳为以下几类:
第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据股覆盖
脏读:一个事务读到另一事务未提交的更新数据
虚读:一个事务独到另一事务已提交的新插入的数据
不可重复读:一个事务读到另一事务已提交的更新数据
第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一事务已提交的个更新数据。
第一类丢失更新:这种并发是由于完全没有隔离事务造成的。当两个事务更新相同的数据资源,若一个事务被提交,另一个事务却被撤销,那么会连同第一个事务所做的更新也被撤销。
脏读:若第二个事务查询到第一个事务未提交的更新数据,第二个事务依据这个查询结果继续执行相关的操作,但接着第一个事务撤销了所做的更新,这导致第二个事务操纵脏数据。
虚读:由于一个事务查询到另一事务已提交的新插入的数据引起的。
不可重复读:由于一个事务查询到了另一个事务已提交的对数据的更新引起的。当第二个事务在某一时刻查询某条记录,在另一时刻在查询相同记录时,看到了第一个事务已提交的对这条记录的更新,第二个事务无法判断到底以哪一时刻查询到的记录作为计算基础。
第二类丢失更新:当两个或多个事务查询同样的记录,然后各自基于最初查询的结果更新记录时,会造成第二类丢失更新问题。每个事务都不知道其他事务的存在,最后一个事务对记录所做的更新将覆盖由其他事务对该记录所做的已提交的更新。
数据库系统的ACID特性中,隔离性就是指数据库系统必须具有隔离并发运行的各个事务的能力,使它们不会互相影响。数据库采用锁来实现事务的隔离性。锁的基本原理如下:
当一个事务访问某种数据库资源时,若执行select语句时,必须先获得共享锁;执行insert、update或delete语句时,也必须获得独占锁,此时根据已经放置在资源上的锁的类型,来决定第二个事务应该等待第一个事务接触对资源的锁定,还是可以立刻获得锁。
根据已放置在资源上的锁来决定第二个事务能否立刻获得特定类别的锁
资源上已经放置的锁 第二个事务进行读操作 第二个事务进行更新操作
无 立即获得共享锁 立即获得独占锁
共享锁 立即获得共享锁 等待第一个事务解除共享锁
独占锁 等待第一个事务解除独占锁 等待第一个事务解除独占锁
数据库系统能够锁定的资源包括:数据库、表、区域、页面、键值、行。按照锁定资源的粒度,锁可分为以下类型:
数据库级锁:锁定一战数据库表
表级锁:锁定一张数据库表
区域级锁:锁定数据库的特定区域
页面级锁:锁定数据库的特定页面
键值级锁:锁定数据库表中带有索引的一行数据
行级锁:锁定数据库表中的单行数据
锁的封锁粒度越大,事物间的隔离性就越高,事务间的并发性能就越低。
按照封锁程度,锁可分为:共享锁、独占锁和更新锁。
共享锁:用于读数据操作,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它。有以下特征:
加锁的条件:当一个事务执行select语句时,数据库系统会为这个事务分配一把共享锁,来锁定被查询的数据。
解锁的条件:在默认的情况下,数据被读取后,数据库系统立即接触共享锁。
与其它锁的兼容性:若数据资源上放置了共享锁,还能在放置共享锁和更新锁
并发性能:具有良好的并发性能,当多个事务读相同的数据时,每个事物都会获得一把共享锁
独占锁:也叫排他锁,适用于修改数据的场合。它锁定的资源,其它事务不能读取,也不能修改。独占锁具有以下特征:
加锁的条件:当一个事务执行insert、update或delete语句时,数据库系统会自动对SQL语句操纵的数据资源使用独占锁。若该数据资源已经有其它锁存在时,无法对其再放置独占锁
解锁的条件:独占锁直到事务结束后才能被解锁
兼容性:独占所不能和其他锁兼容,若数据资源上已经加了独占锁,就不能再放置其他的锁。同样,若数据资源上已经有了其他的锁,就不能再放置独占锁
并发性能:并发性能较差,只允许有一个事务访问锁定的数据,若其他事务也需要访问该数据,就必须等待,直到前一个事务结束,解除了独占锁,其他事务才有机会访问该数据
更新锁:在更新操作的初始化阶段用来锁定可能要被修改的资源,可以避免使用共享锁造成的死锁现象。
若使用共享锁,更新数据的操作分为两步:
例: update ACCOUNTS set BALANCE=9000 where ID=1
获得一个共享锁,读取ACCOUNTS表中ID为1的记录
将共享锁升级为独占锁,在执行更新操作
若同时有两个或多个事务同时更新数据,每个事务都先获得一把共享锁,在更新数据的时候,这些事务都要先将共享锁升级为独占锁。由于独占锁不能和其他锁兼容,因此每个事务都进入等待状态,等待其他事务释放共享锁,这就造成了死锁。
若使用更新锁,更新数据的操作分为以下两步:
获得一个更新锁,读取ACCONTS表中ID为1的记录
将更新所升级为独占锁,在执行更新操作
更新锁有以下特征:
加锁的条件:当一个事务执行update语句时,数据库系统会先为事务分配一把更新锁
解锁的条件:当读取数据完毕,执行更新操作时,会把更新锁升级为独占锁
与其它锁的兼容性:更新锁与共享锁是兼容的,也就是说,一个资源可以同时放置更新锁和共享锁,但最多只能防止一把更新锁
并发性能:允许多个事务同时读锁定的资源,但不允许其他事务修改它
死锁:多个事务分别锁定一个资源,又试图请求锁定对方已经锁定的资源,导致多个事务处于等待对方释放锁定资源的状态
短事务:在一个数据库事务中包含尽可能少的操作,并且在尽可能短的时间内完成。
为实现短事务,在应用程序中可以考虑使用以下策略:
若可能的话尝试把大的事务分解为多个小的事务,然后分别执行,
应该在处理事务前就准备好用户必须提供的数据,不应该在执行事务过程中,停下来查过时间等待用户输入。
为了能让用户根据实际应用的需要,在事务的隔离性与并发性之间做合理的权衡,数据库系统提供了4种事务隔离级别供用户选择。
Serializable:串行化 隔离级别最高
Repeatable Read:可重复读
Read Committed:读已提交数据
Read Uncommitted:读未提交数据 隔离级别最低
各种隔离级别所能避免的并发问题
隔离级别 第一类丢失更新 脏读 虚读 不可重复读 第二类丢失更新
Serializeble 否 否 否 否 否
Repeatable Read 否 否 是 否 否
Read Committed 否 否 是 是 是
Read Uncommitted 否 是 是 是 是
Serializable:当数据库使用Serializable隔离级别时,一个事务在执行过程中完全看不到其他事务对数据库所做的更新。当两个事务同时操纵数据库中相同的数据时,若第一个事务已经在访问数据,第二个事务只能停下来,必读等到第一个事务结束后才能恢复运行
Repeatable Read:一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,但是不能看到其他事务对已有记录的更新
Read Committed:一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,而且能看到其他事务已经提交的对已有记录的更新
Read Uncommitted:一个事务在执行过程中个可以看到其他事务没有提交的新插入的记录,而且能看到其他事务没有提交的对已有记录的更新
在mysql.exe程序中设置隔离级别
//查看当前的隔离级别
mysql>select @@tx_isolation
//设置(全局)隔离级别
mysql> set (global) transaction isolation level read committed
在应用程序中设置隔离级别
JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中以显式地设置隔离级别。每一种隔离级别都对应一个整数
1:Read Uncommitted
2:Read Committed
3:Repeatable Read
4:Seriliazable
hibernate.connection.isolation=2
当数据库系统采用Read Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题。在可能出现这种问题的场合,可以子啊应用中采用悲观锁或乐观锁来避免这类问题。
悲观锁:在应用程序中显式地为数据资源加锁。悲观锁假定当前事务操纵数据资源时,肯定还会有其他事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源。尽管悲观锁能够防止丢失更新和不可重复读这类问题,但它会影响并发性能。
乐观锁:乐观所假定当前事务操纵数据资源时,不会有其他事务同时访问该数据源,因此完全依靠数据库的隔离级别来自动管理锁的工作。
悲观锁有两种实现方式:
方式一:在应用程序中显式指定采用数据库系统的独占锁来锁定数据资源
select ... for update
在Hibernate应用中,当通过Session的get()和load()方法来加载一个对象时,可以采用一下方式声明使用悲观锁
Account account = (Account)session.get(Account.class,new Long
(1),LockMode.UPgrATE);
LockMode类表示的几种锁定模式
锁定模式 描述
LodeMode.NONE(默认) 若在Hibernate的缓存中存在对象,就直接返回该对象的引用,否则就通过select语句到数据库中加载对象 不
LockMode.READ 不管Hibernate的缓存中是否存在对象,总是通过select语句到数据库中加载对象,若映射文件中设置了版本元素,比较缓存中的对象是否和数据库中的对象的版本一致
LockMode.UPGRADE 不管Hibernate的缓存中是否存在对象,总是通过select语句到数据库中加载对象,若映射文件中设置了版本元素,比较缓存中的对象是否和数据库中的对象的版本一致,若数据库系统支持悲观锁,就执行select ... for update语句,若不支持,就执行普通的select语句
LockMode.UPGRADE_NOWAIT 和LockMode.UPGRADE具有同样的功能。nowait表明执行该select语句的事务不能立即获得悲观锁,那么不会等待其他事务释放锁,而是立刻抛出以个锁定异常
LockMode.WRITE 当Hibernate向数据库保存一个对象时,会自动使用这种锁定模式,这种锁定模式仅供Hibernate内部使用,在应用程序中不应该使用
LockMode.FORCE 强制更新数据库中对象的版本属性,从而表明当前事务已经更新了这个对象
在Hibernate提供改的版本控制功能来实现乐观锁。对象-关系映射文件中的<version>元素和<timestamp>都具有版本控制功能。<version>元素利用一个递增的整数来跟踪数据库表中记录的版本,而<timestamp>元素用时间戳来跟踪数据库表红记录的版本。版本控制不具有级联性。
使用<version>元素
1.在ACCOUNT类中定义一个代表版本信息的属性
private int version;
public int getVersion(){
return this.version;
}
public int setVersion(int version){
this.version=version;
}
2.在ACCOUNTS表中定义一个代表版本信息的字段
create table ACCOUNTS{
ID bigint not null,
NAME varchar(15),
BALANCE decimal(10,2),
VERSION integer,
primary key(ID)
}type=INNODB
3.在Account.hbm.xml文件中用<version>元素来建立Account类的version属性与ACCOUNTS表中VERSION字段的映射
<id name="id" type="long" column="ID">
<generator class="increment">
</id>
//version必须紧跟在id后面
<version name="version" column="VERSION">
在应用程序中应该捕获StaleOjectStateException,这种异常有两种处理方式:
1.自动撤销事务,
2.通知用户信息已被其他事务修改,由用户决定如何继续事务
方式二:在数据库表中增加一个表明记录状态的LOCK字段,当它取值为'Y'时,表示该记录已经被某个事务锁定,若为'N',表明该记录处于空闲状态,事务可以访问它
使用<timestamp>元素,只能精确到秒
1.在ACCOUNT类中定义一个代表版本信息的属性
private Date lastUpdateTime;
public int getLastUpdateTime(){
return this.lastUpdateTime;
}
public int setLastUpdateTime(Date lastUpdateTime){
this.lastUpdateTime=lastUpdateTime;
}
2.在ACCOUNTS表中定义一个代表版本信息的字段
create table ACCOUNTS{
ID bigint not null,
NAME varchar(15),
BALANCE decimal(10,2),
LAST_UPDATE_TIME timestamp,
primary key(ID)
}type=INNODB
3.在Account.hbm.xml文件中用<version>元素来建立Account类的version属性与ACCOUNTS表中VERSION字段的映射
<id name="id" type="long" column="ID">
<generator class="increment">
</id>
//timestamp必须紧跟在id后面
<timestamp name="lastUpdateTime" column="LAST_UPDATE_TIME">
Session的lock()方法显式对一个有利对象进行版本控制
Session session1 = sessionFactory.openSession();
tx1 = session1.beginTransaction();
Account account = (Account)session1.get(Account.class,new Long(1));
tx1.commit();
session1.close();
account.setBalance(account.getBalance()-100);
Session session2 = sessionFactory.openSession();
tx2 = session2.beginTransaction();
session2.lock(account,LockMode.READ);
tx2.commit();
session2.close();
Session的lock()方法执行以下步骤:
把Account对象与当前Session关联。
若设定了LockMode.READ模式,就比较这个Account对象的版本是否与ACCOUNTS表中对应记录的版本一致。若不一致,说明ACCOUNTS表中对饮个记录已经被其他事务修改,因此会抛出StaleObjectStateException。
Hibernate提供了实现乐观所的办法。把<class>元素的optimistic-lock属性设为all。
若把optimistic-lock的属性设为all或dirty时,必须同时把dynamic-update属性设为true。这种方法速度慢,只是用于在一个Session中加载了对象,然后在同一个Session中修改这个持久化对象的场合。
第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据股覆盖
脏读:一个事务读到另一事务未提交的更新数据
虚读:一个事务独到另一事务已提交的新插入的数据
不可重复读:一个事务读到另一事务已提交的更新数据
第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一事务已提交的个更新数据。
第一类丢失更新:这种并发是由于完全没有隔离事务造成的。当两个事务更新相同的数据资源,若一个事务被提交,另一个事务却被撤销,那么会连同第一个事务所做的更新也被撤销。
脏读:若第二个事务查询到第一个事务未提交的更新数据,第二个事务依据这个查询结果继续执行相关的操作,但接着第一个事务撤销了所做的更新,这导致第二个事务操纵脏数据。
虚读:由于一个事务查询到另一事务已提交的新插入的数据引起的。
不可重复读:由于一个事务查询到了另一个事务已提交的对数据的更新引起的。当第二个事务在某一时刻查询某条记录,在另一时刻在查询相同记录时,看到了第一个事务已提交的对这条记录的更新,第二个事务无法判断到底以哪一时刻查询到的记录作为计算基础。
第二类丢失更新:当两个或多个事务查询同样的记录,然后各自基于最初查询的结果更新记录时,会造成第二类丢失更新问题。每个事务都不知道其他事务的存在,最后一个事务对记录所做的更新将覆盖由其他事务对该记录所做的已提交的更新。
数据库系统的ACID特性中,隔离性就是指数据库系统必须具有隔离并发运行的各个事务的能力,使它们不会互相影响。数据库采用锁来实现事务的隔离性。锁的基本原理如下:
当一个事务访问某种数据库资源时,若执行select语句时,必须先获得共享锁;执行insert、update或delete语句时,也必须获得独占锁,此时根据已经放置在资源上的锁的类型,来决定第二个事务应该等待第一个事务接触对资源的锁定,还是可以立刻获得锁。
根据已放置在资源上的锁来决定第二个事务能否立刻获得特定类别的锁
资源上已经放置的锁 第二个事务进行读操作 第二个事务进行更新操作
无 立即获得共享锁 立即获得独占锁
共享锁 立即获得共享锁 等待第一个事务解除共享锁
独占锁 等待第一个事务解除独占锁 等待第一个事务解除独占锁
数据库系统能够锁定的资源包括:数据库、表、区域、页面、键值、行。按照锁定资源的粒度,锁可分为以下类型:
数据库级锁:锁定一战数据库表
表级锁:锁定一张数据库表
区域级锁:锁定数据库的特定区域
页面级锁:锁定数据库的特定页面
键值级锁:锁定数据库表中带有索引的一行数据
行级锁:锁定数据库表中的单行数据
锁的封锁粒度越大,事物间的隔离性就越高,事务间的并发性能就越低。
按照封锁程度,锁可分为:共享锁、独占锁和更新锁。
共享锁:用于读数据操作,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它。有以下特征:
加锁的条件:当一个事务执行select语句时,数据库系统会为这个事务分配一把共享锁,来锁定被查询的数据。
解锁的条件:在默认的情况下,数据被读取后,数据库系统立即接触共享锁。
与其它锁的兼容性:若数据资源上放置了共享锁,还能在放置共享锁和更新锁
并发性能:具有良好的并发性能,当多个事务读相同的数据时,每个事物都会获得一把共享锁
独占锁:也叫排他锁,适用于修改数据的场合。它锁定的资源,其它事务不能读取,也不能修改。独占锁具有以下特征:
加锁的条件:当一个事务执行insert、update或delete语句时,数据库系统会自动对SQL语句操纵的数据资源使用独占锁。若该数据资源已经有其它锁存在时,无法对其再放置独占锁
解锁的条件:独占锁直到事务结束后才能被解锁
兼容性:独占所不能和其他锁兼容,若数据资源上已经加了独占锁,就不能再放置其他的锁。同样,若数据资源上已经有了其他的锁,就不能再放置独占锁
并发性能:并发性能较差,只允许有一个事务访问锁定的数据,若其他事务也需要访问该数据,就必须等待,直到前一个事务结束,解除了独占锁,其他事务才有机会访问该数据
更新锁:在更新操作的初始化阶段用来锁定可能要被修改的资源,可以避免使用共享锁造成的死锁现象。
若使用共享锁,更新数据的操作分为两步:
例: update ACCOUNTS set BALANCE=9000 where ID=1
获得一个共享锁,读取ACCOUNTS表中ID为1的记录
将共享锁升级为独占锁,在执行更新操作
若同时有两个或多个事务同时更新数据,每个事务都先获得一把共享锁,在更新数据的时候,这些事务都要先将共享锁升级为独占锁。由于独占锁不能和其他锁兼容,因此每个事务都进入等待状态,等待其他事务释放共享锁,这就造成了死锁。
若使用更新锁,更新数据的操作分为以下两步:
获得一个更新锁,读取ACCONTS表中ID为1的记录
将更新所升级为独占锁,在执行更新操作
更新锁有以下特征:
加锁的条件:当一个事务执行update语句时,数据库系统会先为事务分配一把更新锁
解锁的条件:当读取数据完毕,执行更新操作时,会把更新锁升级为独占锁
与其它锁的兼容性:更新锁与共享锁是兼容的,也就是说,一个资源可以同时放置更新锁和共享锁,但最多只能防止一把更新锁
并发性能:允许多个事务同时读锁定的资源,但不允许其他事务修改它
死锁:多个事务分别锁定一个资源,又试图请求锁定对方已经锁定的资源,导致多个事务处于等待对方释放锁定资源的状态
短事务:在一个数据库事务中包含尽可能少的操作,并且在尽可能短的时间内完成。
为实现短事务,在应用程序中可以考虑使用以下策略:
若可能的话尝试把大的事务分解为多个小的事务,然后分别执行,
应该在处理事务前就准备好用户必须提供的数据,不应该在执行事务过程中,停下来查过时间等待用户输入。
为了能让用户根据实际应用的需要,在事务的隔离性与并发性之间做合理的权衡,数据库系统提供了4种事务隔离级别供用户选择。
Serializable:串行化 隔离级别最高
Repeatable Read:可重复读
Read Committed:读已提交数据
Read Uncommitted:读未提交数据 隔离级别最低
各种隔离级别所能避免的并发问题
隔离级别 第一类丢失更新 脏读 虚读 不可重复读 第二类丢失更新
Serializeble 否 否 否 否 否
Repeatable Read 否 否 是 否 否
Read Committed 否 否 是 是 是
Read Uncommitted 否 是 是 是 是
Serializable:当数据库使用Serializable隔离级别时,一个事务在执行过程中完全看不到其他事务对数据库所做的更新。当两个事务同时操纵数据库中相同的数据时,若第一个事务已经在访问数据,第二个事务只能停下来,必读等到第一个事务结束后才能恢复运行
Repeatable Read:一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,但是不能看到其他事务对已有记录的更新
Read Committed:一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,而且能看到其他事务已经提交的对已有记录的更新
Read Uncommitted:一个事务在执行过程中个可以看到其他事务没有提交的新插入的记录,而且能看到其他事务没有提交的对已有记录的更新
在mysql.exe程序中设置隔离级别
//查看当前的隔离级别
mysql>select @@tx_isolation
//设置(全局)隔离级别
mysql> set (global) transaction isolation level read committed
在应用程序中设置隔离级别
JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中以显式地设置隔离级别。每一种隔离级别都对应一个整数
1:Read Uncommitted
2:Read Committed
3:Repeatable Read
4:Seriliazable
hibernate.connection.isolation=2
当数据库系统采用Read Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题。在可能出现这种问题的场合,可以子啊应用中采用悲观锁或乐观锁来避免这类问题。
悲观锁:在应用程序中显式地为数据资源加锁。悲观锁假定当前事务操纵数据资源时,肯定还会有其他事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源。尽管悲观锁能够防止丢失更新和不可重复读这类问题,但它会影响并发性能。
乐观锁:乐观所假定当前事务操纵数据资源时,不会有其他事务同时访问该数据源,因此完全依靠数据库的隔离级别来自动管理锁的工作。
悲观锁有两种实现方式:
方式一:在应用程序中显式指定采用数据库系统的独占锁来锁定数据资源
select ... for update
在Hibernate应用中,当通过Session的get()和load()方法来加载一个对象时,可以采用一下方式声明使用悲观锁
Account account = (Account)session.get(Account.class,new Long
(1),LockMode.UPgrATE);
LockMode类表示的几种锁定模式
锁定模式 描述
LodeMode.NONE(默认) 若在Hibernate的缓存中存在对象,就直接返回该对象的引用,否则就通过select语句到数据库中加载对象 不
LockMode.READ 不管Hibernate的缓存中是否存在对象,总是通过select语句到数据库中加载对象,若映射文件中设置了版本元素,比较缓存中的对象是否和数据库中的对象的版本一致
LockMode.UPGRADE 不管Hibernate的缓存中是否存在对象,总是通过select语句到数据库中加载对象,若映射文件中设置了版本元素,比较缓存中的对象是否和数据库中的对象的版本一致,若数据库系统支持悲观锁,就执行select ... for update语句,若不支持,就执行普通的select语句
LockMode.UPGRADE_NOWAIT 和LockMode.UPGRADE具有同样的功能。nowait表明执行该select语句的事务不能立即获得悲观锁,那么不会等待其他事务释放锁,而是立刻抛出以个锁定异常
LockMode.WRITE 当Hibernate向数据库保存一个对象时,会自动使用这种锁定模式,这种锁定模式仅供Hibernate内部使用,在应用程序中不应该使用
LockMode.FORCE 强制更新数据库中对象的版本属性,从而表明当前事务已经更新了这个对象
在Hibernate提供改的版本控制功能来实现乐观锁。对象-关系映射文件中的<version>元素和<timestamp>都具有版本控制功能。<version>元素利用一个递增的整数来跟踪数据库表中记录的版本,而<timestamp>元素用时间戳来跟踪数据库表红记录的版本。版本控制不具有级联性。
使用<version>元素
1.在ACCOUNT类中定义一个代表版本信息的属性
private int version;
public int getVersion(){
return this.version;
}
public int setVersion(int version){
this.version=version;
}
2.在ACCOUNTS表中定义一个代表版本信息的字段
create table ACCOUNTS{
ID bigint not null,
NAME varchar(15),
BALANCE decimal(10,2),
VERSION integer,
primary key(ID)
}type=INNODB
3.在Account.hbm.xml文件中用<version>元素来建立Account类的version属性与ACCOUNTS表中VERSION字段的映射
<id name="id" type="long" column="ID">
<generator class="increment">
</id>
//version必须紧跟在id后面
<version name="version" column="VERSION">
在应用程序中应该捕获StaleOjectStateException,这种异常有两种处理方式:
1.自动撤销事务,
2.通知用户信息已被其他事务修改,由用户决定如何继续事务
方式二:在数据库表中增加一个表明记录状态的LOCK字段,当它取值为'Y'时,表示该记录已经被某个事务锁定,若为'N',表明该记录处于空闲状态,事务可以访问它
使用<timestamp>元素,只能精确到秒
1.在ACCOUNT类中定义一个代表版本信息的属性
private Date lastUpdateTime;
public int getLastUpdateTime(){
return this.lastUpdateTime;
}
public int setLastUpdateTime(Date lastUpdateTime){
this.lastUpdateTime=lastUpdateTime;
}
2.在ACCOUNTS表中定义一个代表版本信息的字段
create table ACCOUNTS{
ID bigint not null,
NAME varchar(15),
BALANCE decimal(10,2),
LAST_UPDATE_TIME timestamp,
primary key(ID)
}type=INNODB
3.在Account.hbm.xml文件中用<version>元素来建立Account类的version属性与ACCOUNTS表中VERSION字段的映射
<id name="id" type="long" column="ID">
<generator class="increment">
</id>
//timestamp必须紧跟在id后面
<timestamp name="lastUpdateTime" column="LAST_UPDATE_TIME">
Session的lock()方法显式对一个有利对象进行版本控制
Session session1 = sessionFactory.openSession();
tx1 = session1.beginTransaction();
Account account = (Account)session1.get(Account.class,new Long(1));
tx1.commit();
session1.close();
account.setBalance(account.getBalance()-100);
Session session2 = sessionFactory.openSession();
tx2 = session2.beginTransaction();
session2.lock(account,LockMode.READ);
tx2.commit();
session2.close();
Session的lock()方法执行以下步骤:
把Account对象与当前Session关联。
若设定了LockMode.READ模式,就比较这个Account对象的版本是否与ACCOUNTS表中对应记录的版本一致。若不一致,说明ACCOUNTS表中对饮个记录已经被其他事务修改,因此会抛出StaleObjectStateException。
Hibernate提供了实现乐观所的办法。把<class>元素的optimistic-lock属性设为all。
若把optimistic-lock的属性设为all或dirty时,必须同时把dynamic-update属性设为true。这种方法速度慢,只是用于在一个Session中加载了对象,然后在同一个Session中修改这个持久化对象的场合。
发表评论
-
Hibernate_11
2014-09-22 17:43 421缓存的物理介质通常是内存,而永久性数据存储源的物理介质通常是硬 ... -
Hibernate_9
2014-09-19 11:25 385数据库事务必须具备ACID特征,ACID是Atomic(原子性 ... -
Hibernate_8
2014-09-18 16:37 427Hibernate可以与任何一种Java应用的运行环境集成。J ... -
Hibernate_7
2014-09-17 16:55 704JDBC API提供了一种可滚动的结果集,它是利用数据库系统中 ... -
Hibernate_6
2014-09-15 17:51 533Java的集合类位于java.util包中,Java集合中存放 ... -
Hibernate_5
2014-09-12 19:22 410Hibernate映射类型分为两种:内置映射类型和客户化映射类 ... -
Hibernate_4
2014-09-06 10:39 466当程序通过Hibernate来加载、保存、更新或删除对象时,会 ... -
Hibernate_3
2014-09-04 17:52 364这几天心情不好,效率 ... -
Hibernate_2
2014-09-04 09:12 377hbm2ddl工具位于Hibernate核 ... -
Hibernate_1
2014-09-02 22:10 387分层体系结构: 逻辑上一般分为三层:表述层(提供与用户交互的界 ...
相关推荐
【hibernate_day02笔记】的文档主要涵盖了学习Hibernate框架的基础内容,包括ORM思想、Hibernate入门案例、配置文件解析、核心API的使用等。以下是详细的讲解: **ORM思想**: ORM(Object-Relational Mapping)即...
8. **hibernate_07_003_MTO_SXGL_Category** 和 **hibernate_10_001_composition**: "MTO"可能表示一对多(ManyToOne)关系,"Category"可能是类别或分类的含义。而"composition"则指的是组合关系,这是对象关联的...
hibernate_day03笔记
在Java世界中,Hibernate是一个非常流行的ORM(对象关系映射)框架,它允许开发者用面向对象的方式处理数据库操作。在大型应用中,为了提高性能,有效地管理数据访问,Hibernate引入了缓存机制。本篇文章将深入探讨...
Hibernate_Tools_for_Eclipse插件的安装和使用 Hibernate_Tools_for_Eclipse插件是 Eclipse 中的一个插件,用于支持 Hibernate 开发。它提供了许多有用的功能,如Hibernate配置文件的创建、实体类的生成、SQL语句...
hibernate_day04笔记
标题"DMS.rar_dms_hibernate_myeclipse hibernate_mysql hibernate_struts"表明这是一个与数据库管理系统(DMS)相关的项目,使用了Hibernate ORM框架,MyEclipse作为开发环境,并结合了MySQL数据库和Struts框架。...
标题"Hibernate_QBC和Hibernate_QBE"提及了两个关于Hibernate的查询方式,即Query By Criteria(QBC)和Query By Example(QBE)。Hibernate是Java领域中一个广泛使用的对象关系映射(ORM)框架,它允许开发者以面向...
java_hibernate_day01.pdf
java_hibernate_day02.pdf
10. **Criteria API与DetachedCriteria**:Criteria API用于在Session中执行查询,而DetachedCriteria则允许在Session之外构建查询条件,再在Session中执行。 11. **Criteria与HQL的比较**:两者都是ORM查询方式,...
【hibernate_second2项目源码】是一个基于Hibernate框架的示例项目,它在前一个项目的基础上进行了扩展,特别引入了级联保存的功能。在这个项目中,我们将深入探讨Hibernate的级联操作,以及如何实现数据的级联保存...
【标题】"hibernate_day4_hibernate_sick7s3_" 暗示这是一个关于Hibernate框架的学习资源,可能是第四天的学习内容,专注于"hibernate_sick7s3"这个特定主题。在这个主题下,可能涉及了更深入或者特别的使用场景或...
Struts和Hibernate是Java开发中两个非常重要的框架,它们在构建Web应用程序,特别是大型的、数据驱动的BBS(Bulletin Board System,论坛)系统时,起到了核心作用。本压缩包"struts_hibernate_bbs.rar"包含了一个...
10. **事务处理**:介绍了Hibernate如何配合JTA或JDBC进行事务控制,确保数据的一致性。 11. **关联映射**:包括一对一、一对多、多对一、多对多等各种关联类型,以及懒加载和立即加载策略。 12. **集合映射**:...
【标题】"test_hibernate_oracle_03.zip"是一个包含使用Hibernate框架与Oracle数据库进行CRUD操作(创建、读取、更新、删除)的示例项目。这个压缩包提供了有关如何通过Hibernate在Oracle数据库中执行插入、查询、...
### MyEclipse与Hibernate快速入门知识点详解 #### 一、前言 本篇文章将详细介绍如何使用MyEclipse Enterprise Workbench进行Hibernate开发的基础特征、概念和技术。通过构建一个简单的Java Hibernate应用来逐步...
JavaEE源代码 Hibernate_SpringJavaEE源代码 Hibernate_SpringJavaEE源代码 Hibernate_SpringJavaEE源代码 Hibernate_SpringJavaEE源代码 Hibernate_SpringJavaEE源代码 Hibernate_SpringJavaEE源代码 Hibernate_...
JavaEE源代码 Hibernate_mappingJavaEE源代码 Hibernate_mappingJavaEE源代码 Hibernate_mappingJavaEE源代码 Hibernate_mappingJavaEE源代码 Hibernate_mappingJavaEE源代码 Hibernate_mappingJavaEE源代码 ...