`

session.flush()的使用

阅读更多

session flush在commit之前默认都会执行他。也可以手动执行它,他主要做了两件事: 
1) 清理缓存。 
2) 执行SQL。 

session在什么情况下执行flush 
* 默认在事务提交时 
* 显示的调用flush 
* 在执行查询前,如:iterate 
hibernate按照save(insert),update、delete顺序提交相关操作 

********************************************************************** 
在下面的情况下,Hibernate会调用Session.flush()以清理缓存:     
1)事务提交时如果flush模式不为FlushMode.NEVER,commit()将调用flush().     
2)在某些查询语句之前(此查询语句之前的语句已经改变了数据库状态,所以需要调用flush()以同步数据库是查出来的数据是经过更改的)。在调用Session.flush()时,涉及的SQL语句会按照下面的顺序执行。 
(1所有的实体进行插入的语句,其顺序按照对象执行Session.save()的时间顺序。 
(2)所有对实体进行更新的语句 
(3)所有进行集合的删除语句 
(4)所有对集合元素进行删除,更新或者插入的语句 
(5)所有进行集合插入的语句 
(6)所有对实体进行删除的语句,其顺序按照对象执行Session.delete()的时间顺序。(7)有一个例外是,如果对象使用native方式生成的ID(持久化标识),则他们一执行save就会被插入。除非明确地指定了flush()命令,否则关于Session何时会执行这些JDBC调用完全是无法保证的,只能保证他们执行的前后顺序。 

通过设置session.setFlushMode(),可以精确控制Hibernate的FlushMode. 
(1)FlushMode.AUTO:Hibernate判断对象属性有没有改变,如果被更改成为脏数据,则在一个查询语句钱将更新此改动以保证数据库的同步。这也是Hibernate的默认清理模式。(2)FlushMode.COMMIT:在事务结束之前清理session的缓存.这样有可能导致查出脏数据 
(3)FlushMode.NEVER:除非强制调用Session.flush(),否则永远不清理Session。想当于将数据库设置为一个只读的数据库。 
(4) FlushMode.ALWAYS:在每一个查询数据之前都调用Session.flush()。很显然这种效率很低。    
只用当使用触发器,或把Hibernate和JDBC混合使用,直接调用Session.flush()才是有意义的。 


注意: 
事物在没commit,即没提交之前是可以回滚的。 

隔离级别              脏读  不可重复读  幻读 ReadUncommitted   Y       Y           Y ReadCommitted      N       Y           Y RepeatableRead      N       N           Y Serializable            N       N           N ReadCommited是oracle的默认隔离级别。可以通过悲观锁,消除不可重复读。 RepeatableRead是Mysql的默认级别。 数据库的隔离级别:(设置数据库的隔离级别是为了防止并发访问)这里有几个概念:脏读,不可重复读,幻读没有提交就可以读叫脏读。不可重复读是指第一次读的时候是张三,接着再读一次变为李四了,当重复读的时候出现了错误,叫不可重复读。可以使用悲观锁来锁住,别人修改不了 
就可以避免不可重复读。幻读是指例如当查询年龄时查18到20,出现5条记录,当刷新一下就变成10条了,这叫幻读。 
1》未提交读(Read uncommit):即假如当在发出insert,但是还没执行commit就可以读,数据库中就已经存在,外部已经可以访问这个数据,这样是不安全的。这种使用的少。他存在脏读。也存在不可重复读和幻读。2》提交读(read commit):即在提交之后(commit)才可以读。大部分数据库都是采用这种。oracle默认就是这个。这种情况下避免了脏读。存在不可重复读。也存在幻读。3》可重复读(repeatable read):这个是Myswl的默认级别,只有提交了才可以读,即执行了commit之后才会在数据库中存在。他不存在不可重复读,因为当读一条记录的时候相当于加了悲观锁把锁,别人就读不到,故避免了不可重复读。但是幻读无法避免。4》序列化读(serialiaizble read):这是最高隔离级别,这个是串行的,只有你执行完之后别人才可以执行,这个是用的很少。他没有脏读,没有不可重复读也没有幻读。从1到4是从低到高的。测试: 
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后数据是无法回滚的,没有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); 



}

分享到:
评论

相关推荐

    hibernate的session.flush

    在实际应用中,`Session.flush()`的使用场景包括: 1. **数据一致性**:当你需要确保内存中的修改立即反映到数据库时,比如在并发环境中,防止数据丢失或冲突。 2. **大数据量操作**:当处理大量数据时,分批`flush...

    hibernate的flush()、refresh()、clear()针对一级缓存的操作的区别.docx

    1. `session.flush()`: 这个方法的主要作用是将Session缓存中的改动同步到数据库中。在默认情况下,Hibernate并不会立即更新数据库,而是等到事务提交或者Session关闭时才进行同步。`flush()`方法强迫Hibernate执行...

    hibernate的flush机制

    由于`evict()`操作将`cat`从`entityEntries`中移除,但在事务提交时(即Flush操作时),Hibernate无法找到`cat`对象的引用,从而导致`AssertionFailure`异常,提示可能的非线程安全访问或不正确的Session使用。...

    2022年Hibernate下数据批量处理Java教程.docx

    在 Hibernate 中,使用 Session 的缓存机制可以提高性能,但如果不正确地使用缓存,可能会出现内存溢出错误。例如,如果我们使用 Hibernate 对数据库插入 100,000 条数据,可能会出现内存溢出错误,因为 Hibernate ...

    Hibernate code

    根据提供的文件信息,我们可以深入探讨Hibernate中的几个关键概念与操作,包括`Session.flush()`方法的使用、不同主键生成策略下的保存操作等。 ### Hibernate Session.flush() 方法详解 #### 一、基本概念 在...

    Hibernate下数据批量处理解决方案

    同样,我们需要定期调用`flush()`和`clear()`以控制内存使用。例如: ```java Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); ScrollableResults customers = ...

    Hibernate批量处理数据

    1. **定时刷新缓存**:在循环过程中,设定一定的阈值(如每20条记录),当达到该阈值时,使用`session.flush()`将缓存中的数据写入数据库,并使用`session.clear()`清空缓存,以释放内存空间。 ```java for (int...

    在Hibernate中处理批量更新和批量删除

    在每次更新后调用`session.flush()`强制Hibernate执行当前的数据库操作,然后使用`session.evict(entity)`将实体从缓存中移除。这样做可以确保每个更新操作仅执行一次,并且避免了持久化上下文中的内存浪费。 ```...

    第一个hibernate程序及解释

    使用Session的createCriteria()或createQuery()方法查询数据,然后调用list()获取结果列表。 ```java List<User> users = session.createCriteria(User.class).list(); for (User u : users) { System.out.println...

    java-hibernate持久化

    - 显式调用`session.flush()`方法。 总结来说,Hibernate的持久化机制和一级缓存是其高效处理数据库操作的关键。理解并熟练掌握这些概念,可以帮助开发者编写更高效、更易于维护的Java应用。在实际项目中,合理利用...

    Hibernate持久层方法汇总

    在实际使用中,开发者通常会在一个`Session`生命周期内进行一系列操作,然后在适当的时候调用`flush()`方法强制Hibernate同步数据库,最后在事务结束时调用`commit()`来完成事务。这些方法的正确组合使用是实现高效...

    退出页面自动清除session技巧

    1. **使用`removeAttribute()`方法移除Session中的特定属性** 如果只需要移除Session中的某个特定属性(比如用户名),可以使用`removeAttribute()`方法来实现: ```java session.setAttribute("name", "iverson...

    在Hibernate应用中处理批量更新和批量删除

    1. **使用`flush()`和`evict()`方法**:在修改实体后,主动调用`session.flush()`方法,使Hibernate将缓存中的变更同步到数据库,然后调用`session.evict(entity)`方法,从缓存中移除实体,这样下一次操作不会受到...

    hibernate连接数据[Mysql]的代码实例

    session.flush(); session.clear(); } } transaction.commit(); session.close(); ``` 以上就是使用Hibernate连接MySQL数据库的基本步骤和操作示例。注意,实际应用中还需要考虑事务管理、异常处理、性能...

    hibernate性能优化.doc

    解决方法是使用事务和 flush() 方法来清空缓存。例如: ```java Transaction tx = session.beginTransaction(); for (int i = 0; i ; i++) { News n = new News(); session.save(n); if (i % 20 == 0) { session...

    hibernate--3.Hibernate数据持久化(通过 Session 操纵对象)

    当我们在Session上进行操作时,这些操作不会立即反映到数据库中,而是被缓存起来,直到调用`flush()`方法或者事务提交时才会真正执行。 在开始使用Session之前,需要配置Hibernate的环境,包括创建SessionFactory,...

    hql的增删改查

    session.flush(); } ``` **解析:** - `getCurrentSession()`方法用于获取当前的`Session`实例。 - `save()`方法用于将`item`对象持久化到数据库中。 - `flush()`方法用于刷新缓存并执行所有未完成的持久化操作。 ...

    jsp Hibernate批量更新和批量删除处理代码.docx

    通过合理利用`flush()`、`evict()`以及直接使用JDBC执行SQL,可以有效地处理大数据量的更新和删除操作,降低内存占用并减少对数据库的访问次数。在实际开发中,应根据具体需求和数据规模选择合适的方法,确保系统...

    Java Web程序设计-1期 项目库_单元案例_Request和Response-Session对象案例.doc

    例如,登录成功后,可以使用`session.setAttribute("username", username)`将用户名保存在Session中,之后在其他页面可以使用`session.getAttribute("username")`来验证用户身份。 在实际开发中,这三个对象的协同...

    HibernateTemplate类的使用

    然而,在实际应用中,如果开发者希望对事务进行更细粒度的控制,可以考虑使用`@Transactional`注解或者显式地使用`Session`的`beginTransaction`和`commit`/`rollback`方法来进行事务管理。需要注意的是,直接在`...

Global site tag (gtag.js) - Google Analytics