6.flush刷新(hibernate笔记)

一、复习数据库隔离级别

隔离级别 是否存在脏读 是否存在不可重复读 是否存在幻读
Read UnCommitted Y Y Y
Read Committed N Y Y
Repeated Read N N Y
Serializable N N N

说明:

  • Read UnCommitted表示未提交读,即在未提交之前我们就可以读到数据,也就是脏读。Read Committed表示提交之后才能读到数据。Repeated Read表示可重复读。Serializable表示序列化读。

  • 不可重复读的意思是说我们第一次读到数据,但是别人也能读到,而当别人将数据改变之后我刷新再读,发现两次读到的数据不一样了,这就是不可重复读。不能避免别人修改或添加。

  • 幻读的意思是第一次根据相应的条件查出来了10条数据,但是此时别人又录入了数据,我再次查询发现同样条件可以查出来20条数据,两次结果不一样了。就是说避免不了别人添加,但是可以避免别人修改。

  • 隔离级别由低到高,一般使用Read Committed这个级别,这个级别存在不可重复读取,但是我们可以使用相应的锁就可以避免了,而最后一种使用的极少,因为是序列化了,变成串行的了,并发性太差了。MySQL的默认隔离级别是Repeated Read,Oracle的默认级别是Read Committed

二、Session flush测试(工程hibernate_session_flush

SessionFlushTest.java

package junit.test;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import cn.itcast.model.User1;
import cn.itcast.model.User2;
import cn.itcast.model.User3;
import cn.itcast.util.HibernateUtils;

public class SessionFlushTest {
    
    //测试uuid主键生成策略
    @Test
    public void testSave1(){
        Session session = HibernateUtils.getSession();
        Transaction tx = null;
        try{
            tx = session.beginTransaction();
            User1 user1 = new User1();
            user1.setName("张三1");
            user1.setPassword("123");
            user1.setCreateTime(new Date());
            user1.setExpireTime(new Date());
            //这里因为user1的主键生成策略采用的是id,所以调用save方法后,只是将user1纳入到session的管理
            //不会发出insert语句,但是id已经生成,session中existsInDatabase状态为false,表示在数据库中还不存在
            session.save(user1);
            
            //调用flush时hibernate会清理缓存,发出sql语句
            //那么我们可以看到flush过的数据并且session中existsInDatabase状态为true,但是在数据库中看不到
            //因为MySQL的默认隔离级别是Read Committed
            //session.flush();
            
            //默认情况下,commit操作会先执行flush清理缓存,所以不用显示的调用flush
            //commit后数据是无法回滚的。
            tx.commit();
            
            
        }catch(Exception e){
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
    
    //测试native主键生成策略
    @Test
    public void testSave2(){
        Session session = null;
        Transaction tx = null;
        try {
            session = HibernateUtils.getSession();
            tx = session.beginTransaction();
            User2 user2 = new User2();
            user2.setName("张三");
            user2.setPassword("123");
            user2.setCreateTime(new Date());
            user2.setExpireTime(new Date());
            
            //因为主键生成策略是native,所以调用save方法后,将立刻发出sql语句,返回由数据库生成的id
            //纳入session的管理,修改了session中existsInDatabase的状态为true
            //如果数据库的隔离级别设置为Read Committed,那么那么我们是看不到save添加过的数据
            session.save(user2);
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
    
    //测试uuid主键生成策略
    @Test
    public void testSave3(){
        Session session = HibernateUtils.getSession();
        Transaction tx = null;
        try{
            tx = session.beginTransaction();
            User1 user1 = new User1();
            user1.setName("张三2");
            user1.setPassword("123");
            user1.setCreateTime(new Date());
            user1.setExpireTime(new Date());

            session.save(user1);
            
            //这里如果我们事先进行手工刷新,会将user1对象保存到数据库中,将sess中的insertions中的user1对象
            //清除,并且设置existsInDatabase为true,那么此时是可以成功提交的。
            //session.flush();
            
            //将user1对象从session中逐出,即session的EntityEntries对象中逐出
            session.evict(user1);
            
            //此时是无法成功提交的,因为hibernate在清理缓存时,在session的insertions集合中取出user1对象进行
            //insert操作后,需要更新EntityEntries对象中的existsInDatabase为true,而我们已经将user1对象逐出
            //所以找不到相关数据,无法更新,抛出异常。
            tx.commit();
            
            
        }catch(Exception e){
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
    
    //测试native主键生成策略
    @Test
    public void testSave4(){
        Session session = null;
        Transaction tx = null;
        try {
            session = HibernateUtils.getSession();
            tx = session.beginTransaction();
            User2 user2 = new User2();
            user2.setName("张三");
            user2.setPassword("123");
            user2.setCreateTime(new Date());
            user2.setExpireTime(new Date());

            session.save(user2);
            
            //这里就算将对象逐出,但是这种主键生成策略中在使用save方法后默认是执行flush的,即
            //已经将数据保存到数据库中了,还是可以成功提交的
            session.evict(user2);
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }   
    
    //测试assigned主键生成策略
    @Test
    public void testSave5(){
        Session session = null;
        Transaction tx = null;
        try {
            session = HibernateUtils.getSession();
            tx = session.beginTransaction();
            User3 user3 = new User3();
            user3.setId("001");
            user3.setName("张三");

            session.save(user3);
            
            user3.setName("王五");
            session.update(user3);
            
            User3 user4 = new User3();
            user4.setId("002");
            user3.setName("李四");
            session.save(user4);
            
            /*
             *  Hibernate: insert into _user3 (name, password, createTime, expireTime, id) values (?, ?, ?, ?, ?)
                Hibernate: insert into _user3 (name, password, createTime, expireTime, id) values (?, ?, ?, ?, ?)
                Hibernate: update _user3 set name=?, password=?, createTime=?, expireTime=? where id=?
                hibernate会按照save(insert)、update、delete的顺序提交相关的操作
             * */
            
            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
    
    //测试assigned主键生成策略
    @Test
    public void testSave6(){
        Session session = null;
        Transaction tx = null;
        try {
            session = HibernateUtils.getSession();
            tx = session.beginTransaction();
            User3 user3 = new User3();
            user3.setId("003");
            user3.setName("张三");

            session.save(user3);
            
            user3.setName("王五");
            session.update(user3);
            //如果手动进行刷新,那么会hibernate会按照我们的操作顺序执行相关的操作
            session.flush();
            
            User3 user4 = new User3();
            user4.setId("004");
            user3.setName("李四");
            session.save(user4);

            tx.commit();
        } catch (Exception e) {
            e.printStackTrace();
            tx.rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
}

说明:

  • 1.从测试方法1中我们可以看到使用uuid主键生成策略在使用save方法的时候不会发出相关的sql语句,只有在提交的时候清理缓存时才会发出相应的sql语句。当然我们可以在使用save方法之后手动进行flush清理缓存,那样是会发出sql语句的。但是这样即使我们保存在数据库中了,在提交之前还是会因为数据库的隔离级别的问题而看不到数据。

  • 2.从测试方法2中我们可以看到使用native这种主键生成策略在使用save方法时是会立即清理缓存,发出相关sql语句的。同时save方法执行之后提交之前同样是看不到数据的。还要注意此时实体类中id的类型是int型而不是String类型。

  • 3.测试方法3和4再次说明了这个问题,即uuid主键生成方式中不会自动刷新,而native主键生成方式则会自动刷新。

  • 4.测试方法5和6中采用的自己分配主键,此时hibernate会按照save(insert)、update、delete的顺序提交相关的操作,而不会自动刷新,当然如果我们使用手动刷新,那么hibernate会按照我们自己的顺序执行相关的操作。

最后:

  • flush方法主要做清理缓存和执行sql这两个工作;
  • session在下列情况下执行flush:1.默认在事务提交的时候;2.显式调用flush方法时;3.在执行查询前,如:iterate
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容