I'm programming a web forum using Hibernate 2.0.3, and I've encountered a session level cache problem. See below mapping code:
Code:
<class name="net.gleamynode.notes.driver.hibernate.PageImpl" table="PAGES">
<id name="id" column="PAGE_ID" type="integer">
<generator class="identity"/>
</id>
<property name="timestamp" column="PAGE_TIMESTAMP" type="timestamp" not-null="true"/>
<property name="title" column="PAGE_TITLE" type="string" not-null="true"/>
<property name="content" column="PAGE_CONTENT" type="string" not-null="true"/>
<set name="comments" order-by="COMMENT_TIMESTAMP">
<key column="PAGE_ID"/>
<one-to-many class="net.gleamynode.notes.driver.hibernate.CommentImpl"/>
</set>
<set name="attachments" order-by="ATTACHMENT_NAME">
<key column="PAGE_ID"/>
<one-to-many class="net.gleamynode.notes.driver.hibernate.AttachmentImpl"/>
</set>
<set name="keywords" table="PAGE_INDEX" sort="net.gleamynode.notes.driver.hibernate.KeywordValueComparator">
<key column="PAGE_ID"/>
<many-to-many column="KEYWORD_ID" class="net.gleamynode.notes.driver.hibernate.KeywordImpl"/>
</set>
</class>
<class name="net.gleamynode.notes.driver.hibernate.CommentImpl" table="COMMENTS">
<id name="id" column="COMMENT_ID" type="integer">
<generator class="identity"/>
</id>
<many-to-one name="page" column="PAGE_ID" not-null="true" class="net.gleamynode.notes.driver.hibernate.PageImpl" />
<property name="timestamp" column="COMMENT_TIMESTAMP" type="timestamp" not-null="true"/>
<property name="userName" column="COMMENT_USER" type="string" not-null="true"/>
<property name="userEmail" column="COMMENT_EMAIL" type="string"/>
<property name="userURL" column="COMMENT_URL" type="string"/>
<property name="content" column="COMMENT_CONTENT" type="string" not-null="true"/>
</class>
Here is the code I programmed to write a comment on a page(topic):
Code:
public Comment newComment(Integer pageID, String userName, String userEmail, String userURL, String content) throws NotesException {
CommentImpl comment = new CommentImpl();
comment.setPage(getPage(pageID));
comment.setUserName(userName);
comment.setUserEmail(userEmail);
comment.setUserURL(userURL);
comment.setContent(content);
try {
comment.setId((Integer)session.save(comment));
session.flush();
}
catch (HibernateException e) {
throw new NotesException(e);
}
return comment;
}
public Page getPage(Integer id) throws NotesException {
try {
return (Page)session.load(PageImpl.class, id);
}
catch ( ObjectNotFoundException onfe ) {
return null;
}
catch ( HibernateException he ) {
throw new NotesException(he);
}
}
Here is what happens when a user calls newComment(...):
1. getPage(...) is called. The executed SQLs are:
Code:
Hibernate: select pageimpl0_.PAGE_ID as PAGE_ID, pageimpl0_.PAGE_TIMESTAMP as PAGE_TIM2_, pageimpl0_.PAGE_TITLE as PAGE_TITLE, pageimpl0_.PAGE_CONTENT as PAGE_CON4_ from PAGES pageimpl0_ where pageimpl0_.PAGE_ID=?
Hibernate: select comments0_.COMMENT_ID as COMMENT_ID__, comments0_.COMMENT_ID as COMMENT_ID, comments0_.PAGE_ID as PAGE_ID, comments0_.COMMENT_TIMESTAMP as COMMENT_3_, comments0_.COMMENT_USER as COMMENT_4_, comments0_.COMMENT_EMAIL as COMMENT_5_, comments0_.COMMENT_URL as COMMENT_6_, comments0_.COMMENT_CONTENT as COMMENT_7_ from COMMENTS comments0_ where comments0_.PAGE_ID=? order by comments0_.COMMENT_TIMESTAMP
Hibernate: select attachme0_.ATTACHMENT_ID as ATTACHME1___, attachme0_.ATTACHMENT_ID as ATTACHMENT_ID, attachme0_.PAGE_ID as PAGE_ID, attachme0_.ATTACHMENT_NAME as ATTACHME3_ from ATTACHMENTS attachme0_ where attachme0_.PAGE_ID=? order by attachme0_.ATTACHMENT_NAME
Hibernate: select page_ind0_.KEYWORD_ID as KEYWORD_ID__, keywordi1_.KEYWORD_ID as KEYWORD_ID0_, keywordi1_.KEYWORD_VALUE as KEYWORD_2_0_ from PAGE_INDEX page_ind0_ left outer join KEYWORDS keywordi1_ on page_ind0_.KEYWORD_ID=keywordi1_.KEYWORD_ID where page_ind0_.PAGE_ID=?
2. session.update() and flush() will insert a row:
Code:
Hibernate: insert into COMMENTS (PAGE_ID, COMMENT_TIMESTAMP, COMMENT_USER, COMMENT_EMAIL, COMMENT_URL, COMMENT_CONTENT) values (?, ?, ?, ?, ?, ?)
[PROBLEM 1] If the user calls getPage(...) to load the page again, the only SQL statement executed is the first one in step 1 above, so PageImpl.getComments() will return the list which does not contain the comment that has been inserted just before. I think session-level cache is not working correctly. Because a new row has been inserted, there should be at least one more query.
[PROBLEM 2] I cache SessionFactory instance and call sessionFactory.openSession() for each web page request, but I can't see any SQL queries are executed if there is no updates since the first query. Is it a normal behavior? I thought the result would not be cached because I open and close the session for every request. Is it a session factory level cache actually, or is the session instance is reused internally not clearing the cache?