【发布时间】:2010-04-15 05:52:59
【问题描述】:
我正在开发一个应用程序,该应用程序需要以频繁的时间间隔或触发器从数据库中读取实体的状态。但是,一旦 hibernate 读取状态,它就不会重新读取它,除非我明确关闭会话并在新会话中读取实体。
每次我想读取实体时打开会话然后关闭它是个好主意吗?这会给应用程序和数据库带来多少开销(我们也使用 c3p0 连接池)?
在再次读取之前简单地将实体从会话中逐出就足够了吗?
【问题讨论】:
我正在开发一个应用程序,该应用程序需要以频繁的时间间隔或触发器从数据库中读取实体的状态。但是,一旦 hibernate 读取状态,它就不会重新读取它,除非我明确关闭会话并在新会话中读取实体。
每次我想读取实体时打开会话然后关闭它是个好主意吗?这会给应用程序和数据库带来多少开销(我们也使用 c3p0 连接池)?
在再次读取之前简单地将实体从会话中逐出就足够了吗?
【问题讨论】:
您也可以使用refresh 重新加载实体。或者@Bozho 提到的evict 和clear。
使用连接池,打开和关闭会话的开销并不大。需要时间的是构建会话工厂。
如果我没记错的话,关闭和重新打开会话的问题是已经加载的对象仍然会分离。这对于延迟加载可能是有问题的。所以最好保持会话打开并使用evict、clear 或refresh。
请注意,如果您驱逐实体,并访问一个已加载的此类实体,您仍将获得旧数据。
MyEntity e = session.load( ... );
...
session.evict(e); // remove entity from the cache
String p = e.myProperty; // still the value at the time it was loaded
e = sesssion.load( ... ); // latest value
在您的情况下,最好引入一个设计指南,说明只要实体被操纵,就应该首先刷新它。
MyEntity e = session.load( ... );
...
session.refresh( e ); // refresh entity and cache
String p = e.myProperty; // latest value
e = sesssion.load( ... ); // latest value
上面的代码只是伪代码,我没有查过。
请注意,如果会话打开一段时间,缓存可能会增长,在这种情况下,您可能希望仍然clear 它。一般来说,最好保持会话短,以防止缓存增长的问题,以及连接超时、事务超时和锁争用的问题。
【讨论】:
是的。 evict() 对象。如果你想清除整个会话,clear()它。
新会话应与请求(线程)或较长时间的会话相关联。
【讨论】:
对于链接到其他表的列,如果您将 fetchtype 设置为 LAZY,Hibernate 将不会加载该数据,直到它被明确要求。这样可以节省很多时间。
Table 中的列可以被标记:
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="other_table_id", nullable = false)
private OtherTable otherTable;
因此,直到您执行Table.getOtherTable().getValue() 之类的操作,OtherTable 才会加载到会话中。所以如果你不做那件事,你也不需要驱逐它。
请注意,这是伪代码,您的程序可能看起来有些不同。
【讨论】: