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);
}
}
}
分享到:
相关推荐
在实际应用中,`Session.flush()`的使用场景包括: 1. **数据一致性**:当你需要确保内存中的修改立即反映到数据库时,比如在并发环境中,防止数据丢失或冲突。 2. **大数据量操作**:当处理大量数据时,分批`flush...
1. `session.flush()`: 这个方法的主要作用是将Session缓存中的改动同步到数据库中。在默认情况下,Hibernate并不会立即更新数据库,而是等到事务提交或者Session关闭时才进行同步。`flush()`方法强迫Hibernate执行...
由于`evict()`操作将`cat`从`entityEntries`中移除,但在事务提交时(即Flush操作时),Hibernate无法找到`cat`对象的引用,从而导致`AssertionFailure`异常,提示可能的非线程安全访问或不正确的Session使用。...
在 Hibernate 中,使用 Session 的缓存机制可以提高性能,但如果不正确地使用缓存,可能会出现内存溢出错误。例如,如果我们使用 Hibernate 对数据库插入 100,000 条数据,可能会出现内存溢出错误,因为 Hibernate ...
根据提供的文件信息,我们可以深入探讨Hibernate中的几个关键概念与操作,包括`Session.flush()`方法的使用、不同主键生成策略下的保存操作等。 ### Hibernate Session.flush() 方法详解 #### 一、基本概念 在...
同样,我们需要定期调用`flush()`和`clear()`以控制内存使用。例如: ```java Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); ScrollableResults customers = ...
1. **定时刷新缓存**:在循环过程中,设定一定的阈值(如每20条记录),当达到该阈值时,使用`session.flush()`将缓存中的数据写入数据库,并使用`session.clear()`清空缓存,以释放内存空间。 ```java for (int...
在每次更新后调用`session.flush()`强制Hibernate执行当前的数据库操作,然后使用`session.evict(entity)`将实体从缓存中移除。这样做可以确保每个更新操作仅执行一次,并且避免了持久化上下文中的内存浪费。 ```...
使用Session的createCriteria()或createQuery()方法查询数据,然后调用list()获取结果列表。 ```java List<User> users = session.createCriteria(User.class).list(); for (User u : users) { System.out.println...
- 显式调用`session.flush()`方法。 总结来说,Hibernate的持久化机制和一级缓存是其高效处理数据库操作的关键。理解并熟练掌握这些概念,可以帮助开发者编写更高效、更易于维护的Java应用。在实际项目中,合理利用...
在实际使用中,开发者通常会在一个`Session`生命周期内进行一系列操作,然后在适当的时候调用`flush()`方法强制Hibernate同步数据库,最后在事务结束时调用`commit()`来完成事务。这些方法的正确组合使用是实现高效...
1. **使用`removeAttribute()`方法移除Session中的特定属性** 如果只需要移除Session中的某个特定属性(比如用户名),可以使用`removeAttribute()`方法来实现: ```java session.setAttribute("name", "iverson...
1. **使用`flush()`和`evict()`方法**:在修改实体后,主动调用`session.flush()`方法,使Hibernate将缓存中的变更同步到数据库,然后调用`session.evict(entity)`方法,从缓存中移除实体,这样下一次操作不会受到...
session.flush(); session.clear(); } } transaction.commit(); session.close(); ``` 以上就是使用Hibernate连接MySQL数据库的基本步骤和操作示例。注意,实际应用中还需要考虑事务管理、异常处理、性能...
解决方法是使用事务和 flush() 方法来清空缓存。例如: ```java Transaction tx = session.beginTransaction(); for (int i = 0; i ; i++) { News n = new News(); session.save(n); if (i % 20 == 0) { session...
当我们在Session上进行操作时,这些操作不会立即反映到数据库中,而是被缓存起来,直到调用`flush()`方法或者事务提交时才会真正执行。 在开始使用Session之前,需要配置Hibernate的环境,包括创建SessionFactory,...
session.flush(); } ``` **解析:** - `getCurrentSession()`方法用于获取当前的`Session`实例。 - `save()`方法用于将`item`对象持久化到数据库中。 - `flush()`方法用于刷新缓存并执行所有未完成的持久化操作。 ...
通过合理利用`flush()`、`evict()`以及直接使用JDBC执行SQL,可以有效地处理大数据量的更新和删除操作,降低内存占用并减少对数据库的访问次数。在实际开发中,应根据具体需求和数据规模选择合适的方法,确保系统...
例如,登录成功后,可以使用`session.setAttribute("username", username)`将用户名保存在Session中,之后在其他页面可以使用`session.getAttribute("username")`来验证用户身份。 在实际开发中,这三个对象的协同...
然而,在实际应用中,如果开发者希望对事务进行更细粒度的控制,可以考虑使用`@Transactional`注解或者显式地使用`Session`的`beginTransaction`和`commit`/`rollback`方法来进行事务管理。需要注意的是,直接在`...