并发访问
可能引发的问题:更新丢失
(A线程把name属性改了,B线程马上改age属性,但是B线程中的name属性仍然是改之前的值,这就造成了A线程对name的更新丢失了)
------------------------
解决方案
*悲观锁 LockOptions.UPGRADE 虽然可以保证多线程下并发访问数据不会造成数据混乱---for update
但是,锁定记录的规则太不灵活,不建议使用
[一旦被某个线程锁定,其它线程无法进行,将被挂起,直到其释放锁其它线程才能进入]
行级锁,当A线程在更新此行时,其它线程无法查询到此行的数据,只有等到A线程操作完成,其它线程才能对该行进行查询,这样其它线程查询到的结果就是A线程更新后的结果!
------------------------
*乐观锁 (解决并发访问通用方法!)
<!-- 版本标识,用于解决并发访问 -->
<version name="versionNumber"></version>
定义在<id></id>与<property></property>之间
实体类中添加属性 private int versionNumber;
数据库中该字段的值由hibernate维护,程序员不用管理;
好处:提高性能,避免死锁
对于读操作没有限制,即读操作线程不受限制
通过比较线程所操纵的版本号与数据库记录的版本号是否一致来决定更新是否成功
版本号相同的记录才能被更新,
否则更新失败,抛出异常 Row was updated or deleted by another transaction
可以在捕获异常的时候,转化异常为"更新失败",提示重新更新
package org.leadfar.hibernate.model; import java.util.Set; public class Group { private int id; private String name; private Set<ContactPerson> persons; public Set<ContactPerson> getPersons() { return persons; } public void setPersons(Set<ContactPerson> persons) { this.persons = persons; } public Group() { // TODO Auto-generated constructor stub } public Group(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="org.hibernate.auction"> <!-- name为实体类 table为映射到数据库中的表 lazy默认为true 延迟发出select语句,直到真正用到对象的属性(非id属性)--> <class name="org.leadfar.hibernate.model.Group" table="t_group" batch-size="25"> <!-- id为数据库标识,作为主键 --> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!-- <set name="persons" fetch="select" batch-size="20"> <key column="gid"></key> <one-to-many class="org.leadfar.hibernate.model.ContactPerson"/> </set> --> <set name="persons" fetch="subselect"> <key column="gid"></key> <one-to-many class="org.leadfar.hibernate.model.ContactPerson"/> </set> </class> </hibernate-mapping>
package org.leadfar.hibernate.model; import java.util.Date; public class ContactPerson { private int id; private String name; private int age; private Date birthday; private Group group; private int versionNumber;//版本字段 public ContactPerson() { } public ContactPerson(String name) { this.name = name; } public ContactPerson(int id,String name) { this.id = id; this.name = name; } public ContactPerson(int id,int age,String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Group getGroup() { return group; } public void setGroup(Group group) { this.group = group; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public int getVersionNumber() { return versionNumber; } public void setVersionNumber(int versionNumber) { this.versionNumber = versionNumber; } }
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="org.hibernate.auction"> <!-- name为实体类 table为映射到数据库中的表 lazy默认为true 延迟发出select语句,直到真正用到对象的属性(非id属性)--> <class name="org.leadfar.hibernate.model.ContactPerson" table="t_person"> <id name="id"> <generator class="native"/> </id> <!-- 版本标识,用于解决并发访问 --> <version name="versionNumber"></version> <property name="name"/> <property name="age"></property> <property name="birthday" type="date"></property> <many-to-one name="group" column="gid" fetch="join"></many-to-one> </class> </hibernate-mapping>
测试
package org.leadfar.hibernate.model; import java.util.Date; import java.util.List; import java.util.Random; import java.util.Set; import junit.framework.TestCase; import org.hibernate.LockOptions; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class TestHQL extends TestCase { public void save_person() throws Exception { Configuration cfg = new Configuration().configure(); SessionFactory sfactory = cfg.buildSessionFactory(); Session session = sfactory.openSession(); try { //开启事务 session.beginTransaction(); Random r = new Random(); for(int i=0;i<100;i++) { Group g = new Group("组"+i); session.save(g); ContactPerson cp = new ContactPerson("用户"+i); cp.setAge(r.nextInt(99)); cp.setBirthday(new Date()); cp.setGroup(g); session.save(cp); } //提交事务 session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); //出现异常,回滚事务 session.getTransaction().rollback(); } finally { //关闭session session.close();//session关闭之后,user对象处于离线Detached状态 } } /** * 悲观锁 upgrade * 利用数据库对记录进行锁定,需要等待更新操作完成后才能对其进行读取和更新 */ public void lock_upgrade_01() throws Exception { Configuration cfg = new Configuration().configure(); SessionFactory sfactory = cfg.buildSessionFactory(); Session session = sfactory.openSession(); try { session.beginTransaction(); ContactPerson cp = (ContactPerson)session.get(ContactPerson.class, 100,LockOptions.UPGRADE); System.out.println(cp.getName()); cp.setName("AA"); session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { session.close(); } } public void lock_upgrade_02() throws Exception { Configuration cfg = new Configuration().configure(); SessionFactory sfactory = cfg.buildSessionFactory(); Session session = sfactory.openSession(); try { session.beginTransaction(); ContactPerson cp = (ContactPerson)session.get(ContactPerson.class, 100,LockOptions.UPGRADE); System.out.println(cp.getName()); cp.setAge(101); session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { session.close(); } } /** * 乐观锁 */ public void lock_optimism_01() throws Exception { Configuration cfg = new Configuration().configure(); SessionFactory sfactory = cfg.buildSessionFactory(); Session session = sfactory.openSession(); try { session.beginTransaction(); ContactPerson cp = (ContactPerson)session.get(ContactPerson.class, 100); System.out.println(cp.getName()); cp.setName("BB"); session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { session.close(); } } public void lock_optimism_02() throws Exception { Configuration cfg = new Configuration().configure(); SessionFactory sfactory = cfg.buildSessionFactory(); Session session = sfactory.openSession(); try { session.beginTransaction(); ContactPerson cp = (ContactPerson)session.get(ContactPerson.class, 100); System.out.println(cp.getName()); cp.setAge(88); session.getTransaction().commit(); } catch(Exception e) { e.printStackTrace(); session.getTransaction().rollback(); } finally { session.close(); } } }
相关推荐
使用Hibernate的乐观锁,开发者可以避免长时间持有数据库锁,从而提高系统性能,尤其在并发访问量大的场景下。但是,它并不适用于所有情况。当并发冲突频繁发生时,由于频繁的更新失败,可能会导致应用程序的效率...
《Hibernate 悲观锁与乐观锁详解》 在多用户并发访问的环境中,数据库管理系统必须具备有效的数据访问控制机制,以确保数据的一致性和完整性。Hibernate,作为一款流行的Java持久化框架,提供了两种主要的锁定策略...
在Hibernate中,可以通过配置文件或注解的方式指定实体类的乐观锁策略。例如,使用版本号字段: ```java @Entity @Table(name = "account") public class Account { @Id @GeneratedValue(strategy = ...
总之,Hibernate提供的乐观锁机制通过XML配置为开发者提供了一种优雅的方式来处理并发更新问题,它提高了系统性能,但同时也需要考虑可能产生的冲突处理。理解并合理应用乐观锁,可以帮助我们构建更健壮、高效的...
- **源码**:暗示文章可能会深入到Hibernate的配置文件和Java代码层面,讲解具体的映射关系和乐观锁的实现细节。 - **工具**:表明Hibernate作为一个工具,将在讨论中占据核心位置。 **文件名称列表解析:** ...
乐观锁与数据库锁无关,在数据表中为数据添加版本字段,每次数据修改都会导致版本号+1。 例如,在 Hibernate 中使用乐观锁: ```java public class Customer { private Integer version; // ... } ``` 在 ...
开发者可以通过设置`Session`的`setTransactionIsolationLevel()`方法或在`hibernate.cfg.xml`配置文件中指定全局的隔离级别,来控制并发行为。同时,Hibernate还支持乐观锁和悲观锁机制,通过版本字段或锁定表行的...
在配置乐观锁时,需要在映射文件中为实体类指定`optimistic-lock`属性,例如 `<class ... optimistic-lock="version">`。`optimistic-lock`有多种选择:`none`表示无乐观锁,`version`使用版本号实现,`dirty`检测...
并发控制可以使用乐观锁或悲观锁等方式。 拦截器和事件处理 Hibernate 支持拦截器和事件处理,可以在对象的生命周期中执行特定的操作。 HQL Hibernate Query Language(HQL)是 Hibernate 的查询语言。HQL 可以...
同时,Hibernate还提供了乐观锁和悲观锁等并发控制策略,以防止数据冲突。你需要理解何时使用事务开始、提交和回滚,以及如何正确地实现并发控制策略。 通过阅读《Hibernate PDF 电子书》,你将能够掌握Hibernate的...
Hibernate是一个流行的Java对象关系映射(ORM)框架,它简化了基于Java的应用程序与数据库之间的交互。该文档《Hibernate Developer Guide》是一个针对Hibernate ORM 4.2版本的开发者指南。由于内容详尽,本文将着重...
此外,Hibernate还提供了乐观锁和悲观锁策略,用于并发控制。 七、延迟加载(Lazy Loading) 延迟加载是Hibernate的一个重要特性,它只在真正需要时才加载关联对象,从而避免了大量无谓的数据获取。这种机制依赖于...
包括基础抓取知识和应用抓取策略,例如通过查询和配置文件动态抓取数据。 批处理:Hibernate支持JDBC批处理,以提高批量数据操作的性能。 缓冲:讲解了如何配置二级缓冲以及管理缓冲数据。 拦截器和事件:这部分...
8. 锁章节,讨论了Hibernate提供的乐观锁和悲观锁的实现,包括使用版本号、时间戳、LockMode类等方法来控制并发访问。 9. Fetching(抓取)章节,说明了如何配置和应用不同的抓取策略来优化数据库访问和提升性能。...
还有,乐观锁和悲观锁机制,用于并发控制,保证数据的一致性。 在实际项目中,我们还需要考虑事务管理。Hibernate支持JTA(Java Transaction API)和JPA(Java Persistence API)的事务管理方式,可以很好地与...
乐观锁定版本控制:通过`@Version`注解,Hibernate可以实现乐观锁,防止并发更新时的数据冲突。 2.2.2. 映射简单属性和嵌入式对象:使用`@Column`注解映射简单属性,如字符串、整数等。`@Embeddable`和`@Embedded`...