1. 事务介绍:
1.1. 事务的定义:
事务就是指作为单个逻辑工作单元执行的一组数据操作,这些操作要么必须全部成功,要么必须全部失败,以保证数据的一致性和完整性。
1.2. 事务具有ACID属性:
o 原子性(Atomic):事务由一个或多个行为绑在一起组成,好像是一个单独的工作单元。原子性确保在事务中的所有操作要么都发生,要么都不发生。
o 一致性(Consistent):一旦一个事务结束了(不管成功与否),系统所处的状态和它的业务规则是一致的。即数据应当不会被破坏。
o 隔离性(Isolated):事务应该允许多个用户操作同一个数据,一个用户的操作不会和其他用户的操作相混淆。
o 持久性(Durable):一旦事务完成,事务的结果应该持久化。
事务的ACID特性是由关系数据库管理系统(RDBMS)来实现的。
o 数据库管理系统采用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。
o 数据库管理系统采用锁机制来实现事务的隔离性。当多个事务同时更新数据库相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。
2. 数据库事务声明:
数据库系统的客户程序只要向数据库系统声明了一个事务,数据库系统就会自动保证事务的ACID特性。在JDBC API中,java.sql.Connection类代表一个数据库连接。它提供了以下方法控制事务:
1. setAutoCommit(Boolean autoCommit):设置是否自动提交事务。
2. commit():提交事务。
3. rollback():撤销事务。
2.1. JDBC API声明事务的示例代码如下:
Connection = null;
PreparedStatement pstmt = null;
try{
con = DriverManager.getConnection(dbUrl, username, password);
//设置手工提交事务模式
con.setAutoCommit(false);
pstmt = ……;
pstmt.executeUpdate();
//提交事务
con.commit();
}catch(Exception e){
//事务回滚
con.rollback();
…..
} finally{
…….
}
Hibernate对JDBC进行了轻量级的对象封装,Hibernate本身在设计时并不具备事务处理功能,平时所用的Hibernate的事务,只是将底层的JDBCTransaction或者JTATransaction进行了一下封装,在外面套上Transaction和Session的外壳,其实底层都是通过委托底层的JDBC或JTA来实现事务的调度功能。
2.2. Hibernate中使用JDBC事务:
要在Hibernate中使用事务,可以配置Hibernate事务为JDBCTransaction或者JTATransaction,这两种事务的生命周期不一样,可以在hibernate.cfg.xml中指定使用的是哪一种事务。以下配置为使用JDBC事务。注:如果不进行配置,Hibernate也会默认使用JDBC事务。
<session-factory>
……
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>
……
</session-factory>
Hibernate 使用JDBC transaction处理方式如下所示:
Transaction tx = null;
try {
tx = sess.beginTransaction();
// do some work
...
tx.commit();
}
catch (RuntimeException e) {
if (tx != null) tx.rollback();
throw e; // or display error message
}
finally {
sess.close();
}
2.3. Hibernate中使用JTA事务:
JTA(java Transaction API)是事务服务的JavaEE解决方案。本质上,它是描述事务接口的JavaEE模型的一部分。
JTA具有的3个接口:UserTransaction接口、TransactionManager接口和Transaction接口,这些接口共享公共的事务操作。UserTransaction能够执行事务划分和基本的事务操作,TransactionManager能够执行上下文管理。
在一个具有多个数据库的系统中,可能一个程序将会调用几个数据库中的数据,需要一种分布事务,或者准备用JTA来管理Session的长事务,那么就需要使用JTATransaction。
在hibernate.cfg.xml中配置JTA事务管理:
<session-factory>
……
<property name="hibernate.transaction.factory_class">
org.hibernate.transaction.JTATransactionFactory
</property>
……
</session-factory>
下面是一个实际应用的JTA示例:
// BMT(bean管理事务) idiom with getCurrentSession()
try {
UserTransaction tx = (UserTransaction)new InitialContext()
.lookup("java:comp/UserTransaction");
tx.begin();
// Do some work on Session bound to transaction
factory.getCurrentSession().load(...);
factory.getCurrentSession().persist(...);
tx.commit();
}
catch (RuntimeException e) {
tx.rollback();
throw e; // or display error message
}
在CMT方式下,事务声明是在session bean的部署描述符中,而不需要编程。 因此,代码被简化为:
// CMT idiom
Session sess = factory.getCurrentSession();
// do some work
...
. 多个事务并发引起的问题:
3.1. 第一类丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
3.2. 脏读:一个事务读到另一个事务未提交的更新数据。
3.3. 幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
3.4. 不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。
3.5. 第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一个事务已提交的更新数据。
4. 事务隔离级别:
为了解决多个事务并发会引发的问题。数据库系统提供了四种事务隔离级别供用户选择。
o Serializable:串行化。隔离级别最高
o Repeatable Read:可重复读。
o Read Committed:读已提交数据。
o Read Uncommitted:读未提交数据。隔离级别最差。
数据库系统采用不同的锁类型来实现以上四种隔离级别,具体的实现过程对用户是透明的。用户应该关心的是如何选择合适的隔离级别。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读,而且具有较好的并发性能。
每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中可以显示地设置隔离级别。每一种隔离级别对应着一个正整数。
Read Uncommitted: 1
Read Committed: 2
Repeatable Read: 4
Serializable: 8
在hibernate.cfg.xml中设置隔离级别如下:
session-factory>
<!-- 设置JDBC的隔离级别 -->
<property name="hibernate.connection.isolation">2</property>
</session-factory>
设置之后,在开始一个事务之前,Hibernate将为从连接池中获得的JDBC连接设置级别。需要注意的是,在受管理环境中,如果Hibernate使用的数据库连接来自于应用服务器提供的数据源,Hibernate不会改变这些连接的事务隔离级别。在这种情况下,应该通过修改应用服务器的数据源配置来修改隔离级别。
5. 并发控制:
当数据库系统采用Red Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题,在可能出现这种问题的场合。可以在应用程序中采用悲观锁或乐观锁来避免这类问题。
5.1. 乐观锁(Optimistic Locking):
乐观锁假定当前事务操纵数据资源时,不会有其他事务同时访问该数据资源,因此不作数据库层次上的锁定。为了维护正确的数据,乐观锁使用应用程序上的版本控制(由程序逻辑来实现的)来避免可能出现的并发问题。
唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、 或者时间戳来检测更新冲突(并且防止更新丢失)。
5.1.1. 使用版本检查(<version>):
Hibernate中通过版本号检查来实现后更新为主,这也是Hibernate推荐的方式。在数据库表中加入一个version(版本)字段,在读取数据时连同版本号一起读取,并在更新数据时比较版本号与数据库表中的版本号,如果等于数据库表中的版本号则予以更新,并递增版本号,如果小于数据库表中的版本号就抛出异常。
使用<version>进行版本控制的步骤:
1) 在持久化类中定义一个代表版本号的属性:
package org.qiujy.domain.versionchecking;
import java.util.Date;
public class Product implements java.io.Serializable{
private Long id ;
/** 版本号 */
private int version;
private String name; //产品名
private String description; //描述--简介
private Double unitCost; //单价
private Date pubTime; //生产日期
public Product(){}
//以下为getter()和setter()方法
}
2) 在Product.hbm.xml文件中用<version>元素来建立Product类的version属性与表中version字段的映射。
3) Hibernate在其数据库访问引擎中内置了乐观锁定实现,默认也是选择version方式作为Hibernate乐观锁定实现机制。所以,在配置文件及程序中可以不作其它设置。按往常一样写操作代码。
package org.qiujy.domain.versionchecking;
import java.util.Date;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.qiujy.common.HibernateSessionFactory;
public class TestVersionChecking {
public static void main(String[] args) {
Product prod = new Product();
prod.setName("IBM thinkPad T60");
prod.setUnitCost(new Double(26000.00));
prod.setDescription("笔记本电脑");
prod.setPubTime(new Date());
//test start.......
Session session = HibernateSessionFactory.getSession();
Transaction tx =null;
try{
tx = session.beginTransaction();
session.save(prod);
tx.commit();
}catch(HibernateException e){
if(tx != null){
tx.rollback();
}
e.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
//进行更新 测试..
prod.setDescription("新款的");
Session session2 = HibernateSessionFactory.getSession();
Transaction tx2 =null;
try{
tx2 = session2.beginTransaction();
session2.update(prod);
tx2.commit();
}catch(HibernateException e){
if(tx2 != null){
tx2.rollback();
}
e.printStackTrace();
}finally{
HibernateSessionFactory.closeSession();
}
}
}
新增数据时产生的SQL是:
insert into products (version, name, description, unitCost, pubTime)
values(?, ?, ?, ?, ?)
程序无需为Product对象的version属性显示赋值,当持久化一个Product对象时,Hibernate会自动为它赋初始值为0。
更新数据时产生的SQL是:
update
products
set
version=?,
name=?,
description=?,
unitCost=?,
pubTime=?
where
id=?
and version=?
当Hibernate更新一个Product对象,会根据它的id和version属性到相应的数据库表中定位匹配的记录,如果存在这条匹配的记录,就更新记录,并且把version字段的值加1。若找不到匹配的记录,此时Hibernate会抛出StaleObjectStateException。
需要注意的是,由于乐观锁定是使用系统中的程序来控制,而不是使用数据库中的锁定机制,因而如果有人故意自行更新版本信息来超过检查,则锁定机制就无效。所以建议把持久化类中的version的get方法设置为private的。
5.1.2. 使用时间戳(<timestamp>):
跟版本检查的用法相似。不再多说。
5.2. 悲观锁(Pessimistic Locking):
悲观锁假定当前事务操纵数据资源时,肯定还会有其他事务同时访问该数据资源,为了避免当前事务的操作受到干扰,先锁定资源。尽管悲观锁能够防止丢失更新和不可重复读这类并发问题,但是它影响并发性能,因此应该很谨慎地使用悲观锁。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1874599
分享到:
相关推荐
本文将深入探讨Hibernate中的事务和并发控制,这对于开发高效、稳定的数据库应用至关重要。 首先,我们来理解Hibernate中的事务管理。在数据库操作中,事务是保证数据一致性的重要手段。一个事务包含了一组数据库...
事务和并发控制是数据库管理中的核心概念,特别是在使用ORM框架如Hibernate时,理解它们的工作原理至关重要。本文将深入探讨Hibernate中的事务管理和并发控制。 首先,事务是数据库操作的基本单位,它保证了数据的...
#### 二、Hibernate事务管理机制 Hibernate 本身不实现事务逻辑,而是依赖于底层的数据源(JDBC 或 JTA)来实现事务管理。这意味着,当你使用 Hibernate 进行数据操作时,所涉及的事务要么基于 JDBC 的事务管理,要么...
《课程hibernate的事务和并发》主要探讨了在Hibernate框架中如何管理和处理事务以及并发控制。Hibernate作为一款流行的Java ORM(对象关系映射)工具,其事务处理和并发控制策略对于开发高效、稳定的数据库应用至关...
《Hibernate的事务和并发资料》深入探讨了在Java应用程序中使用Hibernate进行事务管理和并发控制的关键概念。Hibernate作为一款流行的ORM框架,它简化了与数据库的交互,但同时也需要开发者理解其背后的事务处理机制...
描述:本文深入解析了Hibernate框架中事务管理和并发控制的核心概念及其实现机制,基于一份详尽的“hibernate详细解析.pdf”文档,覆盖了非托管环境、JTA环境下的事务处理以及如何在不同场景下确保数据的一致性和...
在Hibernate中,事务、并发控制和缓存管理是至关重要的概念,它们极大地影响了应用程序的性能和数据一致性。 一、Hibernate事务管理 在数据库操作中,事务确保了数据的一致性和完整性。Hibernate提供了四种事务隔离...
本文将深入探讨Hibernate中的版本管理机制及其在控制事务并发中的作用。 一、Hibernate版本管理机制 1. 版本号原理:Hibernate使用乐观锁策略,即假定在正常情况下,同一时间只有一个用户修改数据,当多个用户同时...
本教程主要聚焦于Hibernate中的事务并发处理,包括悲观锁和乐观锁两种策略,这对于我们理解如何在高并发环境中确保数据的一致性和完整性至关重要。 首先,事务是数据库操作的基本单元,它确保一组操作要么全部成功...
在 Hibernate 中,对事务并发处理是非常重要的, especialmente 在多用户环境中。事务处理的目的是为了保证数据的可靠性和一致性。 事务四个特性 ACID 1. 原子性(Atomicity):事务作为一个整体,所有操作要么...
9. **实体状态与生命周期**:理解Hibernate中的临时态、持久态、瞬时态和脱管态对于正确处理并发事务至关重要。 10. **最佳实践**:包括合理设计实体关系、避免N+1查询、使用批处理等,都是提升并发性能的关键。 ...
**一、Hibernate事务的概念** 事务是一组数据库操作,这些操作被视为一个逻辑单元,要么全部执行,要么全部不执行。这是为了保证数据的一致性。在Hibernate中,事务管理通常通过SessionFactory和Session接口来实现。...
通过谨慎地管理事务、正确使用`flush`,以及遵循并发控制的最佳实践,我们可以有效地防止和解决这类问题。在复杂的应用场景中,虽然手动调用`flush`可能带来一些灵活性,但它也可能引入新的风险,因此需要谨慎使用。
在Spring框架中,为了管理和控制Hibernate事务,Spring提供了两种关键工具:HibernateTemplate和JdbcTemplate。这两个模板类简化了与数据库的交互,同时也处理了事务管理。让我们深入了解一下这两个类以及它们如何...
### 详解Hibernate事务处理机制 #### 一、引言 Hibernate作为一款优秀的对象关系映射(ORM)框架,在Java开发领域扮演着极其重要的角色。它不仅简化了数据持久化的复杂性,还提供了一系列强大的功能来支持高效的...
【hibernate事务管理机制】是指在使用Hibernate框架进行数据库操作时,如何管理和协调事务的一系列规则和策略。事务管理是确保数据一致性、完整性和并发控制的重要机制。 **悲观锁**是预防性的锁定策略,它假设并发...
**Hibernate事务管理详解** 在Java开发中,尤其是在企业级应用中,事务管理是不可或缺的一部分。Hibernate作为一款流行的ORM(对象关系映射)框架,提供了强大的事务处理能力。本篇文章将深入探讨Hibernate中的事务...