session.flush()理解

刚刚开始时,阅读孙维琴的《精通 Hibernate:Java对象持久化技术详解.pdf》一书,由于不仔细误解了书中的意思,书中的意思是当程序显式调用 session. flush()方法时, session清理缓存,而我却误解为 清空 缓存。差之毫厘,谬之千里...

   清理是什么意思呢?一下是《精通 Hibernate:Java 对象持久化技术详解.pdf》的说法:

    Session加载了一个PO对象,会为这个PO对象的值类型的属性复制一份快照,当Session清理缓存时,通过比较PO对象的当前属性与它的快照,Session能够判断PO对象的哪些属性发生了变化。

   就是说,清理的意思就是让PO对象的快照与PO对象同步。

   在网上查了一下,关于session.flush()对这个方法有的误解的人还不止我一个,误解的地方也各不相同,所以想先做些关于这个方法的实验,然后把结果写出来,大家一起探讨阿,呵呵。

    引用一下《精通Hibernate:Java 对象持久化技术详解.pdf》中的原话吧:

   注意Session的commit()和flush()方法的区别。flush()方法进行清理缓存的操作,执行一系列的SQL语句,但不会提交事务;commit()方法会先调用flush()方法,然后提交事务。提交事务意味着对数据库所做的更新被永久保存下来。

   先建一个简单的Hibernate项目,数据库只有一个表:很简单,就为做session.flush()的实验,没有任何实际的业务逻辑。

DAO的代码如下:

L01-package com.dao;

L02-import org.hibernate.Session;
L03-import org.hibernate.Transaction;

L04-import com.HibernateSessionFactory;
L05-import com.po.User1;

L06-public class User1DAO {

L07- Session se =HibernateSessionFactory.getSession();
L08- User1 user =null;

L09- public void modifyUser() throws Exception
L10- {
L11-    Transaction tx = null;

L12-    tx = se.beginTransaction();
L13-    user = (User1)se.get(User1.class, "id1");
L14-    user.setName("name1_2");

L15-    se.flush();
L16-    System.out.println(user.getName());//在这一行设置断点

L17-    tx.commit();
L18-    System.out.println(user.getName());

L19-    se.close();
L20- }

L21- public static void main(String[] args) throws Exception{
L22-    User1DAO user1DAO = new User1DAO();
L23-    user1DAO.modifyUser();
L24- }
L25-}

   在第16行设置断点,当程序运行到断点时,我们看看se.flush()这个方法做了些什么,程序不要往下运行,让程序在断点处保持挂起,打开数据库的企业管理器(SQLSERVER2000),出现下面的情况:

   数据库连接超时,这说明什么??如果把企业管理器也看作一个事务,那么就是有另一个事务锁住了数据库,导致企业管理器这个事务无法看到数据,另一个事务是谁呢,就是session.flush()它了。那么session.flush()的作用就是让数据库执行SQL语句,但是不提交。所以只要程序一直在断点处挂起,其他的事务就不能看到数据。即便是使用企业管理企业也不行。

   但是为什么要这样呢??没有事务会引起的问题之一就是脏读——A事务读取了B事务尚未提交的更改数据,并在这个数据的基础上操作。所以如果假如企业管理器能让你看到数据,那看到的就是脏数据,SQLServer当然不允许这样的事情发生。

   另外还有两点说明:

   1. 在程序的第14行,user.setName("name1_2");使用setter方法对user的name属性赋了新值,假如没有赋值

  • a.没有调用setName(String)方法。
  • b.调用了setName(String)方法,但是参数与原来数据库中的值相同(都是"name1_1")

两种方式的结果是相同的,Hibernate都不会生成update的sql语句,也都不会锁数据库,大家可以试一下。
   2.是什么级别的锁呢?
   这个通过企业管理器貌似看不出来,打开查询分析器看看。
    select *fromdbo.User1;                --对整个表的查询
    select *from dbo.User1 where id='id1'; --对正在修改的那一行的查询
    select *from dbo.User1 where id='id2';  --对其他行的查询
在查询分析器里,第一二句sql都因为记录被锁而无法查出数据,只有第三行记录可以查出数据。
   所以结论是当程序执行se.flush()时,数据库上的锁是行级别的独占锁。
                                                               
还没完,企业管理其不能看,那么理论上另一个Session也不能得到数据,试试看:
L01- package com.dao;

L02- import org.hibernate.Session;
L03- import org.hibernate.Transaction;

L04- import com.HibernateSessionFactory;
L05- import com.po.User1;

L06- public class User1DAO {

L07- Session se =HibernateSessionFactory.getSession();
L08- Session se2 =HibernateSessionFactory.getSession2();
L09- User1 user =null;

L10- public void modifyUser() throws Exception
L11- {
L12-    Transaction tx = null;

L13-    tx = se.beginTransaction();
L14-    user = (User1)se.get(User1.class, "id1");
L15-    user.setName("name1_1");

L16-    se.flush();
L17-    //tx.commit();
L18-    //se.close();
L19- }

L20- public void modifyUser2() throws Exception
L21- {
L22-    Transaction tx = null;
L23-    tx = se2.beginTransaction();
L24-    user = (User1)se2.get(User1.class, "id1");
L25-    System.out.println(user.getName());
L26-    tx.commit();
L27- }

L28- public static void main(String[] args) throws Exception{
L29-    User1DAO user1DAO = new User1DAO();
L30-    user1DAO.modifyUser();
L31-    user1DAO.modifyUser2();
L32- }
L33- }
   加一个modifyUser2方法,modifyUser方法没有事务提交,没有关闭Session,接着执行modifyUser2,modifyUser2里创建一个新的Session实例se2,想用se2取数据,取不出来,程序一直停在那里。。。
另外还要注意一下Hibernate的锁(乐观的和悲观的)。
注:有一个存疑,这里第17、18行把tx.commit()和se.close()注释掉了,但是如果把se.close()注释打开,tx.commit()依然注释着,修改的数据更新到数据库了,并且提交了,modifyUser2也可以读出来数据了,好像tx.commit()会自动调用Transaction.commit(),而且不是调用Transaction.rollback();这个还要请大家多指教阿。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值