• 笔记46 Hibernate快速入门(三)


    Hibernate相关概念

    一、事物概念

    Hibernate的任何对数据有改动的操作,都应该被放在事务里面。

    hibernate中的事务由s.beginTransaction();开始由s.getTransaction().commit();结束

    本例子,执行了两个操作

    第一个,删除id=1的产品,这个是会成功的
    第二个,修改id=2的产品,使得其产品名称超过了数据库中设置的长度30,这个是会失败的。
    因为这两个操作都是在一个事务中,而且第二个操作失败了,所以最后的结果是两个操作都没有生效

     1 package hibernate.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 import hibernate.pojo.Product;
     8 
     9 public class testTransaction {
    10 
    11     public static void main(String[] args) {
    12         // TODO Auto-generated method stub
    13 
    14         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    15         Session session = sFactory.openSession();
    16         session.beginTransaction();
    17 
    18         Product product = (Product) session.get(Product.class, 1);
    19         session.delete(product);
    20 
    21         Product product2 = (Product) session.get(Product.class, 2);
    22         product2.setName("iphoneiphoneiphoneiphoneiphoneiphoneiphoneiphoneiphone");
    23         session.update(product2);
    24 
    25         session.getTransaction().commit();
    26         session.close();
    27         sFactory.close();
    28     }
    29 
    30 }

    二、属性延迟加载

    属性的延迟加载: 当使用load的方式来获取对象的时候,只有访问了这个对象的属性,hibernate才会到数据库中进行查询,否则不会访问数据库。

     1 package hibernate.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 import hibernate.pojo.Product;
     8 
     9 public class testDelayProperty {
    10 
    11     public static void main(String[] args) {
    12         // TODO Auto-generated method stub
    13 
    14         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    15         Session session = sFactory.openSession();
    16         session.beginTransaction();
    17 
    18         Product product = (Product) session.load(Product.class, 1);
    19         System.out.println("log1");
    20         System.out.println(product.getName());
    21         System.out.println("log2");
    22 
    23         session.getTransaction().commit();
    24         session.close();
    25         sFactory.close();
    26     }
    27 
    28 }

    三、关系延迟加载

    延迟加载又叫lazyload,在one-many many-many的时候都可以使用关系的延迟加载。

    <set name="products" lazy="false">改为<set name="products" lazy="true">表示通过Category获取产品是延迟加载的。

     1 <?xml version="1.0"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC
     3         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4         "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5  
     6 <hibernate-mapping package="hibernate.pojo">
     7     <class name="Category" table="category">
     8         <id name="id" column="id">
     9             <generator class="native">
    10             </generator>
    11         </id>
    12         <property name="name" />
    13  
    14         <set name="products" lazy="true">
    15             <key column="cid" not-null="false" />
    16             <one-to-many class="Product" />
    17         </set>            
    18     </class>
    19 </hibernate-mapping>

    测试:

      执行22行的时候,只会查询Category表的信息,不会查询product表。只有在执行24行,通过category取products的时候,才会进行对product表的查询。

     1 package hibernate.test;
     2 
     3 import java.util.Iterator;
     4 import java.util.Set;
     5 
     6 import org.hibernate.Session;
     7 import org.hibernate.SessionFactory;
     8 import org.hibernate.cfg.Configuration;
     9 
    10 import hibernate.pojo.Category;
    11 import hibernate.pojo.Product;
    12 
    13 public class testDelayRelation {
    14 
    15     public static void main(String[] args) {
    16         // TODO Auto-generated method stub
    17 
    18         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    19         Session session = sFactory.openSession();
    20         session.beginTransaction();
    21 
    22         Category category = (Category) session.get(Category.class, 4);
    23         System.out.println("log1");
    24         Set<Product> products = category.getProducts();
    25         Iterator<Product> iterator = products.iterator();
    26         while (iterator.hasNext()) {
    27             System.out.println(iterator.next().getName());
    28 
    29         }
    30         System.out.println("log2");
    31 
    32         session.getTransaction().commit();
    33         session.close();
    34         sFactory.close();
    35     }
    36 
    37 }

    四、级联

      什么是级联? 简单的说,就是没有配置级联的时候,删除分类,其对应的产品不会被删除。 但是如果配置了恰当的级联,那么删除分类的时候,其对应的产品都会被删除掉。

      级联有4种类型:

    all:所有操作都执行级联操作;

    none:所有操作都不执行级联操作;

    delete:删除时执行级联操作; 

    save-update:保存和更新时执行级联操作;

    级联通常用在one-many和many-to-many上,几乎不用在many-one上。

    1.delete级联

    在Category.hbm.xml 加上 <set name="products" cascade="delete" lazy="false">

    在删除分类的时候,会把分类下对应的产品都删除掉,否则只会把产品对应的cid设置为空。

    2.save-update级联

      运行代码就会发现,这3个瞬时状态的产品对象虽然没有添加到数据库里,但是在事务提交的时候,会把他们3个持久化。 如果没有cascade="save-update",就会报错。

     1 package hibernate.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 import hibernate.pojo.Category;
     8 import hibernate.pojo.Product;
     9 
    10 public class testCascadeSaveUpdate {
    11     /*
    12      * 级联有4种类型: all:所有操作都执行级联操作; none:所有操作都不执行级联操作; delete:删除时执行级联操作;
    13      * save-update:保存和更新时执行级联操作;
    14      */
    15     public static void main(String[] args) {
    16         // TODO Auto-generated method stub
    17 
    18         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    19         Session session = sFactory.openSession();
    20         session.beginTransaction();
    21 
    22         Category category = (Category) session.get(Category.class, 5);
    23         Product product = new Product();
    24         product.setName("xiaomi_note");
    25         Product product2 = new Product();
    26         product2.setName("xiaomi_max");
    27         Product product3 = new Product();
    28         product3.setName("xiaomi_8");
    29 
    30         category.getProducts().add(product);
    31         category.getProducts().add(product2);
    32         category.getProducts().add(product3);
    33 
    34         session.getTransaction().commit();
    35         session.close();
    36         sFactory.close();
    37     }
    38 
    39 }

    五、一级缓存

      hibernate默认是开启一级缓存的,一级缓存存放在session上。

    例子:

    第一次通过id=1获取对象的时候,session中是没有对应缓存对象的,所以会在"log1"后出现sql查询语句。
    第二次通过id=1获取对象的时候,session中有对应的缓存对象,所以在"log2"后不会出现sql查询语句。

     1 package hibernate.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 import hibernate.pojo.Category;
     8 
     9 public class testCacheL1 {
    10 
    11     public static void main(String[] args) {
    12         // TODO Auto-generated method stub
    13 
    14         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    15         Session session = sFactory.openSession();
    16         session.beginTransaction();
    17 
    18         System.out.println("log1");
    19         Category category = (Category) session.get(Category.class, 1);
    20         System.out.println("log2");
    21         Category category2 = (Category) session.get(Category.class, 1);
    22         System.out.println("log3");
    23 
    24         session.getTransaction().commit();
    25         session.close();
    26         sFactory.close();
    27     }
    28 
    29 }

    六、二级缓存

      Hibernate的一级缓存是在Session上,二级缓存是在SessionFactory上。

    创建了两个Session:

    在第一个Session里

    第一次获取id=1的Category 会执行SQL语句

    第二次获取id=1的Category,不会执行SQL语句,因为有一级缓存

    在第二个Session里

    获取id=1的Category,如果没有设置二级缓存时,会执行SQL语句,因为在第二个Session,没有缓存该对象。 所以总共会看到两条SQL语句。

    如果设置了二级缓存就使用不同的session,都去获取id=1的category,只会访问一次数据库。因为第二次获取虽然没有从第二个session中拿到缓存,但是从sessionfactory中拿到了Category缓存对象。

    1.在hibernate.cfg.xml 中增加对二级缓存的配置

     1 <?xml version='1.0' encoding='utf-8'?>
     2 <!DOCTYPE hibernate-configuration PUBLIC
     3        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
     4 "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
     5 
     6 <hibernate-configuration>
     7 
     8     <session-factory>
     9         <!-- Database connection settings -->
    10         <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
    11         <property name="connection.url">jdbc:mysql://localhost:3306/tests?characterEncoding=UTF-8</property>
    12         <property name="connection.username">root</property>
    13         <property name="connection.password">123456</property>
    14         <!-- SQL dialect -->
    15         <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
    16         <property name="current_session_context_class">thread</property>
    17         <property name="show_sql">true</property>
    18         <property name="hbm2ddl.auto">update</property>
    19         <property name="hibernate.cache.use_second_level_cache">true</property> 
    20             <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> 
    21         <mapping resource="hibernate/pojo/Product.hbm.xml" />
    22         <mapping resource="hibernate/pojo/Category.hbm.xml" />
    23         <mapping resource="hibernate/pojo/User.hbm.xml" />
    24     </session-factory>
    25 
    26 </hibernate-configuration>

    2.在src目录下,创建一个ehcache.xml用于EHCache的缓存配置。

     1 <ehcache>
     2     <diskStore path="java.io.tmpdir"/>
     3     <defaultCache
     4         maxElementsInMemory="10000"
     5         eternal="false"
     6         timeToIdleSeconds="120"
     7         timeToLiveSeconds="120"
     8         overflowToDisk="true"
     9         />
    10 </ehcache>

    3.对于要进行二级缓存的实体类,进行配置,增加<cache usage="read-only" />

    4.测试

     1 package hibernate.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 import hibernate.pojo.Category;
     8 
     9 public class testCacheL2 {
    10 
    11     public static void main(String[] args) {
    12         // TODO Auto-generated method stub
    13 
    14         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    15         Session session = sFactory.openSession();
    16         session.beginTransaction();
    17 
    18         Category category = (Category) session.get(Category.class, 1);
    19         System.out.println("log1");
    20         Category category2 = (Category) session.get(Category.class, 1);
    21         System.out.println("log2");
    22         session.getTransaction().commit();
    23         session.close();
    24 
    25         Session session2 = sFactory.openSession();
    26         session2.beginTransaction();
    27         Category category3 = (Category) session2.get(Category.class, 1);
    28         System.out.println("log3");
    29 
    30         session2.getTransaction().commit();
    31         session2.close();
    32 
    33         sFactory.close();
    34     }
    35 
    36 }

    七、分页

      使用Criteria进行分页查询Hibernate使用Criteria 来进行分页查询c.setFirstResult(2); 表示从第2条数据开始c.setMaxResults(5); 表示一共查询5条数据

     1 package hibernate.test;
     2 
     3 import java.util.List;
     4 
     5 import org.hibernate.Criteria;
     6 import org.hibernate.Session;
     7 import org.hibernate.SessionFactory;
     8 import org.hibernate.cfg.Configuration;
     9 import org.hibernate.criterion.Restrictions;
    10 
    11 import hibernate.pojo.Product;
    12 
    13 public class testPaging {
    14 
    15     public static void main(String[] args) {
    16         // TODO Auto-generated method stub
    17 
    18         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    19         Session session = sFactory.openSession();
    20         session.beginTransaction();
    21 
    22         String name = "iphone";
    23 
    24         Criteria criteria = session.createCriteria(Product.class);
    25         criteria.add(Restrictions.like("name", "%" + name + "%"));
    26         criteria.setFirstResult(2);
    27         criteria.setMaxResults(5);
    28 
    29         List<Product> products = criteria.list();
    30         for (Product p : products) {
    31             System.out.println(p.getName());
    32         }
    33 
    34         session.getTransaction().commit();
    35         session.close();
    36         sFactory.close();
    37     }
    38 
    39 }

    八、两种获取方式

    Hibernate中根据Id单条查询获取对象的方式有两种,分别是get()和load(),来看一下这两种方式的区别。

    1.当get()方法被调用的时候就会立即发出SQL语句。

    2.当调用load()方法的时候会返回一个目标对象的代理对象,在这个代理对象中只存储了目标对象的ID值,只有当调用除ID值以外的属性值的时候才会发出SQL查询的。

    3.Exception

    <1>当使用get获取数据库中不存在的数据时会抛出空指针异常NullPointerException

    <2>当使用load获取数据库中不存在的数据时会发生一个ObjectNotFoundException异常。

      这个是因为使用load()的时候返回的是一个代理对象,因为这个时候还没有进行查询,所以我们并没有办法确定要查询的对象到底存在不存在,所以使用load()查询的返回值是永远不会为空的,但是呢,当我们试图访问被代理的真实对象的时候,因为这个对象并不存在,所以就抛出了一个ObjectNotFoundException。

     

      还有一种说法是get()是用于不确定对象是否真的存在的情况,所以在查询出来后可以先进行一个空指针判断,而load()方法用于对象一定存在的情况下,不然等会儿使用的时候就可能会抛出ObjectNotFoundException了。

    4.缓存

      get()和load()都会使用缓存,都是首先从一级缓存Session中查找,当找不到的时候再去二级缓存中查找,当查询不到的时候get()返回的是null,而load()则返回代理对象。

      如果使用这两种方式访问同一个id数据,会发现两个返回的都是真实对象,连load()返回的也是真实对象,并且它们引用的还是同一块对象。这个是因为get()查询出来的对象后会将其放入到缓存中,而load()再去查询的时候它会先去缓存中查找,如果缓存中没有的话才会返回代理对象,但是当缓存中已经存在的话就直接将真实对象返回来了。

    5.小结

    返回值:

    get()返回的是查询出来的实体对象,而load()查询出来的是一个目标实体的代理对象。

    查询时机:

    get()在调用的时候就立即发出SQL语句查询,而load()在访问非ID属性的时候才会发出查询语句并且将被代理对象target填充上,但是如果这个动作发生在Session被关闭后的话就会抛出LazyInitializationException。

    查询结果为空时:

    get()抛出NullPointerException

    load()抛出ObjectNotFoundException

     1 package hibernate.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 import hibernate.pojo.Product;
     8 
     9 public class testLoadAndGet {
    10 
    11     /*
    12      * load方式是延迟加载,只有属性被访问的时候才会调用sql语句 ;get方式是非延迟加载,无论后面的代码是否会访问到属性,马上执行sql语句
    13      */
    14     @SuppressWarnings("unused")
    15     public static void main(String[] args) {
    16         // TODO Auto-generated method stub
    17 
    18         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    19         Session session = sFactory.openSession();
    20         session.beginTransaction();
    21         System.out.println("log1");
    22         Product product = (Product) session.get(Product.class, 1);
    23         System.out.println("log2");
    24         Product product2 = (Product) session.load(Product.class, 2);
    25         // Product product2 = (Product) session.load(Product.class, 200);
    26         System.out.println("log3");
    27         // System.out.println(product2.getName());
    28         System.out.println("log4");
    29 
    30         // Product p3 = (Product) session.get(Product.class, 500);
    31         // System.out.println("p3=" + p3.getName());
    32 
    33         // Product p4 = (Product) session.load(Product.class, 500);
    34         // System.out.println("p4=" + p4.getName());
    35 
    36         Product product3 = (Product) session.load(Product.class, 5);
    37         System.out.println(product3.getName());
    38         Product product4 = (Product) session.load(Product.class, 5);
    39         System.out.println(product4.getName());
    40         session.getTransaction().commit();
    41         session.close();
    42         System.out.println(product.getName());
    43         sFactory.close();
    44     }
    45 
    46 }

    九、两种Session方式

    Hibernate有两种方式获得session,分别是:openSession和getCurrentSession 

    区别在于 

    1. 获取的是否是同一个session对象 
    openSession每次都会得到一个新的Session对象 
    getCurrentSession在同一个线程中,每次都是获取相同的Session对象,但是在不同的线程中获取的是不同的Session对象 
    2. 事务提交的必要性 
    openSession只有在增加,删除,修改的时候需要事务,查询时不需要的 
    getCurrentSession是所有操作都必须放在事务中进行,并且提交事务后,session就自动关闭,不能够再进行关闭 

     1 package hibernate.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 import hibernate.pojo.Product;
     8 
     9 public class testSession {
    10 
    11     static Session session;
    12     static Session session2;
    13 
    14     public static void main(String[] args) throws InterruptedException {
    15         // TODO Auto-generated method stub
    16 
    17         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    18         // Session session = sFactory.openSession();
    19         // Session session2 = sFactory.openSession();
    20 
    21         // Session session = sFactory.getCurrentSession();
    22         // Session session2 = sFactory.getCurrentSession();
    23         //
    24         // System.out.println(session == session2);
    25 
    26         // session.close();
    27         // session2.close();
    28 
    29         Thread thread = new Thread() {
    30             public void run() {
    31                 session = sFactory.getCurrentSession();
    32             }
    33         };
    34         thread.start();
    35 
    36         Thread thread2 = new Thread() {
    37             public void run() {
    38                 session2 = sFactory.getCurrentSession();
    39             }
    40         };
    41         thread2.start();
    42 
    43         thread.join();
    44         thread2.join();
    45 
    46         System.out.println(session == session2);
    47 
    48         Session session3 = sFactory.openSession();
    49         System.out.println(((Product) session3.get(Product.class, 2)).getName());
    50 
    51         // Session session4 = sFactory.getCurrentSession();
    52         // session4.get(Product.class, 2);
    53 
    54         session.close();
    55         session2.close();
    56 
    57         Session session5 = sFactory.getCurrentSession();
    58         session5.beginTransaction();
    59         session5.get(Product.class, 3);
    60         session5.getTransaction().commit();
    61         // session5.close();
    62 
    63         sFactory.close();
    64     }
    65 
    66 }

    十、N+1

      Hibernate有缓存机制,可以通过用id作为key把product对象保存在缓存中 同时hibernate也提供Query的查询方式。假设数据库中有100条记录,其中有30条记录在缓存中,但是使用Query的list方法,就会所有的100条数据都从数据库中查询,而无视这30条缓存中的记录。 N+1是什么意思呢,首先执行一条sql语句,去查询这100条记录,但是,只返回这100条记录的ID 然后再根据id,进行进一步查询。如果id在缓存中,就从缓存中获取product对象了,否则再从数据库中获取。

      Hibernate使用Iterator实现N+1。

      首先通过Query的iterator把所有满足条件的Product的id查出来然后再通过it.next()查询每一个对象如果这个对象在缓存中,就直接从缓存中取了否则就从数据库中获取N+1中的1,就是指只返回id的SQL语句,N指的是如果在缓存中找不到对应的数据,就到数据库中去查。

     1 package hibernate.test;
     2 
     3 import java.util.Iterator;
     4 
     5 import org.hibernate.Query;
     6 import org.hibernate.Session;
     7 import org.hibernate.SessionFactory;
     8 import org.hibernate.cfg.Configuration;
     9 
    10 import hibernate.pojo.Product;
    11 
    12 public class testN1 {
    13 
    14     public static void main(String[] args) {
    15         // TODO Auto-generated method stub
    16 
    17         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    18         Session session = sFactory.openSession();
    19         session.beginTransaction();
    20 
    21         String name = "iphone";
    22         Query query = session.createQuery("from Product p where p.name like ?");
    23         query.setString(0, "%" + name + "%");
    24 
    25         Iterator<Product> iterator = query.iterate();
    26         while (iterator.hasNext()) {
    27             Product product = (Product) iterator.next();
    28             System.out.println(product.getName());
    29 
    30         }
    31 
    32         Query query2 = session.createQuery("select count(*) from Product p where p.name like ?");
    33         query2.setString(0, "%" + name + "%");
    34 
    35         long total = (Long) query2.uniqueResult();
    36         System.out.println(total);
    37 
    38         session.getTransaction().commit();
    39         session.close();
    40         sFactory.close();
    41     }
    42 
    43 }

    十一、乐观锁

      乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。

    1.场景描述:

    <1>. 通过session1得到id=1的对象 product1

    <2>. 在product1原来价格的基础上增加1000

    <3>. 更新product1之前,通过session2得到id=1的对象product2

    <4>. 在product2原来价格的基础上增加1000

    <5>. 更新product1

    <6>. 更新product2

    最后结果是product的价格只增加了1000,而不是2000

    代码:

     1 package hibernate.test;
     2 
     3 import org.hibernate.Session;
     4 import org.hibernate.SessionFactory;
     5 import org.hibernate.cfg.Configuration;
     6 
     7 import hibernate.pojo.Product;
     8 
     9 public class testOptimisticLock {
    10     /*
    11      * 场景描述 1. 通过session1得到id=1的对象 product1 2. 在product1原来价格的基础上增加1000
    12      * 3.更新product1之前,通过session2得到id=1的对象product2 4. 在product2原来价格的基础上增加1000
    13      * 5.更新product1 6. 更新product2
    14      */
    15 
    16     public static void main(String[] args) throws InterruptedException {
    17         // TODO Auto-generated method stub
    18 
    19         SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
    20         Session session = sFactory.openSession();
    21         Session session2 = sFactory.openSession();
    22 
    23         session.beginTransaction();
    24         session2.beginTransaction();
    25 
    26         Product product = (Product) session.get(Product.class, 1);
    27         System.out.println("产品原价为:" + product.getPrice());
    28         product.setPrice(product.getPrice() + 1000);
    29 
    30         Product product2 = (Product) session2.get(Product.class, 1);
    31         product2.setPrice(product2.getPrice() + 1000);
    32 
    33         session.update(product);
    34         session2.update(product2);
    35 
    36         session.getTransaction().commit();
    37         session2.getTransaction().commit();
    38 
    39         Product product3 = (Product) session.get(Product.class, 1);
    40         System.out.println("最终的价格:" + product3.getPrice());
    41 
    42         session.close();
    43         session2.close();
    44         sFactory.close();
    45     }
    46 
    47 }

     

    2.修改配置文件 Product.hbm.xml

    <version name="version" column="ver" type="int"></version>增加一个version字段,用于版本信息控制。这就是乐观锁的核心机制。

    比如session1获取product1的时候,version=1。 那么session1更新product1的时候,就需要确保version还是1才可以进行更新,并且更新结束后,把version改为2。
    注意: version元素必须紧跟着id后面,否则会出错。

     

     1 <?xml version="1.0"?>
     2 <!DOCTYPE hibernate-mapping PUBLIC
     3         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
     4         "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
     5  
     6 <hibernate-mapping package="hibernate.pojo">
     7     <class name="Product" table="product">
     8         <id name="id" column="id">
     9             <generator class="native">
    10             </generator>
    11         </id>
    12         <!--version元素必须紧挨着id后面  -->
    13         <version name="version" column="ver" type="int"></version>
    14         <property name="name" />
    15         <property name="price" />
    16         <many-to-one name="category" class="Category" column="cid"></many-to-one>
    17         <set name="users" table="user_product" lazy="false" >
    18             <key column="pid"></key>
    19             <many-to-many column="uid" class="User"></many-to-many>
    20         </set>
    21     </class>
    22      
    23 </hibernate-mapping>

    3.修改 Product.java

    增加version属性

     1 package hibernate.pojo;
     2 
     3 import java.util.Set;
     4 
     5 public class Product {
     6     int id;
     7     String name;
     8     float price;
     9     Category category;
    10     Set<User> users;
    11     int version;
    12     int cid;
    13 
    14     public int getId() {
    15         return id;
    16     }
    17 
    18     public void setId(int id) {
    19         this.id = id;
    20     }
    21 
    22     public String getName() {
    23         return name;
    24     }
    25 
    26     public void setName(String name) {
    27         this.name = name;
    28     }
    29 
    30     public float getPrice() {
    31         return price;
    32     }
    33 
    34     public void setPrice(float price) {
    35         this.price = price;
    36     }
    37 
    38     public Category getCategory() {
    39         return category;
    40     }
    41 
    42     public void setCategory(Category category) {
    43         this.category = category;
    44     }
    45 
    46     public Set<User> getUsers() {
    47         return users;
    48     }
    49 
    50     public void setUsers(Set<User> users) {
    51         this.users = users;
    52     }
    53 
    54     public int getCid() {
    55         return cid;
    56     }
    57 
    58     public void setCid(int cid) {
    59         this.cid = cid;
    60     }
    61 
    62     public int getVersion() {
    63         return version;
    64     }
    65 
    66     public void setVersion(int version) {
    67         this.version = version;
    68     }
    69 
    70 }

    4.再次运行代码

    5.原理

    <1>. 假设数据库中产品的价格是10000,version是10
    <2>. session1,session2分别获取了该对象
    <3>. 都修改了对象的价格
    <4>. session1试图保存到数据库,检测version依旧=10,成功保存,并把version修改为11
    <5>. session2试图保存到数据库,检测version=11,说明该数据已经被其他人动过了。 保存失败,抛出异常

    相关代码:https://github.com/lyj8330328/hibernate.git

  • 相关阅读:
    The Preliminary Contest for ICPC China Nanchang National Invitational and International Silk-Road Programming Contest
    HDU 5299 Circles Game
    UVALive
    算法笔记--匈牙利算法
    算法笔记--Splay && Link-Cut-Tree && fhq _treap
    P2685 [TJOI2012]桥
    2017-2018 ACM-ICPC German Collegiate Programming Contest (GCPC 2017)
    ACM-ICPC2018南京赛区 Mediocre String Problem
    Project Euler 345: Matrix Sum
    算法笔记--manacher算法
  • 原文地址:https://www.cnblogs.com/lyj-gyq/p/9190741.html
Copyright © 2020-2023  润新知