`

乐观锁的理解

阅读更多
   悲观锁假定任何时刻存取数据时,都有可能有另一个客户也正在存取同一笔资料,因而对资料采取了资料库层次的锁定状态,在锁定的时间内其他的客户不能对资料进行存取,对于单机或小系统而言,这并不成问题,然而如果是在网路上的系统,同时刻会有许多连线,如果每一次读取资料都造成锁定,那后面的存取就必须等待,这将造成效能上的问题,造成后面使用者的长时间等待。

   乐观锁定则认为资料的存取很少发生同时存取的问题,因而不作资料库层次上的锁定,为了维护正确的资料,乐观锁定使用应用程式上的逻辑实现版本控制的解决。在不实行悲观锁定策略的情况下,资料不一致的情况一但发生,就会造成资料不一致。Hibernate的乐观锁处理是在数据中加入一个version栏位记录,在读取数据时,连同版本号一同读取,并在更新资料时对比版本号与数据库中的版本号,如果等于数据库中的版本号则予以更新,并递增版本号,如果小于资料库中的版本号就抛出异常。

新建一个表event。

create table event(id integer primary key,version integer,title varchar(20))



新建Event.java
package com;

public class Event {

 private int id;
 private String title;
 private int version;
 Event(){  }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getTitle() {
  return title;
 }

 public void setTitle(String title) {
  this.title = title;
 }

 public int getVersion() {
  return version;
 }

 public void setVersion(int version) {
  this.version = version;
 }
}



文件Event.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
 <class name="com.Event" table="Event">
                <id name="id"  column="id" length="32">
   <generator class="increment" />
  </id>
  <version name="version"
    column="version" type="java.lang.Integer" >
  </version>
  <property name="title" column="title"/>
 </class>
</hibernate-mapping>



程序HibernateSessionFactory.java

package com;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactory {

    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
 private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    private  static Configuration configuration = new Configuration();
    private static org.hibernate.SessionFactory sessionFactory;
    private static String configFile = CONFIG_FILE_LOCATION;

    private HibernateSessionFactory() {
    }
     public static Session getSession() throws HibernateException {
        Session session = (Session) threadLocal.get();

  if (session == null || !session.isOpen()) {
   if (sessionFactory == null) {
    rebuildSessionFactory();
   }
   session = (sessionFactory != null) ? sessionFactory.openSession()
     : null;
   threadLocal.set(session);
  }

        return session;
    }

  public static void rebuildSessionFactory() {
  try {
   configuration.configure(configFile);
   sessionFactory = configuration.buildSessionFactory();
  } catch (Exception e) {
   System.err
     .println("%%%% Error Creating SessionFactory %%%%");
   e.printStackTrace();
  }
 }

     public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);

        if (session != null) {
            session.close();
        }
    }

  public static org.hibernate.SessionFactory getSessionFactory() {
  return sessionFactory;
 }

  public static void setConfigFile(String configFile) {
  HibernateSessionFactory.configFile = configFile;
  sessionFactory = null;
 }

  public static Configuration getConfiguration() {
  return configuration;
 }

}




程序BaseHibernateDAO.java


package com;

import org.hibernate.Session;

public class BaseHibernateDAO {

 public Session getSession() {
    return HibernateSessionFactory.getSession();
 }

 public void closeSession(){
  HibernateSessionFactory.closeSession();
 }
}



测试程序EventDao.java

package com;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.Transaction;
import com.Event;

public class EventDao extends BaseHibernateDAO{

 public static void main(String args[]) throws Exception{
  new EventDao().add();
    } 
 public void add() throws Exception {
    Session sess = this.getSession();
    Transaction tran = sess.beginTransaction();
    try{
     tran.begin();

 /***/
     Event event = new Event();
    // Event event = (Event)sess.load(Event.class, 1);
     event.setTitle("First super star");
/***/
     sess.save(event);
     tran.commit();
    }catch(Exception e){
     e.printStackTrace();
    }finally{
     this.closeSession();
    }
 }



执行EventDao.java

可以看到数据库中添加了数据,这是version的值是0。然后把程序中/***/的部分改一下

//Event event = new Event();
Event event = (Event)sess.load(Event.class, 1);
event.setTitle("Second super star");


在执行,查询数据库,会发现version的数据递增成1了。

现在来测试一个例子,看看出现异常的情况。

首先要改程序HibernateSessionFactory.java里的getSession方法。
public static Session getSession() throws HibernateException {
        Session session = (Session) threadLocal.get();

        if (sessionFactory == null) {
          rebuildSessionFactory();
        }
        return sessionFactory.openSession();
}




这时修改EventDao.java


package com;

import org.hibernate.Session;
import org.hibernate.Transaction;
import com.Event;

public class EventDao extends BaseHibernateDAO{

 public static void main(String args[]) throws Exception{
  new EventDao().add();
 } 
 public void add() throws Exception {
    Session sess1 = this.getSession();
    Session sess2 = this.getSession();
    Transaction tran1 = sess1.beginTransaction();
    Transaction tran2 = sess2.beginTransaction();
    try{
     Event event1 = (Event)sess1.load(Event.class, 1);
     Event event2 = (Event)sess2.load(Event.class, 1);
     System.out.println("v1 v2:"+event1.getVersion()+" "+event2.getVersion());
     tran1.begin();
     event1.setTitle("Modify one");
     sess1.save(event1);
     tran1.commit();
    
     System.out.println("v1 v2:"+event1.getVersion()+" "+event2.getVersion());
     tran2.begin();
     event2.setTitle("Modify two");
     sess2.save(event2);
     tran2.commit();
    
     sess1.close();
     sess2.close();
    }catch(Exception e){
     e.printStackTrace();
    }

 }

 }



运行,可以看到控制台上的输出。

Hibernate: select event0_.id as id0_0_, event0_.version as version0_0_, event0_.title as title0_0_ from event event0_ where event0_.id=?
Hibernate: select event0_.id as id0_0_, event0_.version as version0_0_, event0_.title as title0_0_ from event event0_ where event0_.id=?
v1 v2:12 12
Hibernate: update event set version=?, title=? where id=? and version=?
v1 v2:13 12
Hibernate: update event set version=?, title=? where id=? and version=?

严重: Could not synchronize database state with session
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.Event#1]

这时就是在event2更新时发生了版本异常。

要注意的是,乐观锁是在程序里做的控制,如果在更新数据时,人为的改变version的值,那么保存时,数据一样会被成功保存,这样锁定机制就有问题了,在设计时要注意。

分享到:
评论

相关推荐

    thinkPHP框架乐观锁和悲观锁实例分析

    在ThinkPHP框架中,常见的有乐观锁和悲观锁两种机制。本文将通过实例分析这两种锁在ThinkPHP框架中的应用,以及它们各自的优缺点。 首先,让我们从乐观锁开始了解。乐观锁机制假设多个事务在处理数据时很少发生冲突...

    乐观锁version-练习

    1. **乐观锁的工作原理**:理解乐观锁的基本概念,以及它如何在数据更新时防止并发问题。 2. **Hibernate的乐观锁机制**:了解Hibernate如何通过`version`字段实现乐观锁,包括`@Version`注解的使用、对象状态管理...

    Hibernate乐观锁和悲观锁分析

    【Hibernate乐观锁与悲观锁详解】 在开发过程中,尤其是在并发环境下,确保数据的一致性和完整性至关重要。Hibernate,作为Java领域广泛使用的ORM框架,提供了一种处理并发数据访问冲突的手段,那就是锁机制。主要...

    吊打面试官之乐观锁实现源码

    同时,理解如何处理乐观锁引发的并发冲突,也是开发者必须掌握的技能之一。在实际项目中,合理地使用乐观锁可以提高系统的并发处理能力,减少不必要的资源竞争,从而提升整体性能。 在面试时,讨论乐观锁的优缺点也...

    面试必备之乐观锁与悲观锁.pdf

    ### 面试必备之乐观锁与悲观锁详解 #### 一、悲观锁与乐观锁的概念 悲观锁和乐观锁是计算机科学中用于处理并发控制的两种不同策略,它们主要应用于多线程环境下数据的一致性和完整性保护。两种锁的设计哲学反映了...

    node+js页面乐观锁帧同步示例源码

    在IT行业中,乐观锁是一种重要的并发控制策略,用于管理共享...通过分析这个示例源码,开发者可以学习如何在Node.js和JavaScript环境中实现乐观锁,并理解如何将这种技术应用于Web游戏或其他需要实时同步的应用场景。

    Hibernate的乐观锁与悲观锁

    ### Hibernate的乐观锁与悲观锁 #### 一、引言 在并发环境下,尤其是在金融、电商等业务场景中,确保数据的一致性和完整性至关重要。**Hibernate**作为一种流行的Java持久层框架,提供了多种机制来处理并发控制...

    hibernate乐观锁和悲观锁学习

    本文主要讨论的是Hibernate框架中两种锁机制的使用:乐观锁和悲观锁。 首先,让我们深入理解悲观锁(Pessimistic Locking)。悲观锁正如其名字所示,假设并发环境中数据会被频繁修改,所以在整个数据处理过程中,它...

    Redis分布式锁----乐观锁的实现,以秒杀系统为例.rar

    本文件“Redis分布式锁----乐观锁的实现,以秒杀系统为例”主要探讨了如何利用Redis实现乐观锁,并通过秒杀系统的实例进行详细阐述。 首先,我们需要理解什么是分布式锁。在分布式系统中,当多个节点同时访问同一...

    Hibernate悲观锁和乐观锁的实现

    在进行Hibernate的测试时,可以创建一个名为`hibernate_test`的项目,编写对应的实体类、映射文件以及测试用例,模拟并发场景,来深入理解并对比悲观锁和乐观锁的差异和效果。 总之,理解并合理运用悲观锁和乐观锁...

    mysql 悲观锁与乐观锁的理解及应用分析

    悲观锁与乐观锁是人们定义出来的概念,你可以理解为一种思想,是处理并发资源的常用手段。 不要把他们与mysql中提供的锁机制(表锁,行锁,排他锁,共享锁)混为一谈。 一、悲观锁 顾名思义,就是对于数据的处理持悲观...

    Hibernate悲观锁与乐观锁案例

    在Java的持久化框架Hibernate中,悲观锁和乐观锁是两种重要的并发控制策略,它们用于管理数据库中的数据在多线程环境下的访问安全。本文将深入探讨这两种锁机制的原理、应用场景及其区别。 首先,我们来理解悲观锁...

    面试必备之乐观锁与悲观锁.zip

    了解和掌握乐观锁与悲观锁的原理和应用场景,可以帮助你在面试中展示出对并发控制和数据库事务管理的深入理解,为你的职业生涯加分。在实际工作中,根据业务需求选择合适的锁策略,能够有效地提高系统的稳定性和性能...

    hibernate的乐观锁和悲观锁

    ### Hibernate的乐观锁和悲观锁 #### 一、引言 在软件开发中,尤其是在涉及大量并发操作的应用场景下,确保数据的一致性和完整性是非常重要的。对于基于Java Web的应用而言,Hibernate作为一款流行的ORM框架,提供...

    数据库乐观锁与悲观锁1

    总的来说,数据库的锁机制是确保数据一致性的重要工具,理解并合理使用乐观锁和悲观锁,可以帮助我们设计出更高效、更稳定的数据库应用程序。在数据库设计时,应充分考虑并发控制策略,根据业务特点选择合适的锁类型...

Global site tag (gtag.js) - Google Analytics