Use of session.flush()

Session flush will be executed by default before commit. It can also be executed manually, he mainly does two things: 
1) Clear the cache. 
2) Execute SQL. 

Under what circumstances does the session execute flush 
* The default is when the transaction is submitted 
* The displayed call flush 
* Before executing the query, such as: iterate 
hibernate submits related operations in the order of save(insert), update, delete 

********* **************************************************** ********** 
In the following cases, Hibernate will call Session.flush() to clear the cache:     
1) When the transaction commits, if the flush mode is not FlushMode.NEVER, commit() will call flush() ).     
2) Before some query statements (the statement before this query statement has changed the database state, so it is necessary to call flush() to synchronize the database. The data found out has been changed). When Session.flush() is called, the SQL statements involved are executed in the following order. 
(1) All entity insertion statements are in the order of the time when the object executes Session.save(). 
(2) All entity update statements 
(3) All collection deletion statements 
(4) All collection elements Statements that perform delete, update, or insert 
(5) All statements that perform set inserts 
(6) All statements that delete entities are in the order of the time when the object executes Session.delete(). (7) One exception is that if objects use natively generated IDs (persistent identifiers), they will be inserted as soon as they execute save. Unless the flush() command is explicitly specified, there is absolutely no guarantee about when the Session will execute these JDBC calls, only the order in which they are executed. 

By setting session.setFlushMode(), the FlushMode of Hibernate can be precisely controlled. 
(1) FlushMode.AUTO: Hibernate judges whether the object properties have changed. If it is changed into dirty data, it will update this change in a query statement to ensure the database synchronization. This is also Hibernate's default cleanup mode. (2) FlushMode.COMMIT: Clear the cache of the session before the end of the transaction. This may lead to the detection of dirty data 
(3) FlushMode.NEVER: Unless the Session.flush() is forced to be called, the Session will never be cleaned up. Think of setting the database as a read-only database. 
(4) FlushMode.ALWAYS: Session.flush() is called before each query data. Obviously this efficiency is very low.    
It only makes sense to call Session.flush() directly when using triggers, or when mixing Hibernate and JDBC. 


Note: 
Things can be rolled back without commit, that is, before committing. 

隔离级别              脏读  不可重复读  幻读 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); 



}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326552254&siteId=291194637