• 理解hibernat的flush(转)


    *SessionFlush:

    *session flush方法主要做了两件事:

         清理临时记录

         执行sql

    *session在什么情况下执行flush

         默认在事务提交时(commit)

         显示的调用flush

         在执行查询前,如:iterate

    hibernate按照save(insert),update、delete顺序提交相关操作

    !!只要事务没有commit,就随时可以回滚 !!

    所有状态都适用:

    flush:清的是临时记录!!!!!

    elementData临时数据,entryArray缓存数据:只有在save后才有数据!!与三个状态有关

    调用commit的时候默认会先执行flush()

    uuid:commit时的flush清理临时记录

    save后:Hiernate就分配一个32的字符串,数据库中没有记录,elementData临时记录:有数据,entryArray缓存中:有记录,existsInDatabase:flase,纳入了session管理.

    【如果此时执行:session.evict(user);//逐出缓存,清的是缓存中的记录,但临时集合没有清掉. 然后再执行commit,flush时发现临时集合有数据,就会发insert,然后找缓存记录,把existsInDatabase状态变为true,因为缓存清掉了(existsInDatabase也没了),所以有问题,抛异常】【上述问题的解决:save()完后执行flush(发sql,清临时集合,找缓存,改变esistsInDatabase状态),然后执行逐出,清理缓存,再执行commit,找临时集合有没数据,有的话发sql,已经flush了,所以没数据,不发sql】

    flush后:清理临时集合,发sql,existsInDatabasse:true,临时集合没有数据了,但是由于隔离级别,MySQL数据库是查不到的。缓存中有记录。

    commit后:数据不可回滚了,commit默认会先执行flush();所以不用显示调用

    native:save清临时记录

    save后:执行insert语句,清理临时记录。返回由数据库生成的id,纳入session管理因为缓存的map中有记录了,其中:id是由数据库返回的。临时数据中没记录(永远也看不到:save前没有save后也没有,只有save过程中才有,一旦发了sql临时记录中就没有记录了)

    【此时执行session.evict(user),没问题,与uuid的区别!!!】

    flush后:临时记录在save的时候已经清了

    commit后:数据不可回滚了

    不管什么策略:执行commit()默认会先执行flush(),commit()后数据无法回滚!!

    assigned:flush情况和uuid相同,因为id new对象的时候给出了,不用数据库里取.

                                Uuid是Hibernate自动生成了,也不用数据库里取

    public void testSave3(){

           Session session = null;

           Transaction tx = null;

          

           try{

               session = HibernateUtils.getSession();

               tx = session.beginTransaction();

               //Transient 瞬时状态

               User3 user = new User3();

               user.setId("0001");

               user.setName("张三");

              

               session.save(user);

              

               user.setName("王五");

               session.update(user);//此行可以不写,因为此时为持久状态,Hibernate会自动同步

              

               User3 user3 = new User3();

               user3.setId("002");

               user3.setName("李四");

               session.save(user3);

               System.out.print("hell");

               tx.commit();//此时发sql,hibernate按照save(insert),update、delete顺序提交相关操作,而上面的顺序是:保存、更新、保存。发的顺序发insert,insert,update。//如果在user.setName("王五");前先执行session.flush();则先发两条sql,然后最后commit的时候再发一条insert。所有,发sql的顺序按我们的意愿执行。 

           }catch(Exception e){

               e.printStackTrace();

               tx.rollback();

           }finally{

               HibernateUtils.closeSession(session);

           }  

        }

    数据库隔离级别:解决并发性问题

    隔离级别                                             是否存在脏读        是否存在不可重复读    是否存在幻读

    Read Unommited(未提交读)                           Y                   Y                           Y

    Read Commited(提交读,Oracle默认的)              N             Y 与悲观锁有关               Y

    Repeatable Read(可重复读,MySql默认)           N                    N                         Y

    Serialiazble(序列化读)                                    N                   N                          N

    隔离级别低到高:MySQL隔离级别高于Oracle

    序列化读:并发性最差,一个人独占!

    脏读:没有提交数据就读到

    不可重复读:第一次读出来为张三,再刷新一次为李四,悲观锁锁住就变成可重复读了

    存在幻读:影响的是插入操作。A读出5条记录,刷新变成十条记录,新增了5条。

    序列化读:锁住表,别人不可能添加数据。

    查看mysql的隔离级别: select @@tx_isolation; 默认级别可重复读,必须提交了才可以看得到

    改隔离级别为未提交读:set transaction  isolation level read uncommitted

    package com.guojie.hibernate;

    import java.util.Date;

    import org.hibernate.Session;

    import org.hibernate.Transaction;

    import com.guojie.hibernate.HibernateUtils;

    import com.guojie.hibernate.User1;

    import com.guojie.hibernate.User2;

    import com.guojie.hibernate.User3;

    import junit.framework.TestCase;

    public class SessionFlushTest extends TestCase {

       

        /**

         * 测试uuid主键生成策略

         */

        public void testSave1() {

           Session session = null;

           Transaction tx = null;

           try {

               session = HibernateUtils.getSession();

               tx = session.beginTransaction();

               User1 user = new User1();

               user.setName("李四");

               user.setPassword("123");

               user.setCreateTime(new Date());

               user.setExpireTime(new Date());

              

               //因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理

               //不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false

               session.save(user);

              

               //调用flush,hibernate会清理缓存,执行sql

               //如果数据库的隔离级别设置为为提交读,那么我们可以看到flush过的数据

               //并且session中existsInDatebase状态为true

               session.flush();

              

               //提交事务

               //默认情况下commit操作会先执行flush清理缓存,所以不用显示的调用flush

               //commit后数据是无法回滚的

               tx.commit();

           }catch(Exception e) {

               e.printStackTrace();

               tx.rollback();

           }finally {

               HibernateUtils.closeSession(session);

           }

        }

       

        /**

         * 测试native主键生成策略

         */

        public void testSave2() {

           Session session = null;

           Transaction tx = null;

           try {

               session = HibernateUtils.getSession();

               tx = session.beginTransaction();

               User2 user = new User2();

               user.setName("张三1");

               user.setPassword("123");

               user.setCreateTime(new Date());

               user.setExpireTime(new Date());

              

               //因为user的主键生成策略为native,所以调用session.save后,将执行insert语句,返回有数据库生成的id

               //纳入了session的管理,修改了session中existsInDatebase状态为true

               //如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据

               session.save(user);

               tx.commit();

           }catch(Exception e) {

               e.printStackTrace();

               tx.rollback();

           }finally {

               HibernateUtils.closeSession(session);

           }

        }

       

       

        /**

         * 测试uuid主键生成策略

         */

        public void testSave3() {

           Session session = null;

           Transaction tx = null;

           try {

               session = HibernateUtils.getSession();

               tx = session.beginTransaction();

               User1 user = new User1();

               user.setName("王五");

               user.setPassword("123");

               user.setCreateTime(new Date());

               user.setExpireTime(new Date());

              

               //因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理

               //不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false

               session.save(user);

              

               //将user对象从session中逐出,即session的EntityEntries属性中逐出

               session.evict(user);

              

               //无法成功提交,因为hibernate在清理缓存时,在session的insertions集合中取出user对象进行insert操作后

               //需要更新entityEntries属性中的existsInDatabase为true,而我们采用evict已经将user从session的entityEntries

               //中逐出了,所以找不到相关数据,无法更新,抛出异常

               tx.commit();

           }catch(Exception e) {

               e.printStackTrace();

               tx.rollback();

           }finally {

               HibernateUtils.closeSession(session);

           }

        }

       

        /**

         * 测试uuid主键生成策略

         */

        public void testSave4() {

           Session session = null;

           Transaction tx = null;

           try {

               session = HibernateUtils.getSession();

               tx = session.beginTransaction();

               User1 user = new User1();

               user.setName("王五");

               user.setPassword("123");

               user.setCreateTime(new Date());

               user.setExpireTime(new Date());

              

               //因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理

               //不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false

               session.save(user);

              

               //flush后hibernate会清理临时集合,会将user对象保存到数据库中,将session中的insertions中的user对象

               //清除,并且设置session中existsInDatebase的状态为true

               session.flush();

              

               //将user对象从session中逐出,即session的EntityEntries属性中逐出

               session.evict(user);

              

               //可以成功提交,因为hibernate在清理临时集合时,在session的insertions集合中无法找到user对象

               //所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态

               tx.commit();

           }catch(Exception e) {

               e.printStackTrace();

               tx.rollback();

           }finally {

               HibernateUtils.closeSession(session);

           }

        }

       

        /**

         * 测试native主键生成策略

         */

        public void testSave5() {

           Session session = null;

           Transaction tx = null;

           try {

               session = HibernateUtils.getSession();

               tx = session.beginTransaction();

               User2 user = new User2();

               user.setName("张三11");

               user.setPassword("123");

               user.setCreateTime(new Date());

               user.setExpireTime(new Date());

              

               //因为user的主键生成策略为native,所以调用session.save后,将执行insert语句,返回有数据库生成的id

               //纳入了session的管理,修改了session中existsInDatebase状态为true

               //如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据

               session.save(user);

              

               //将user对象从session中逐出,即session的EntityEntries属性中逐出

               session.evict(user);

              

               //可以成功提交,因为hibernate在清理缓存时,在session的insertions集合中无法找到user对象

               //所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态

               tx.commit();

           }catch(Exception e) {

               e.printStackTrace();

               tx.rollback();

           }finally {

               HibernateUtils.closeSession(session);

           }

        }

       

        /**

         * 测试assigned主键生成策略

         *

         */

        public void testSave6() {

           Session session = null;

           Transaction tx = null;

           try {

               session = HibernateUtils.getSession();

               tx = session.beginTransaction();

               User3 user = new User3();

               user.setId("001");

               user.setName("张三");

              

               session.save(user);

              

               user.setName("王五");

               session.update(user);

              

               User3 user3 = new User3();

               user3.setId("002");

               user3.setName("李四");

               session.save(user3);

              

               //Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)

               //Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)

               //Hibernate: update t_user3 set name=?, password=?, create_time=?, expire_time=? where user_id=?

               //hibernate按照save(insert),update、delete顺序提交相关操作

               tx.commit();

           }catch(Exception e) {

               e.printStackTrace();

               tx.rollback();

           }finally {

               HibernateUtils.closeSession(session);

           }

        }  

       

        /**

         * 测试assigned主键生成策略

         *

         */

        public void testSave7() {

           Session session = null;

           Transaction tx = null;

           try {

               session = HibernateUtils.getSession();

               tx = session.beginTransaction();

               User3 user = new User3();

               user.setId("003");

               user.setName("张三");

              

               session.save(user);

              

               user.setName("王五");

               session.update(user);

              

               session.flush();

              

               User3 user3 = new User3();

               user3.setId("004");

               user3.setName("李四");

               session.save(user3);

              

               //Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)

               //Hibernate: update t_user3 set name=?, password=?, create_time=?, expire_time=? where user_id=?

               //Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)

               //因为我们在session.udpate(user)后执行了flush,所以在清理缓存时执行flush前的sql不会生成

               //sql会按照我们的意愿执行

               tx.commit();

           }catch(Exception e) {

               e.printStackTrace();

               tx.rollback();

           }finally {

               HibernateUtils.closeSession(session);

           }

        }     

    }

     

  • 相关阅读:
    windchill系统安装大概步骤
    Javase、Javaee、Javame的区别
    Cocoa Touch事件处理流程--响应者链
    iOS KVC & KVO
    GET异步 请求图片步骤
    iOS7——图像资源Images Assets
    IOS编程教程(八):在你的应用程序添加启动画面
    Objective C内存管理之理解autorelease------面试题
    runtime 运行时机制 完全解读
    图片的异步下载
  • 原文地址:https://www.cnblogs.com/Fskjb/p/1625050.html
Copyright © 2020-2023  润新知