Hibernate Version: 3.2.5
App Servers: WAS 6.1 + Glassfish V2
DB: Oracle10g and MySQL 5
All,
Following on from my previous post: I have written a test application to demonstrate the problems I am having with the 2nd level cache when trying to update data.
Can you guys please: 1) Let me know if the results below are as you would expect 2) Confirm that DML Style update *can* be used in conjunction with the 2nd level cache without it become cleared
Description of my test is below
Test Format
**********
1) Insert a Person Object into my Person table via session.persist(person)
2) Insert another person via A SQLQuery insert
3) Insert an other person via a direct SQL query (session.connection)
4) Load all Persons
--- Cache Reports 3 Object in Cache ---
5) Perfom either a SQLQuery update, a DML Style update, Native SQL Update or load and update via object model, results below.
Test Results after Updates
**********************
------------------------------------------------------------
| Query Type | Elements In Cache | Cache Hits |
-------------------------------------------------------------
| DML Update | 0 | 0 |
| SQLQuery Updates | 0 | 0 |
| Load and Update| 3 | 3 |
-------------------------------------------------------------
Conclusions
***********
1) Performing either a SQLQuery update or DML update will cause data in the cache to become stale and as a result cause the cache to be cleared
2) Point 1 is irrespective of how many rows are actually modified by the update queries
3) OSCache Listener reports stale hits when SQLQuery or DML updates are used.
3) Modifying objects via session.load and then session.update works as expected
4) Results are the same if the query cache is disabled or enabled
5) Cache is still cleared if .setCachable(true) is enabled or disabled
6) This is not an environment issue as its been tested in multiple environments
7) The behaviour is the same for OSCache and Ehcache
Configuration
************
Hibernate:
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
<property name="hibernate.cache.use_query_cache">false</property>
Example Queries
**************
DML:
int updates = sess.createQuery("update Person p set p.age = 100 where p.name='Hamster'").setCacheable(true).executeUpdate();
SQLQuery:
final String query = "insert into Person values ('" + name + "' ,'" + name + "'," + age + ")";
Session sess = HibernateUtil.getSessionFactory().openSession();
SQLQuery sql = sess.createSQLQuery(query);
Annotated Log file
*****************
Code:
Application server startup complete.
deployed with moduleid = EHCacheDemo
**** HQL Insert****
HQLQuery INSERT: inserting person
Hibernate 3.2.5
hibernate.properties not found
Bytecode provider name : cglib
using JDK 1.4 java.sql.Timestamp handling
configuring from resource: /hibernate.cfg.xml
Configuration resource: /hibernate.cfg.xml
Reading mappings from resource : Person.hbm.xml
Mapping class: com.integrasp.demo.entity.Person -> Person
Configured SessionFactory: session1
Using Hibernate built-in connection pool (not for production use!)
Hibernate connection pool size: 20
autocommit mode: false
using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost:3306/demo
connection properties: {user=root, password=****}
RDBMS: MySQL, version: 5.0.51a-3ubuntu5.2
JDBC driver: MySQL-AB JDBC Driver, version: mysql-connector-java-5.1.6 ( Revision: ${svn.Revision} )
Using dialect: org.hibernate.dialect.MySQLDialect
Transaction strategy: org.hibernate.transaction.CMTTransactionFactory
instantiating TransactionManagerLookup: org.hibernate.transaction.SunONETransactionManagerLookup
instantiated TransactionManagerLookup
Automatic flush during beforeCompletion(): disabled
Automatic session close at end of transaction: disabled
JDBC batch size: 15
JDBC batch updates for versioned data: disabled
Scrollable result sets: enabled
JDBC3 getGeneratedKeys(): enabled
Connection release mode: auto
Maximum outer join fetch depth: 2
Default batch fetch size: 1
Order SQL updates by primary key: disabled
Order SQL inserts for batching: disabled
Query translator: org.hibernate.hql.ast.ASTQueryTranslatorFactory
Using ASTQueryTranslatorFactory
Query language substitutions: {}
JPA-QL strict compliance: disabled
Second-level cache: enabled
Query cache: disabled
Cache provider: org.hibernate.cache.OSCacheProvider
Properties {cache.capacity=1000, cache.event.listeners=com.integrasp.demo.persistence.SimpleStatisticListenerImpl}
Optimize cache for minimal puts: disabled
Structured second-level cache entries: enabled
Statistics: enabled
Deleted entity synthetic identifier rollback: disabled
Default entity-mode: pojo
Named query checking : enabled
building session factory
Properties {cache.capacity=1000, cache.event.listeners=com.integrasp.demo.persistence.SimpleStatisticListenerImpl}
Constructed GeneralCacheAdministrator()
Creating new cache
Creation of SimpleStatisticListenerImpl
Factory name: session1
JNDI InitialContext properties:{}
Bound factory to JNDI name: session1
InitialContext did not implement EventContext
Running hbm2ddl schema export
exporting generated schema to database
schema export complete
JNDI InitialContext properties:{}
INFO: Session located
INFO: Tranaction committed.
**** SQLQuery Insert ****
SQLQuery INSERT: method called
SQL Query:insert into Person values ('Bob' ,'Bob',21)
CACHE: CacheWide Flushed method called
CACHE: Flush method called
FLUSH : wide Tue Aug 12 10:06:35 BST 2008
STATISTIC SUM : Hit = 0, stale hit = 0, miss = 0, flush = 1
CACHE: CacheWide Flushed method called
CACHE: Flush method called
FLUSH : wide Tue Aug 12 10:06:35 BST 2008
STATISTIC SUM : Hit = 0, stale hit = 0, miss = 0, flush = 2
INFO: Number of updates = 1
INFO: SQL Transaction commited
****Native SQLQuery insert ****
NATIVE SQL INSERT: method called
SQL Query:insert into Person values ('Dave' ,'Dave',101)
INFO: SQL Transaction commited
***** HQL Load All ****
HQL LOAD Method called
CACHE: Access method called
ACCESS : MISS: com.integrasp.demo.entity.Person#Karl.demo.Person
STATISTIC : Hit = 0, stale hit =0, miss = 1
CACHE: Entry added method called
CACHE: Access method called
ACCESS : MISS: com.integrasp.demo.entity.Person#Bob.demo.Person
STATISTIC : Hit = 0, stale hit =0, miss = 2
CACHE: Entry added method called
CACHE: Access method called
ACCESS : MISS: com.integrasp.demo.entity.Person#Dave.demo.Person
STATISTIC : Hit = 0, stale hit =0, miss = 3
CACHE: Entry added method called
INFO: People found :3
***** 3 Objects In cache *****
**** DML Update 0 Rows effected !!! *****
DML Update : method called
CACHE: CacheWide Flushed method called
CACHE: Flush method called
FLUSH : wide Tue Aug 12 10:06:35 BST 2008
STATISTIC SUM : Hit = 0, stale hit = 0, miss = 3, flush = 3
CACHE: CacheWide Flushed method called
CACHE: Flush method called
FLUSH : wide Tue Aug 12 10:06:35 BST 2008
STATISTIC SUM : Hit = 0, stale hit = 0, miss = 3, flush = 4
INFO: DML Updates = 0
***** HQL LOAD Reports 3 Stale Hits ******
HQL LOAD Method called
CACHE: Access method called
ACCESS : STALE HIT: com.integrasp.demo.entity.Person#Karl.demo.Person
STATISTIC : Hit = 0, stale hit =1, miss = 0
CACHE: CacheEntryUpdated added method called
CACHE: Access method called
ACCESS : STALE HIT: com.integrasp.demo.entity.Person#Bob.demo.Person
STATISTIC : Hit = 0, stale hit =2, miss = 0
CACHE: CacheEntryUpdated added method called
CACHE: Access method called
ACCESS : STALE HIT: com.integrasp.demo.entity.Person#Dave.demo.Person
STATISTIC : Hit = 0, stale hit =3, miss = 0
CACHE: CacheEntryUpdated added method called
INFO: People found :3