Hibernate中的悲观锁与乐观锁

来源:互联网 发布:淘宝网中老年冬装 编辑:程序博客网 时间:2024/06/05 13:40

(一).悲观锁的概念
1.Hibernate悲观锁:在数据有加载的时候就给其进行加锁,直到该锁被释放掉,其他用户才可以进行修改,优点:数据的一致性保持得很好,缺点:不适合多个用户并发访问。当一个锁住的资源不被释放掉的时候,这个资源永远不会被其他用户进行修改,容易造成无限期的等待。

  • 悲观锁的加锁模式有:

  • LockMode.NONE:无锁机制

  • LockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取
  • LockMode.READ:Hibernate在读取记录的时候会自动获取
  • LockMode.UPGRADE:利用数据库的for update子句加锁

(二) 乐观锁的概念
- Hibernate乐观锁:就是在对数据进行修改的时候,对数据才去版本或者时间戳等方式来比较,数据是否一致性来实现加锁。优点比较好。
- 乐观锁加锁模式有:

  • none:无乐观锁
  • version:通过版本机制实现乐观锁
  • dirty:通过检查发生变动过的属性实现乐观锁
  • all:通过检查所有属性实现乐观锁
    (三)悲观锁的实例代码
package cn.codeWang.entity;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;@Entity(name = "person")public class Person {    @Id    @GeneratedValue    private int id;    private String name;    private String sex;    private String department;    public Person() {    }    public Person(String name, String sex, String department) {        super();        this.name = name;        this.sex = sex;        this.department = department;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getSex() {        return sex;    }    public void setSex(String sex) {        this.sex = sex;    }    public String getDepartment() {        return department;    }    public void setDepartment(String department) {        this.department = department;    }}<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration>    <session-factory>        <!-- 配置连接数据库 -->        <property name="connection.username">root</property>        <property name="connection.password">root</property>        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>        <property name="connection.url">jdbc:mysql:///hibernate1?useUnicode=true&amp;characterEncoding=UTF-8</property>        <!-- 配置方言是非常重要!!!我这里配置的为MySQL5Dialect -->        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>        <!-- 配置C3P0连接池 -->        <property name="hibernate.c3p0.max_size">200</property>        <property name="hibernate.c3p0.min_size">2</property>        <property name="hibernate.c3p0.max_statements">50</property>        <property name="hibernate.c3p0.timeout"></property>        <property name="show_sql">true</property>        <property name="format_sql">true</property>        <property name="hbm2ddl.auto">update</property>        <!-- 配置映射文件 -->        <mapping  class="cn.codeWang.entity.Person"/>    </session-factory></hibernate-configuration>
1.模拟两个人向同一数据库修改数据,这里我使用了悲观锁,看看它的作用是什么?import java.util.Iterator;import java.util.List;import org.hibernate.LockOptions;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.boot.MetadataSources;import org.hibernate.boot.registry.StandardServiceRegistryBuilder;import org.hibernate.service.ServiceRegistry;import org.junit.After;import org.junit.Before;import org.junit.Test;import cn.codeWang.entity.Person;public class DemoTest {    private SessionFactory sessionFactory;    private Session session;    private Transaction transaction;    @Before    public void init() {        // 创建服务注册对象        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();        // 创建会话工厂对象        sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();        // 会话对象        session = sessionFactory.openSession();        // 开启事物        transaction = session.beginTransaction();    }    @After    public void destory() {        // 提交事物        transaction.commit();        // 关闭会话        session.close();        // 关闭会话工厂        sessionFactory.close();    }    @Test    public void TestLock(){    Person  p1=session.get(Person.class, 2, LockOptions.UPGRADE );    System.out.println(p1.getName());    p1.setName("李四");    session.update(p1);    //第二次获得session对象    Session session = sessionFactory.openSession();     Person p2=session.get(Person.class, 2);    System.out.println(p2.getName());    p2.setName("曹操");    session.update(p2);    }}控制台输出结果为:Hibernate:     select        person0_.id as id1_0_0_,        person0_.department as departme2_0_0_,        person0_.name as name3_0_0_,        person0_.sex as sex4_0_0_     from        person person0_     where        person0_.id=?李四Hibernate:     select        person0_.id as id1_0_0_,        person0_.department as departme2_0_0_,        person0_.name as name3_0_0_,        person0_.sex as sex4_0_0_     from        person person0_     where        person0_.id=?李四总结:    第一个session对象调用get()方法使用了悲观锁机制,可以对对象实现更新操作。但是第二person对象无法对数据库进行更新操作(delete、update、insert)。只能对数据库进行读取操作。

4.乐观锁实例代码

package cn.codeWang.entity;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.Version;@Entity(name = "person")public class Person {    @Id    @GeneratedValue    private int id;    @Version    private int version;    private String name;    private String sex;    private String department;    public Person() {    }    public Person(String name, String sex, String department) {        super();        this.name = name;        this.sex = sex;        this.department = department;    }    public int getVersion() {        return version;    }    public void setVersion(int version) {        this.version = version;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getSex() {        return sex;    }    public void setSex(String sex) {        this.sex = sex;    }    public String getDepartment() {        return department;    }    public void setDepartment(String department) {        this.department = department;    }}
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration>    <session-factory>        <!-- 配置连接数据库 -->        <property name="connection.username">root</property>        <property name="connection.password">root</property>        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>        <property name="connection.url">jdbc:mysql:///hibernate1?useUnicode=true&amp;characterEncoding=UTF-8</property>        <!-- 配置方言是非常重要!!!我这里配置的为MySQL5Dialect -->        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>        <!-- 配置C3P0连接池 -->        <property name="hibernate.c3p0.max_size">200</property>        <property name="hibernate.c3p0.min_size">2</property>        <property name="hibernate.c3p0.max_statements">50</property>        <property name="hibernate.c3p0.timeout"></property>        <property name="show_sql">true</property>        <property name="format_sql">true</property>        <property name="hbm2ddl.auto">update</property>        <!-- 配置映射文件 -->        <mapping  class="cn.codeWang.entity.Person"/>    </session-factory></hibernate-configuration>
import java.util.Iterator;import java.util.List;import org.hibernate.LockOptions;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.boot.MetadataSources;import org.hibernate.boot.registry.StandardServiceRegistryBuilder;import org.hibernate.service.ServiceRegistry;import org.junit.After;import org.junit.Before;import org.junit.Test;import cn.codeWang.entity.Person;public class DemoTest {    private SessionFactory sessionFactory;    private Session session;    private Transaction transaction;    @Before    public void init() {        // 创建服务注册对象        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();        // 创建会话工厂对象        sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();        // 会话对象        session = sessionFactory.openSession();        // 开启事物        transaction = session.beginTransaction();    }    @After    public void destory() {        // 提交事物        transaction.commit();        // 关闭会话        session.close();        // 关闭会话工厂        sessionFactory.close();    }    @Test    // 筛选需要的数据    public void testSaveDate() {        Person p1 = new Person("凯耐", "男", "生产部");        Person p2 = new Person("凯丽", "女", "管理部");        Person p3 = new Person("欧陆", "男", "营销部");        session.save(p1);        session.save(p2);        session.save(p3);    }    @Test    public void testOptimistic() {        Person p = session.get(Person.class, 2);        p.setName("赵本山");        session.update(p);        System.out.println("姓名=" + p.getName());         session = sessionFactory.openSession();         p = session.get(Person.class, 2);        p.setName("飞机");        session.update(p);        System.out.println("姓名=" + p.getName());    }}

控制台输出结果为:
Hibernate:
select
person0_.id as id1_0_0_,
person0_.department as departme2_0_0_,
person0_.name as name3_0_0_,
person0_.sex as sex4_0_0_,
person0_.version as version5_0_0_
from
person person0_
where
person0_.id=?
姓名=赵本山
姓名=飞机
Hibernate:
update
person
set
department=?,
name=?,
sex=?,
version=?
where
id=?
and version=?

总结:使用乐观锁不同的session可以并发的对同一对象数据进行修改!