Spring, JPA (Hibernate) & Ehcache Poor Performance - performance

I have what I would assume is a pretty standard setup...spring, jpa (hibernate) and I'm trying to add ehcache.
I have it all configured and verified that it's working...I'm logging the hibernate sql statements and cache statements and can see that the cache is getting invoked and that once the object is in the cache, when I try to load it again, the sql statement is not written out (ie, it's not hitting the database).
However, the performance is terrible...it's pretty much the same performance if I get the object from the cache or from the db. I suspect that perhaps the problem is to do with spring automatically flushing the hibernate session, or maybe the overhead is due to transactions (which I have tried to turn off for that method), or maybe my connection pooling using c3p0 isn't working well enough. At any rate, I'm at a bit of a loss..
I'll post all the relevant information that I have and hopefully some genius here can help me out otherwise I'm stuck.
Firstly, my spring config:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:hprof="http://www.nhprof.com/schema/hprof"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.nhprof.com/schema/hprof http://www.nhprof.com/schema/hprof/hprof.xsd">
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="systemPropertyManager" class="com.service.impl.SystemPropertyManagerImpl" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="mysql" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="MYSQL" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<!-- always puts logging out to the console...we want it in the log file -->
<prop key="hibernate.connection.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
<prop key="net.sf.ehcache.configurationResourceName">ehcache.xml</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.default_batch_fetch_size">500</prop>
<prop key="hibernate.max_fetch_depth">5</prop>
<prop key="hibernate.jdbc.batch_size">1000</prop>
<prop key="hibernate.use_outer_join">true</prop>
</props>
</property>
<!-- <hprof:profiler /> -->
</bean>
<bean id="mysql" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost/daily?relaxAutoCommit=true&useUnicode=true&characterEncoding=UTF-8&jdbcCompliantTruncation=false&emulateLocators=true" />
<property name="user" value="root" />
<property name="password" value="" />
<property name="initialPoolSize"><value>5</value></property>
<property name="minPoolSize"><value>5</value></property>
<property name="maxPoolSize"><value>50</value></property>
<property name="idleConnectionTestPeriod"><value>200</value></property>
<property name="acquireIncrement"><value>3</value></property>
<property name="numHelperThreads"><value>3</value></property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
My ehcache file is as follows
<ehcache>
<diskStore path="c:/cache"/>
<defaultCache eternal="false"
overflowToDisk="false"
maxElementsInMemory="50000"
timeToIdleSeconds="30"
timeToLiveSeconds="6000"
memoryStoreEvictionPolicy="LRU"
/>
<cache name="com.model.SystemProperty"
maxElementsInMemory="5000"
eternal="true"
overflowToDisk="false"
memoryStoreEvictionPolicy="LFU" />
My cached object which is annotated in order to invoke the cache is as follows:
package com.model;
import javax.persistence.*;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
#Entity
#Cache(usage = CacheConcurrencyStrategy.READ_ONLY, region="com.model.SystemProperty", include="non-lazy")
#EntityListeners(com.util.GenericEntityLogger.class)
public class SystemProperty extends BaseObject{
private String name;
private String value;
// default constructor
public SystemProperty(){
}
public SystemProperty(String name, String value){
this.name = name;
this.value = value;
}
#Id
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
#Override
public boolean equals(Object o) {
// TODO Auto-generated method stub
return false;
}
#Override
public int hashCode() {
// TODO Auto-generated method stub
return 0;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return null;
}
}
and my implementation of my interface used to save and get the SystemProperty object with the spring #Transactional method is as follows:
package com.service.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;
import com.model.SystemProperty;
import com.service.SystemPropertyManager;
public class SystemPropertyManagerImpl extends BaseManagerImpl implements SystemPropertyManager {
// logging
protected final Log log = LogFactory.getLog(getClass());
public SystemProperty find(String name){
return (SystemProperty) super.entityManager.find(SystemProperty.class, name);
}
#Transactional
public SystemProperty save(SystemProperty prop){
return (SystemProperty) super.save(prop);
}
}
Note that #Transactional is only on the save method.
Finally, I have populated the mysql database with 3000 system property objects and then have written a little test file, that loads them up twice.
The first time it loads them, I can see the sql being generated and that the cache is not getting hit. The second time, the cache does get hit and the sql isn't generated.
Unit Test:
#Test
public void testGetCachedUser1(){
log.debug("starting testGetCachedUser");
SystemPropertyManager mgr = ManagerFactory.getSystemPropertyManager();
EntityManager em = mgr.getEntityManager();
log.debug("start timing 1");
for(int i = 0; i<3000; i ++){
mgr.find("name_"+i);
}
log.debug("end timing 1");
log.debug("start timing 2");
for(int i = 0; i<3000; i ++){
mgr.find("name_"+i);
}
log.debug("end timing 2");
}
The log file has lots of info. I'll post the section from the log file in the "start timing 1" area. This corresponds to what happens only for the very first object that is loaded when it's not in the cache:
DEBUG 2010-10-22 11:57:49,533 [main][] org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method [find] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT]
DEBUG 2010-10-22 11:57:49,533 [main][] org.hibernate.impl.SessionImpl - opened session at timestamp: 5274603804807168
DEBUG 2010-10-22 11:57:49,533 [main][] org.hibernate.transaction.JDBCTransaction - begin
DEBUG 2010-10-22 11:57:49,533 [main][] org.hibernate.jdbc.ConnectionManager - opening JDBC connection
DEBUG 2010-10-22 11:57:49,533 [main][] com.mchange.v2.resourcepool.BasicResourcePool - trace com.mchange.v2.resourcepool.BasicResourcePool#4e2f0a [managed: 5, unused: 4, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection#1631573)
DEBUG 2010-10-22 11:57:49,533 [main][] org.hibernate.transaction.JDBCTransaction - current autocommit status: true
DEBUG 2010-10-22 11:57:49,533 [main][] org.hibernate.transaction.JDBCTransaction - disabling autocommit
DEBUG 2010-10-22 11:57:49,533 [main][] org.hibernate.jdbc.JDBCContext - after transaction begin
DEBUG 2010-10-22 11:57:49,549 [main][] org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.jdbc.datasource.ConnectionHolder#5fbbf3] for key [com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 31ghzi8b1mphf1c19l14qo|149105b, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.p6spy.engine.spy.P6SpyDriver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 31ghzi8b1mphf1c19l14qo|149105b, idleConnectionTestPeriod -> 200, initialPoolSize -> 5, jdbcUrl -> jdbc:mysql://localhost/daily?relaxAutoCommit=true&useUnicode=true&characterEncoding=UTF-8&jdbcCompliantTruncation=false&emulateLocators=true, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 50, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 5, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]] to thread [main]
DEBUG 2010-10-22 11:57:49,549 [main][] org.springframework.transaction.support.TransactionSynchronizationManager - Bound value [org.springframework.orm.jpa.EntityManagerHolder#1bb03ee] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#11b99c4] to thread [main]
DEBUG 2010-10-22 11:57:49,549 [main][] org.springframework.transaction.support.TransactionSynchronizationManager - Initializing transaction synchronization
DEBUG 2010-10-22 11:57:49,549 [main][] org.springframework.transaction.interceptor.TransactionInterceptor - Getting transaction for [com.service.SystemPropertyManager.find]
DEBUG 2010-10-22 11:57:49,549 [main][] org.springframework.transaction.support.TransactionSynchronizationManager - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#1bb03ee] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#11b99c4] bound to thread [main]
DEBUG 2010-10-22 11:57:49,549 [main][] org.hibernate.event.def.DefaultLoadEventListener - loading entity: [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,549 [main][] org.hibernate.event.def.DefaultLoadEventListener - attempting to resolve: [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,549 [main][] org.hibernate.event.def.DefaultLoadEventListener - object not resolved in any cache: [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,549 [main][] org.hibernate.persister.entity.AbstractEntityPersister - Fetching entity: [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,549 [main][] org.hibernate.loader.Loader - loading entity: [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,549 [main][] org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
DEBUG 2010-10-22 11:57:49,549 [main][] org.hibernate.SQL - select systemprop0_.name as name11_0_, systemprop0_.value as value11_0_ from SystemProperty systemprop0_ where systemprop0_.name=?
DEBUG 2010-10-22 11:57:49,549 [main][] org.hibernate.jdbc.AbstractBatcher - preparing statement
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.type.StringType - binding 'name_0' to parameter: 1
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.loader.Loader - processing result set
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.loader.Loader - result set row: 0
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.loader.Loader - result row: EntityKey[com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.loader.Loader - Initializing object from ResultSet: [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.persister.entity.AbstractEntityPersister - Hydrating entity: [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.type.StringType - returning 'value_0' as column: value11_0_
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.loader.Loader - done processing result set (1 rows)
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.jdbc.AbstractBatcher - closing statement
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.loader.Loader - total objects hydrated: 1
DEBUG 2010-10-22 11:57:49,580 [main][] org.hibernate.engine.TwoPhaseLoad - resolving associations for [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.engine.TwoPhaseLoad - adding entity to second-level cache: [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.cache.ReadOnlyCache - Caching: com.model.SystemProperty#name_0
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.engine.TwoPhaseLoad - done materializing entity [com.model.SystemProperty#name_0]
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.engine.StatefulPersistenceContext - initializing non-lazy collections
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.loader.Loader - done entity load
DEBUG 2010-10-22 11:57:49,596 [main][] org.springframework.transaction.interceptor.TransactionInterceptor - Completing transaction for [com.service.SystemPropertyManager.find]
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.transaction.JDBCTransaction - commit
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.impl.SessionImpl - automatically flushing session
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - flushing session
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - processing flush-time cascades
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.engine.Cascade - processing cascade ACTION_PERSIST_ON_FLUSH for: com.model.SystemProperty
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.engine.Cascade - done processing cascade ACTION_PERSIST_ON_FLUSH for: com.model.SystemProperty
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - dirty checking collections
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - Flushing entities and processing referenced collections
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - Processing unreferenced collections
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - Scheduling collection removes/(re)creates/updates
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 0 deletions to 1 objects
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.pretty.Printer - listing entities:
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.pretty.Printer - com.model.SystemProperty{name=name_0, value=value_0}
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - executing flush
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.jdbc.ConnectionManager - registering flush begin
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.jdbc.ConnectionManager - registering flush end
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.event.def.AbstractFlushingEventListener - post flush
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.jdbc.JDBCContext - before transaction completion
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.impl.SessionImpl - before transaction completion
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.transaction.JDBCTransaction - re-enabling autocommit
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.transaction.JDBCTransaction - committed JDBC Connection
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.jdbc.JDBCContext - after transaction completion
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.jdbc.ConnectionManager - aggressively releasing JDBC connection
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
DEBUG 2010-10-22 11:57:49,596 [main][] com.mchange.v2.resourcepool.BasicResourcePool - trace com.mchange.v2.resourcepool.BasicResourcePool#4e2f0a [managed: 5, unused: 4, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection#1631573)
DEBUG 2010-10-22 11:57:49,596 [main][] org.hibernate.impl.SessionImpl - after transaction completion
DEBUG 2010-10-22 11:57:49,596 [main][] org.springframework.transaction.support.TransactionSynchronizationManager - Clearing transaction synchronization
DEBUG 2010-10-22 11:57:49,596 [main][] org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [org.springframework.orm.jpa.EntityManagerHolder#1bb03ee] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#11b99c4] from thread [main]
DEBUG 2010-10-22 11:57:49,612 [main][] org.springframework.transaction.support.TransactionSynchronizationManager - Removed value [org.springframework.jdbc.datasource.ConnectionHolder#5fbbf3] for key [com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> 31ghzi8b1mphf1c19l14qo|149105b, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.p6spy.engine.spy.P6SpyDriver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> 31ghzi8b1mphf1c19l14qo|149105b, idleConnectionTestPeriod -> 200, initialPoolSize -> 5, jdbcUrl -> jdbc:mysql://localhost/daily?relaxAutoCommit=true&useUnicode=true&characterEncoding=UTF-8&jdbcCompliantTruncation=false&emulateLocators=true, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 50, maxStatements -> 0, maxStatementsPerConnection -> 0, minPoolSize -> 5, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> null, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]] from thread [main]
DEBUG 2010-10-22 11:57:49,612 [main][] org.hibernate.impl.SessionImpl - closing session
DEBUG 2010-10-22 11:57:49,612 [main][] org.hibernate.jdbc.ConnectionManager - connection already null in cleanup : no action
You can see that it's getting loaded into the cache, the hibernate session is opened and closed and flushed.
I'll post my second log file in a comment below as I've hit the max length already of this question. Main point is, it all looks ok, the only real problem is that it's sooo damn slow.
When I load 3000 objects the first time (ie, hitting the db) it takes pretty much exactly the same as teh second time (ie, hitting the cache). Like I said, is it cos the overhead is opening and closing the connection, flushing the session, dealing with transactions? I'm not sure. But it's pretty brutal at any rate. Help me stackoverflow...you're my only hope :)

I would suggest trying to replace that 2nd level cache usage with plain applicative cache. When I tested Hibernate's 2nd level cache performance in the past, I noticed it wasn't very effective. This is due to the way the cached data is structured - similar to a result set - that is tabular data is being store, and not objects. This means many many cache requests, which turns out to be expensive.
In order to separate the cache code from the persistence logic, I use AOP. Since you use Spring this should be easy.

Main point is, it all looks ok, the only real problem is that it's sooo damn slow.
Damn slow is a subjective measurement unit :)
When I load 3000 objects the first time (ie, hitting the db) it takes pretty much exactly the same as the second time (ie, hitting the cache).
Show metrics, without all the logging overhead (and also without P6Spy), using System.nanoTime()
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
Maybe also try to perform your test inside a single transaction, using a single EntityManager, just to see how things behave in these conditions.
Like I said, is it cos the overhead is opening and closing the connection, flushing the session, dealing with transactions? I'm not sure. But it's pretty brutal at any rate.
Can't say, you should profile your code to see where the time is spent (and also monitor the GC activity).
But in theory:
The connection in a Session is lazy (will get acquired only when required)
Acquiring a connection from C3P0 should be pretty fast (negligible)
Since your entities are cached as read-only, the flush should be pretty fast
In other words, I wouldn't expect the above operations to be expensive (so I'd focus on the surrounding parts). But as I said, profile (and monitor the GC activity).

are you sure you are not hitting database in your cache call? enable hibernate sql debug logger to see if it is doing the right thing. I never used entity manager before. I always use the hibernate session. If you enable query cache, you still have to do setCache(true) in the hibernate query. Otherwise, it will still hit the db. The #Cache annotation in the entity only cache it by id in ehcache. When you set your query to be cacheable, the cache key is your query and result is the entity id, then it will try to resolve the entity in the ehcache by id.

Your test uses the EntityManager directly without a transaction. An EntityManager is scoped to a single unit of work, typically a single transaction. You're probably forcing a new transaction incl. the lookup in the pool of a DB connection for every find invocation.
Here's what I would suggest:
use read-only transactions for the non-save methods instead of no TX demarcation
wrap your DataSource bean in a LazyConnectionDataSourceProxy to avoid getting a Connection if you don't actually need to talk to your database (i.e. in case of a cache hit)
update your test to talk to your service bean instead of directly using an EntityManager.

Related

Hibernate not flushing entity update on transaction commit

This is the transactional service defining the method I use to create a UserCommit and explicitly persisting it (this part works), and in the meantime updating the lastCommit field of the already existent parent entity User. This update doesn't get flushed.
#Transactional
#Service
public class UserCommitService {
#Autowired
private UserService userService;
#Autowired
private UserCommitRepository ucRepo;
public UserCommit createFrom(User user, Integer prodId, String ucType, String stage) {
UserCommit uc = new UserCommit();
uc.setUser(userService.findUserById(user.getId()));
uc.getUser().addUserCommit(uc);
uc.setTime(LocalDateTime.now());
uc.getUser().setLastCommit(uc.getTime());
ucRepo.save(uc);
return uc;
}
}
Here you can read the tracing log:
User gets correctly selected from DB
An inner transaction gets created for ucRepo.save (It's a CRUDRepo method, then I think it's normal) and userCommit gets correctly inserted into DB
EDIT
Why CrudRepository.save creates a new transaction instead of joining the existing one?
Outer transaction gets resumed, but even if the entity show the updated field, it seems this gets ignored by dirty checking, because no insert is logged on commit.
2020-05-31 12:52:36.405 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#296e6024] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#1826475] bound to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:52:36.406 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(461939992<open>)] for JPA transaction
2020-05-31 12:52:36.406 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [petmenu.services.users.UserCommitService.createFrom]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2020-05-31 12:52:36.407 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#5ac66b8d]
2020-05-31 12:52:36.407 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder#4905e3e7] for key [HikariDataSource (HikariPool-1)] to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:52:36.407 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2020-05-31 12:52:36.407 TRACE 7194 --- [.10-8080-exec-6] o.s.t.i.TransactionInterceptor : Getting transaction for [petmenu.services.users.UserCommitService.createFrom]
2020-05-31 12:53:24.212 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#296e6024] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#1826475] bound to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:53:24.217 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(461939992<open>)] for JPA transaction
2020-05-31 12:53:24.221 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder#4905e3e7] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:53:24.228 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
2020-05-31 12:53:24.232 TRACE 7194 --- [.10-8080-exec-6] o.s.t.i.TransactionInterceptor : Getting transaction for [petmenu.services.users.UserService.findUserById]
2020-05-31 12:53:24.256 TRACE 7194 --- [.10-8080-exec-6] o.s.t.i.TransactionInterceptor : No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findUserById]: This method is not transactional.
2020-05-31 12:53:24.265 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.EntityManagerFactoryUtils : Opening JPA EntityManager
2020-05-31 12:53:24.271 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.jpa.EntityManagerHolder#75c27c80] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:53:24.279 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#75c27c80] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] bound to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:53:24.288 DEBUG 7194 --- [.10-8080-exec-6] org.hibernate.SQL : select user0_.id as id1_0_, user0_.kc_id as kc_id2_0_, user0_.last_commit as last_com3_0_, user0_.name as name4_0_ from user user0_ where user0_.id=?
2020-05-31 12:53:24.298 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [6]
2020-05-31 12:53:24.309 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicExtractor : extracted value ([id1_0_] : [INTEGER]) - [6]
2020-05-31 12:53:24.317 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicExtractor : extracted value ([kc_id2_0_] : [VARCHAR]) - [80a3b4b1-00d1-4062-a7e5-1927b938c203]
2020-05-31 12:53:24.325 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicExtractor : extracted value ([last_com3_0_] : [TIMESTAMP]) - [null]
2020-05-31 12:53:24.332 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicExtractor : extracted value ([name4_0_] : [VARCHAR]) - [user1]
2020-05-31 12:53:24.342 TRACE 7194 --- [.10-8080-exec-6] o.s.t.i.TransactionInterceptor : Completing transaction for [petmenu.services.users.UserService.findUserById]
2020-05-31 12:55:07.918 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata#326a9afb] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:07.957 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#75c27c80] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] bound to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:07.961 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(1373582834<open>)] for JPA transaction
2020-05-31 12:55:07.966 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder#75c27c80] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] from thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:07.970 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2020-05-31 12:55:07.975 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2020-05-31 12:55:07.980 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(756005269<open>)] for JPA transaction
2020-05-31 12:55:07.987 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#6860e795]
2020-05-31 12:55:07.992 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder#6374741f] for key [HikariDataSource (HikariPool-2)] to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:07.998 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.jpa.EntityManagerHolder#4b2cad26] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:08.002 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2020-05-31 12:55:08.006 TRACE 7194 --- [.10-8080-exec-6] o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2020-05-31 12:55:08.226 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#4b2cad26] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] bound to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:08.392 DEBUG 7194 --- [.10-8080-exec-6] org.hibernate.SQL : select nextval(hibernate_sequence)
2020-05-31 12:55:08.783 TRACE 7194 --- [.10-8080-exec-6] o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
2020-05-31 12:55:08.787 TRACE 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Triggering beforeCommit synchronization
2020-05-31 12:55:08.791 TRACE 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Triggering beforeCompletion synchronization
2020-05-31 12:55:08.796 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2020-05-31 12:55:08.800 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(756005269<open>)]
2020-05-31 12:55:08.824 DEBUG 7194 --- [.10-8080-exec-6] org.hibernate.SQL : insert into user_commit (uctype, prod_id, stage, time, user, id) values (?, ?, ?, ?, ?, ?)
2020-05-31 12:55:08.832 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [1]
2020-05-31 12:55:08.838 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [INTEGER] - [3]
2020-05-31 12:55:08.845 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [3] as [INTEGER] - [0]
2020-05-31 12:55:08.884 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [4] as [TIMESTAMP] - [2020-05-31T12:54:58.518530]
2020-05-31 12:55:08.922 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [5] as [INTEGER] - [6]
2020-05-31 12:55:08.929 TRACE 7194 --- [.10-8080-exec-6] o.h.type.descriptor.sql.BasicBinder : binding parameter [6] as [INTEGER] - [3003]
2020-05-31 12:55:09.043 TRACE 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Triggering afterCommit synchronization
2020-05-31 12:55:09.048 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2020-05-31 12:55:09.052 TRACE 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Triggering afterCompletion synchronization
2020-05-31 12:55:09.056 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder#4b2cad26] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] from thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:09.062 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder#6374741f] for key [HikariDataSource (HikariPool-2)] from thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:09.066 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(756005269<open>)] after transaction
2020-05-31 12:55:09.070 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Resuming suspended transaction after completion of inner transaction
2020-05-31 12:55:09.075 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2020-05-31 12:55:09.080 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.jpa.EntityManagerHolder#75c27c80] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] to thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:55:09.085 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata#326a9afb] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] from thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:58:18.989 TRACE 7194 --- [.10-8080-exec-6] o.s.t.i.TransactionInterceptor : Completing transaction for [petmenu.services.users.UserCommitService.createFrom]
2020-05-31 12:58:18.997 TRACE 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Triggering beforeCommit synchronization
2020-05-31 12:58:19.001 TRACE 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Triggering beforeCompletion synchronization
2020-05-31 12:58:19.006 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder#75c27c80] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6c8672b9] from thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:58:19.071 INFO 7194 --- [.10-8080-exec-6] o.h.c.i.AbstractPersistentCollection : HHH000496: Detaching an uninitialized collection with queued operations from a session: [petmenu.entities.users.User.userCommitList#6]
2020-05-31 12:58:19.075 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2020-05-31 12:58:19.081 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(461939992<open>)]
2020-05-31 12:58:19.095 TRACE 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Triggering afterCommit synchronization
2020-05-31 12:58:19.099 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2020-05-31 12:58:19.104 TRACE 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Triggering afterCompletion synchronization
2020-05-31 12:58:19.109 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder#4905e3e7] for key [HikariDataSource (HikariPool-1)] from thread [http-nio-192.168.1.10-8080-exec-6]
2020-05-31 12:58:19.113 DEBUG 7194 --- [.10-8080-exec-6] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
2020-05-31 12:59:07.063 TRACE 7194 --- [.10-8080-exec-6] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder#296e6024] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#1826475] from thread [http-nio-192.168.1.10-8080-exec-6]
EDIT2
I tried to remove the CrudRepository.save call, because it behaves strangely, creating a new transaction on its own, and seems responsible for previous one closing. The log becomes a little more logic, but still User.lastCommit new value doesn't get flushed.
2020-06-01 11:39:10.518 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#5f0cca8f] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#27bbe773] bound to thread [http-nio-192.168.1.10-8080-exec-2]
2020-06-01 11:39:10.518 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(2096513672<open>)] for JPA transaction
2020-06-01 11:39:10.518 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [petmenu.services.users.UserCommitService.createFrom]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2020-06-01 11:39:10.518 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#62cbdd03]
2020-06-01 11:39:10.519 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.jdbc.datasource.ConnectionHolder#4b988820] for key [HikariDataSource (HikariPool-1)] to thread [http-nio-192.168.1.10-8080-exec-2]
2020-06-01 11:39:10.519 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Initializing transaction synchronization
2020-06-01 11:39:10.519 TRACE 26420 --- [.10-8080-exec-2] o.s.t.i.TransactionInterceptor : Getting transaction for [petmenu.services.users.UserCommitService.createFrom]
2020-06-01 11:39:16.678 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#5f0cca8f] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#27bbe773] bound to thread [http-nio-192.168.1.10-8080-exec-2]
2020-06-01 11:39:16.683 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(2096513672<open>)] for JPA transaction
2020-06-01 11:39:16.688 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder#4b988820] for key [HikariDataSource (HikariPool-1)] bound to thread [http-nio-192.168.1.10-8080-exec-2]
2020-06-01 11:39:16.693 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
2020-06-01 11:39:16.697 TRACE 26420 --- [.10-8080-exec-2] o.s.t.i.TransactionInterceptor : Getting transaction for [petmenu.services.users.UserService.findUserById]
2020-06-01 11:39:16.720 TRACE 26420 --- [.10-8080-exec-2] o.s.t.i.TransactionInterceptor : No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findUserById]: This method is not transactional.
2020-06-01 11:39:16.727 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.EntityManagerFactoryUtils : Opening JPA EntityManager
2020-06-01 11:39:16.733 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Bound value [org.springframework.orm.jpa.EntityManagerHolder#ca14c2f] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#161c9468] to thread [http-nio-192.168.1.10-8080-exec-2]
2020-06-01 11:39:16.738 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#ca14c2f] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#161c9468] bound to thread [http-nio-192.168.1.10-8080-exec-2]
2020-06-01 11:39:16.747 DEBUG 26420 --- [.10-8080-exec-2] org.hibernate.SQL : select user0_.id as id1_0_, user0_.kc_id as kc_id2_0_, user0_.last_commit as last_com3_0_, user0_.name as name4_0_ from user user0_ where user0_.id=?
2020-06-01 11:39:16.754 TRACE 26420 --- [.10-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [INTEGER] - [6]
2020-06-01 11:39:16.763 TRACE 26420 --- [.10-8080-exec-2] o.h.type.descriptor.sql.BasicExtractor : extracted value ([id1_0_] : [INTEGER]) - [6]
2020-06-01 11:39:16.772 TRACE 26420 --- [.10-8080-exec-2] o.h.type.descriptor.sql.BasicExtractor : extracted value ([kc_id2_0_] : [VARCHAR]) - [80a3b4b1-00d1-4062-a7e5-1927b938c203]
2020-06-01 11:39:16.779 TRACE 26420 --- [.10-8080-exec-2] o.h.type.descriptor.sql.BasicExtractor : extracted value ([last_com3_0_] : [TIMESTAMP]) - [null]
2020-06-01 11:39:16.787 TRACE 26420 --- [.10-8080-exec-2] o.h.type.descriptor.sql.BasicExtractor : extracted value ([name4_0_] : [VARCHAR]) - [user1]
2020-06-01 11:39:16.795 TRACE 26420 --- [.10-8080-exec-2] o.s.t.i.TransactionInterceptor : Completing transaction for [petmenu.services.users.UserService.findUserById]
2020-06-01 11:39:48.779 TRACE 26420 --- [.10-8080-exec-2] o.s.t.i.TransactionInterceptor : Completing transaction for [petmenu.services.users.UserCommitService.createFrom]
2020-06-01 11:39:48.780 TRACE 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Triggering beforeCommit synchronization
2020-06-01 11:39:48.780 TRACE 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Triggering beforeCompletion synchronization
2020-06-01 11:39:48.780 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.orm.jpa.EntityManagerHolder#ca14c2f] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#161c9468] from thread [http-nio-192.168.1.10-8080-exec-2]
2020-06-01 11:39:48.782 INFO 26420 --- [.10-8080-exec-2] o.h.c.i.AbstractPersistentCollection : HHH000496: Detaching an uninitialized collection with queued operations from a session: [petmenu.entities.users.User.userCommitList#6]
2020-06-01 11:39:48.782 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2020-06-01 11:39:48.782 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(2096513672<open>)]
2020-06-01 11:39:48.787 TRACE 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Triggering afterCommit synchronization
2020-06-01 11:39:48.787 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Clearing transaction synchronization
2020-06-01 11:39:48.787 TRACE 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Triggering afterCompletion synchronization
2020-06-01 11:39:48.787 TRACE 26420 --- [.10-8080-exec-2] .s.t.s.TransactionSynchronizationManager : Removed value [org.springframework.jdbc.datasource.ConnectionHolder#4b988820] for key [HikariDataSource (HikariPool-1)] from thread [http-nio-192.168.1.10-8080-exec-2]
2020-06-01 11:39:48.787 DEBUG 26420 --- [.10-8080-exec-2] o.s.orm.jpa.JpaTransactionManager : Not closing pre-bound JPA EntityManager after transaction
I spent just 4 days to realize the what the problem was. Awesome...(To be honest, I took advantage of all the stuff I had to read about JPA and Hibernate to get rid completely of OSIV).
When I defined my two datasources (Products and Users) configs, I annotated all the classes inside ProductsDataSourceConfiguration as #Primary, making them the default values when called without explicitly setting a name.
The problem was with PlatformTransactionManager in it, that was called as transaction manager for both my datasources, while actually being crafted just for Products one.
To solve the issue I had to specify the secondary transaction manager name on #Transactional annotation used on methods referring to secondary (Users) datasource:
#Transactional("usersTransactionManager")
#Service
public class UserCommitService {
...

Spring transactions - isolation and propagation understanding

I am exploring spring transactions and after going through the spring docs and the following link i still have few questions. If I have a parent method with Propogation.REQUIRED which is calling 3 methods with Propogation.REQUIRES_NEW as follows:
//#Transactional(isolation=Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
public Contact saveContactInSteps(Contact contact, String newFirstName, String newLastName, Date bDate) throws Exception {
contact.setFirstName(newFirstName);
try {
updateContactFirstName(contact);
} catch (Exception e) {
LOG.error("Contact first name could not be saved !!");
e.printStackTrace();
throw e;
}
contact.setLastName(newLastName);
try {
updateContactLastName(contact);
} catch (Exception e) {
LOG.error("Contact Last name could not be saved !!");
e.printStackTrace();
throw e;
}
contact.setBirthDate(bDate);
updateContactBday(contact);
return contact;
}
public Contact saveById(Contact contact) {
sessionFactory.getCurrentSession().saveOrUpdate(contact);
LOG.info("Contact " + contact + " saved successfully");
return contact;
}
//#Transactional(isolation=Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public Contact updateContactFirstName(Contact contact) throws Exception {
throw new Exception("Cannot update first name");
//sessionFactory.getCurrentSession().saveOrUpdate(contact);
//LOG.info("Contact First name saved successfully");
//return contact;
}
//#Transactional(isolation=Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public Contact updateContactLastName(Contact contact) throws Exception {
throw new Exception("Cannot update last name");
//sessionFactory.getCurrentSession().saveOrUpdate(contact);
//LOG.info("Contact " + contact + " saved successfully");
//return contact;
}
//#Transactional(isolation=Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public Contact updateContactBday(Contact contact) {
sessionFactory.getCurrentSession().saveOrUpdate(contact);
LOG.info("Contact Birth Date saved successfully");
return contact;
}
Whenever i process the parent method i.e. saveContactInSteps, even the last name is getting updated in database. I am not sure how that is happening. If i throw the exception from first child method nothing gets updated. Is it because of the fact that i am setting the attributes i.e. names and birthdate in the parent method ? Even if i am setting the attributes in the parent method, i am not letting the parent method complete as well. Does the isolation level play any part here ? I believe it's for concurrent transactions ? Is there something i am missing ?
EDIT 1:
After going through the article i did realize what i was missing. I needed AOP proxies in place which i have added as follows:
<aop:config>
<aop:pointcut
expression="execution(* org.pack.spring.transactions.ContactService.*(..))"
id="updateOperation" />
<aop:advisor pointcut-ref="updateOperation" advice-ref="saveUpdateAdvice" />
</aop:config>
<tx:advice id="saveUpdateAdvice">
<tx:attributes>
<tx:method name="update*" propagation="REQUIRES_NEW" isolation="DEFAULT" rollback-for="Exception"/>
<tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
Log output is as follows:
01:23:57.535 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:57.550 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
01:23:57.552 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'saveUpdateAdvice'
01:23:57.552 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean 'saveUpdateAdvice'
01:23:57.552 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Eagerly caching bean 'saveUpdateAdvice' to allow for resolving potential circular references
01:23:57.553 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
01:23:57.553 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating instance of bean '(inner bean)#56ac5c80'
01:23:57.553 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
01:23:57.553 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
01:23:57.557 [main] DEBUG o.s.t.i.NameMatchTransactionAttributeSource - Adding transactional method [update*] with attribute [PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT,-Exception]
01:23:57.557 [main] DEBUG o.s.t.i.NameMatchTransactionAttributeSource - Adding transactional method [save*] with attribute [PROPAGATION_REQUIRED,ISOLATION_DEFAULT,-Exception]
01:23:57.557 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
01:23:57.557 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
01:23:57.557 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
01:23:57.557 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
01:23:57.558 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean '(inner bean)#56ac5c80'
01:23:57.558 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Invoking afterPropertiesSet() on bean with name 'saveUpdateAdvice'
01:23:57.558 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'saveUpdateAdvice'
01:23:57.568 [main] DEBUG o.s.a.a.a.AspectJAwareAdvisorAutoProxyCreator - Creating implicit proxy for bean 'springTxContactService' with 0 common interceptors and 3 specific interceptors
01:23:57.575 [main] DEBUG o.s.aop.framework.CglibAopProxy - Creating CGLIB proxy: target source is SingletonTargetSource for target object [org.pack.ch9.spring.transactions.hibernate.home.ContactService#598260a6]
01:23:57.654 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public org.pack.ch9.spring.transactions.hibernate.home.Contact org.pack.ch9.spring.transactions.hibernate.home.ContactService.save(org.pack.ch9.spring.transactions.hibernate.home.Contact)
01:23:57.654 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.saveContactInSteps' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:57.655 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public org.pack.ch9.spring.transactions.hibernate.home.Contact org.pack.ch9.spring.transactions.hibernate.home.ContactService.saveContactInSteps(org.pack.ch9.spring.transactions.hibernate.home.Contact,java.lang.String,java.lang.String,java.util.Date) throws java.lang.Exception
01:23:57.655 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.findAll' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
01:23:57.656 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public java.util.List org.pack.ch9.spring.transactions.hibernate.home.ContactService.findAll()
01:23:57.656 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.findById' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
01:23:57.656 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public org.pack.ch9.spring.transactions.hibernate.home.Contact org.pack.ch9.spring.transactions.hibernate.home.ContactService.findById(java.lang.Long)
01:23:57.657 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.saveById' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:57.657 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public org.pack.ch9.spring.transactions.hibernate.home.Contact org.pack.ch9.spring.transactions.hibernate.home.ContactService.saveById(org.pack.ch9.spring.transactions.hibernate.home.Contact)
01:23:57.657 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.updateContactFirstName' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:57.657 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public org.pack.ch9.spring.transactions.hibernate.home.Contact org.pack.ch9.spring.transactions.hibernate.home.ContactService.updateContactFirstName(org.pack.ch9.spring.transactions.hibernate.home.Contact) throws java.lang.Exception
01:23:57.658 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.updateContactLastName' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:57.658 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public org.pack.ch9.spring.transactions.hibernate.home.Contact org.pack.ch9.spring.transactions.hibernate.home.ContactService.updateContactLastName(org.pack.ch9.spring.transactions.hibernate.home.Contact) throws java.lang.Exception
01:23:57.658 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.updateContactBday' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:57.658 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public org.pack.ch9.spring.transactions.hibernate.home.Contact org.pack.ch9.spring.transactions.hibernate.home.ContactService.updateContactBday(org.pack.ch9.spring.transactions.hibernate.home.Contact)
01:23:57.659 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.setSessionFactory' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:57.660 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public void org.pack.ch9.spring.transactions.hibernate.home.ContactService.setSessionFactory(org.hibernate.SessionFactory)
01:23:57.661 [main] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'ContactService.getSessionFactory' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:57.661 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public org.hibernate.SessionFactory org.pack.ch9.spring.transactions.hibernate.home.ContactService.getSessionFactory()
01:23:57.661 [main] DEBUG o.s.aop.framework.CglibAopProxy - Found 'equals' method: public boolean java.lang.Object.equals(java.lang.Object)
01:23:57.662 [main] DEBUG o.s.aop.framework.CglibAopProxy - Unable to apply any optimisations to advised method: public java.lang.String java.lang.Object.toString()
01:23:57.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Finished creating instance of bean 'org.springframework.context.event.internalEventListenerFactory'
01:23:57.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0'
01:23:57.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'saveUpdateAdvice'
01:23:57.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'sessionFactory'
01:23:57.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'hibernateProperties'
01:23:57.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor'
01:23:57.698 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor'
01:23:57.699 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionalEventListenerFactory'
01:23:57.699 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
01:23:57.746 [main] DEBUG o.s.c.s.GenericXmlApplicationContext - Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor#21d1b321]
01:23:57.747 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'lifecycleProcessor'
01:23:57.750 [main] DEBUG o.s.c.e.PropertySourcesPropertyResolver - Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
01:23:57.752 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'springTxContactService'
01:23:57.755 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
01:23:57.762 [main] DEBUG o.s.o.h.HibernateTransactionManager - Creating new transaction with name [org.pack.ch9.spring.transactions.hibernate.home.ContactService.findById]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
01:23:57.962 [main] DEBUG o.s.o.h.HibernateTransactionManager - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for Hibernate transaction
01:23:57.964 [main] DEBUG o.s.o.h.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
01:23:57.965 [main] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/springorm]
01:23:57.977 [main] DEBUG o.s.jdbc.datasource.DataSourceUtils - Setting JDBC Connection [com.mysql.jdbc.JDBC4Connection#2a685eba] read-only
01:23:57.983 [main] DEBUG o.s.o.h.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [com.mysql.jdbc.JDBC4Connection#2a685eba]
Hibernate: select distinct contact0_.ID as ID1_0_0_, contacttel1_.ID as ID1_2_1_, hobby3_.HOBBY_ID as HOBBY_ID1_3_2_, contact0_.BIRTH_DATE as BIRTH_DA2_0_0_, contact0_.FIRST_NAME as FIRST_NA3_0_0_, contact0_.LAST_NAME as LAST_NAM4_0_0_, contact0_.VERSION as VERSION5_0_0_, contacttel1_.CONTACT_ID as CONTACT_5_2_1_, contacttel1_.TEL_NUMBER as TEL_NUMB2_2_1_, contacttel1_.TEL_TYPE as TEL_TYPE3_2_1_, contacttel1_.VERSION as VERSION4_2_1_, contacttel1_.CONTACT_ID as CONTACT_5_2_0__, contacttel1_.ID as ID1_2_0__, hobbies2_.CONTACT_ID as CONTACT_2_1_1__, hobbies2_.HOBBY_ID as HOBBY_ID1_1_1__ from contact contact0_ left outer join contact_tel_detail contacttel1_ on contact0_.ID=contacttel1_.CONTACT_ID left outer join contact_hobby_detail hobbies2_ on contact0_.ID=hobbies2_.CONTACT_ID left outer join hobby hobby3_ on hobbies2_.HOBBY_ID=hobby3_.HOBBY_ID where contact0_.ID=?
01:23:58.099 [main] DEBUG o.s.o.h.HibernateTransactionManager - Initiating transaction commit
01:23:58.101 [main] DEBUG o.s.o.h.HibernateTransactionManager - Committing Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[org.pack.ch9.spring.transactions.hibernate.home.Contact#6], EntityKey[org.pack.ch9.spring.transactions.hibernate.home.ContactTelDetail#6], EntityKey[org.pack.ch9.spring.transactions.hibernate.home.ContactTelDetail#7]],collectionKeys=[CollectionKey[org.pack.ch9.spring.transactions.hibernate.home.Contact.contactTelDetails#6], CollectionKey[org.pack.ch9.spring.transactions.hibernate.home.Contact.hobbies#6]]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
01:23:58.103 [main] DEBUG o.s.jdbc.datasource.DataSourceUtils - Resetting read-only flag of JDBC Connection [com.mysql.jdbc.JDBC4Connection#2a685eba]
01:23:58.103 [main] DEBUG o.s.o.h.HibernateTransactionManager - Closing Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[org.pack.ch9.spring.transactions.hibernate.home.Contact#6], EntityKey[org.pack.ch9.spring.transactions.hibernate.home.ContactTelDetail#6], EntityKey[org.pack.ch9.spring.transactions.hibernate.home.ContactTelDetail#7]],collectionKeys=[CollectionKey[org.pack.ch9.spring.transactions.hibernate.home.Contact.contactTelDetails#6], CollectionKey[org.pack.ch9.spring.transactions.hibernate.home.Contact.hobbies#6]]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] after transaction
01:23:58.117 [main] DEBUG o.s.o.h.HibernateTransactionManager - Creating new transaction with name [org.pack.ch9.spring.transactions.hibernate.home.ContactService.saveContactInSteps]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
01:23:58.117 [main] DEBUG o.s.o.h.HibernateTransactionManager - Opened new Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for Hibernate transaction
01:23:58.117 [main] DEBUG o.s.o.h.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
01:23:58.117 [main] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/springorm]
01:23:58.127 [main] DEBUG o.s.o.h.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [com.mysql.jdbc.JDBC4Connection#1daf3b44]
01:23:58.127 [main] DEBUG o.s.o.h.HibernateTransactionManager - Found thread-bound Session [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])] for Hibernate transaction
01:23:58.127 [main] DEBUG o.s.o.h.HibernateTransactionManager - Participating in existing transaction
01:23:58.127 [main] ERROR o.p.c.s.t.h.home.ContactService - Contact First name could not be saved !!
01:23:58.127 [main] ERROR o.p.c.s.t.h.home.ContactService - Contact Last name could not be saved !!
01:23:58.137 [main] INFO o.p.c.s.t.h.home.ContactService - Contact Birth Date saved successfully
01:23:58.138 [main] DEBUG o.s.o.h.HibernateTransactionManager - Initiating transaction commit
01:23:58.138 [main] DEBUG o.s.o.h.HibernateTransactionManager - Committing Hibernate transaction on Session [SessionImpl(PersistenceContext[entityKeys=[EntityKey[org.pack.ch9.spring.transactions.hibernate.home.Contact#6], EntityKey[org.pack.ch9.spring.transactions.hibernate.home.ContactTelDetail#6], EntityKey[org.pack.ch9.spring.transactions.hibernate.home.ContactTelDetail#7]],collectionKeys=[CollectionKey[org.pack.ch9.spring.transactions.hibernate.home.Contact.contactTelDetails#6], CollectionKey[org.pack.ch9.spring.transactions.hibernate.home.Contact.hobbies#6]]];ActionQueue[insertions=ExecutableList{size=0} updates=ExecutableList{size=0} deletions=ExecutableList{size=0} orphanRemovals=ExecutableList{size=0} collectionCreations=ExecutableList{size=0} collectionRemovals=ExecutableList{size=0} collectionUpdates=ExecutableList{size=0} collectionQueuedOps=ExecutableList{size=0} unresolvedInsertDependencies=null])]
Note - I have removed the #Transactional annotations from the methods as i am relying on proxy to achieve the same.
From the logs, it seems that the proxies are getting created but again as pointed out in the comment, will the 3 methods invoked from saveContactInSteps not have a transaction against them as mentioned in the documentation :
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with #Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. #PostConstruct
Is there a way to get around this ? Is AspectJ the only solution ?

Update native query is too slow

I am using Hibernate with native query to update a field in a table with 17000 rows in Oracle.
When I execute the query on Toad, it takes 0.5s to be executed and with the below code no finish ever.
Query query = em.createNativeQuery("UPDATE table SET field= LEAST(NUMERADOR/DENOMINADO, ? )");
query.setParameter(1, value);
query.executeUpdate();
This is the trace:
10-08 14:15:59 DEBUG JpaTransactionManager - Creating new transaction with name [es.package.app.repository.jpa.JPAValorMaximo.update]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
10-08 14:15:59 DEBUG JpaTransactionManager - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl#405264e8] for JPA transaction
10-08 14:15:59 DEBUG AbstractTransactionImpl - begin
10-08 14:15:59 DEBUG LogicalConnectionImpl - Obtaining JDBC connection
10-08 14:15:59 DEBUG LogicalConnectionImpl - Obtained JDBC connection
10-08 14:15:59 DEBUG JdbcTransaction - initial autocommit status: true
10-08 14:15:59 DEBUG JdbcTransaction - disabling autocommit
10-08 14:15:59 DEBUG JpaTransactionManager - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#1bbb3b9e]
10-08 14:15:59 DEBUG SQL - UPDATE table SET field= LEAST(NUMERADOR/DENOMINADO, ? )
Hibernate: UPDATE table SET field= LEAST(NUMERADOR/DENOMINADO, ? )
thanks

XAER_OUTSIDE Exception - Spring 4.0.3 - Hibernate 4.1.12 - JTA - Websphere 8 - DB2

EDIT - I have checked this combinations so it seems there's something wrong with Hibernate 4:
Spring 4 + JPA + Hibernate 4 -> Exception
Spring 4 + Hibernate 4 -> Exception
Spring 4 + JPA + Hibernate 3 -> OK
Spring 4 + Hibernate 3 -> OK
Spring 3 + JPA - Hibernate 4 -> Exception
Spring 3 + JPA - Hibernate 3 -> OK
Spring 3 + Hibernate 3 -> OK
I have recently upgraded an application from Spring 3.2/Hibernate 3.6.10 to Spring 4.0.3 + Hibernate 4.1.12. My environment is IBM Websphere 8.0.0.7 and DB2 and the application is configured to use a XA Datasource.
The point is that at the first database call (subsequent calls are always OK) I am getting this error:
#Transactional(readOnly = true)
public Foo loadFoo(int id) {
LOG.debug("load {}", id);
FooEntity fe = fooDAO.findOne(id);
...
}
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'fooRestController'
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'globalControllerAdvice'
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'transactionManager'
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Invoking WebSphere UOW action: type=1, join=false
org.springframework.data.repository.core.support.TransactionalRepositoryProxyPostProcessor$CustomAnnotationTransactionAttributeSource DEBUG - Adding transactional method 'findOne' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'transactionManager'
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Invoking WebSphere UOW action: type=1, join=true
org.springframework.orm.jpa.EntityManagerFactoryUtils DEBUG - Opening JPA EntityManager
org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl DEBUG - Skipping JTA sync registration due to auto join checking
org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl DEBUG - successfully registered Synchronization
org.hibernate.ejb.AbstractEntityManagerImpl DEBUG - Looking for a JTA transaction to join
org.springframework.orm.jpa.EntityManagerFactoryUtils DEBUG - Registering transaction synchronization for JPA EntityManager
org.hibernate.loader.Loader DEBUG - Loading entity: [com.mycompany.spring4.entity.FooEntity#17027]
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl DEBUG - Obtaining JDBC connection
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl DEBUG - Obtained JDBC connection
DSRA0304E: XAException occurred. XAException contents and details are: "".
DSRA0302E: XAException occurred. Error code is: XAER_OUTSIDE (-9). Exception is: XAER_OUTSIDE
J2CA0027E: An exception occurred while invoking start on an XA Resource Adapter from DataSource jdbc/LOCDBD1_XA, within transaction ID {XidImpl: formatId(57415344), gtrid_length(36), bqual_length(54),
data(0000014517a4c063000000015e7f81b4c90865e6b88e167905e5d2ed67f44ed6409cba5c0000014517a4c063000000015e7f81b4c90865e6b88e167905e5d2ed67f44ed6409cba5c000000010000000000000000000000000001)} : com.ibm.db2.jcc.c.zh: XAER_OUTSIDE
Caused by: javax.transaction.RollbackException: XAResource working outside transaction
at com.ibm.tx.jta.impl.RegisteredResources.startRes(RegisteredResources.java:1019)
at com.ibm.ws.tx.jta.RegisteredResources.enlistResource(RegisteredResources.java:1113)
at com.ibm.ws.tx.jta.TransactionImpl.enlistResource(TransactionImpl.java:2214)
at com.ibm.tx.jta.impl.EmbeddableTranManagerSet.enlist(EmbeddableTranManagerSet.java:150)
at com.ibm.ejs.j2c.XATransactionWrapper.enlist(XATransactionWrapper.java:727)
... 140 more
Caused by: com.ibm.db2.jcc.c.zh: XAER_OUTSIDE
at com.ibm.db2.jcc.b.bc.a(bc.java:1651)
at com.ibm.db2.jcc.b.bc.start(bc.java:1530)
at com.ibm.ws.rsadapter.spi.WSRdbXaResourceImpl.start(WSRdbXaResourceImpl.java:1525)
at com.ibm.ejs.j2c.XATransactionWrapper.start(XATransactionWrapper.java:1475)
at com.ibm.ws.Transaction.JTA.JTAResourceBase.start(JTAResourceBase.java:153)
at com.ibm.tx.jta.impl.RegisteredResources.startRes(RegisteredResources.java:1002)
... 144 more
This is the log trace of the second and successful call :
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'fooRestController'
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'globalControllerAdvice'
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'transactionManager'
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Invoking WebSphere UOW action: type=1, join=false
org.springframework.beans.factory.support.DefaultListableBeanFactory DEBUG - Returning cached instance of singleton bean 'transactionManager'
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Creating new transaction with name [null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly; ''
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Invoking WebSphere UOW action: type=1, join=true
org.springframework.orm.jpa.EntityManagerFactoryUtils DEBUG - Opening JPA EntityManager
org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl DEBUG - Skipping JTA sync registration due to auto join checking
org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl DEBUG - successfully registered Synchronization
org.hibernate.ejb.AbstractEntityManagerImpl DEBUG - Looking for a JTA transaction to join
org.springframework.orm.jpa.EntityManagerFactoryUtils DEBUG - Registering transaction synchronization for JPA EntityManager
org.hibernate.loader.Loader DEBUG - Loading entity: [com.mycompany.spring4.entity.FooEntity#17027]
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl DEBUG - Obtaining JDBC connection
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl DEBUG - Obtained JDBC connection
org.hibernate.loader.Loader DEBUG - Result set row: 0
org.hibernate.loader.Loader DEBUG - Result row: EntityKey[com.mycompany.spring4.entity.FooEntity#17027]
org.hibernate.engine.internal.TwoPhaseLoad DEBUG - Resolving associations for [com.mycompany.spring4.entity.FooEntity#17027]
org.hibernate.engine.internal.TwoPhaseLoad DEBUG - Done materializing entity [com.mycompany.spring4.entity.FooEntity#17027]
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl DEBUG - Releasing JDBC connection
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl DEBUG - Released JDBC connection
org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler DEBUG - HHH000163: Logical connection releasing its physical connection
org.hibernate.loader.Loader DEBUG - Done entity load
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Returned from WebSphere UOW action: type=1, join=true
org.springframework.orm.jpa.EntityManagerFactoryUtils DEBUG - Closing JPA EntityManager
org.hibernate.engine.jdbc.internal.LogicalConnectionImpl DEBUG - Aggressively releasing JDBC connection
org.springframework.transaction.jta.WebSphereUowTransactionManager DEBUG - Returned from WebSphere UOW action: type=1, join=false
The relevant part of my cfg is:
<bean id="mainEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="mainPersistenceUnit"/>
<property name="jtaDataSource" ref="mainDataSource"/>
<property name="packagesToScan" ref="packages-mainEntityManagerFactory"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.jta.platform">org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform</prop>
<prop key="hibernate.current_session_context_class">jta</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory</prop>
</props>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
</property>
</bean>
<tx:annotation-driven order="0" />
<bean name="transactionManager" class="org.springframework.transaction.jta.WebSphereUowTransactionManager">
<property name="allowCustomIsolationLevels" value="true" />
</bean>
Any idea why it fails the first time it's called?
The problem solved by itself upgrading to Spring 4.1.6 and Hibernate 4.2.19. I guess it was a Hibernate-related issue.

Spring 3.1.1 service not lazy loading joined custom objects

I'm getting an odd error when calling a service.
It won't load the user object into the card pojo.
The error is displayed on the user attribute in my card pojo (Viewing through eclipse debug mode).
com.sun.jdi.InvocationException occurred invoking method.
The resulting error then occurs when attempting to render the view:
SEVERE: Servlet.service() for servlet [WebApp] in context with path [/WebApp] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "user.card.alias" (card/index:37)] with root cause
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
#Controller
public class CardController extends AppController
{
static Logger logger = LoggerFactory.getLogger(CardController.class);
#Autowired
private ICardService cardService;
// Card home page (list all cards and options)
#RequestMapping(value = "/card", method = RequestMethod.GET)
public String cardMain(Model model, HttpServletRequest request)
{
PagedListHolder<Card> cards = new PagedListHolder<Card>(
cardService.getAll());
...
}
...
}
#Service
public class CardService implements ICardService
{
#Autowired
ICardDAO cardDAO;
#Transactional
public List<Card> getAll()
{
return cardDAO.findAll();
}
...
}
#Entity
public class Card implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({ #JoinColumn(name = "USERID", referencedColumnName = "ID") })
#Valid
private User user;
public User getUser()
{
if (user == null)
{
user = new User();
}
return user;
}
public void setUser(User user)
{
this.user = user;
}
...
}
#Entity
public class User implements Serializable
{
#OneToOne(mappedBy="user", cascade={CascadeType.ALL})
private UserRole userRole;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
private Set<Card> cards;
public UserRole getUserRole()
{
if (userRole == null)
{
userRole = new UserRole();
}
return userRole;
}
public void setUserRole(UserRole userRole)
{
this.userRole = userRole;
}
public Set<Card> getCards()
{
if (cards == null)
{
cards = new LinkedHashSet<Card>();
}
return cards;
}
public void setCards(Set<Card> cards)
{
this.cards = cards;
}
...
}
I have logging enabled and it looks like it does get them at some point (user=com.webapp.model.User#35, pan=5499999999999999, expiry=1214....):
2012-08-30 00:15:47,212 DEBUG [http-bio-8080-exec-4] o.s.b.f.s.DefaultListableBeanFactory [AbstractBeanFactory.java:245] Returning cached instance of singleton bean 'transactionManager'
2012-08-30 00:15:47,214 DEBUG [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [AbstractPlatformTransactionManager.java:365] Creating new transaction with name [com.webapp.service.impl.CardService.getAll]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
2012-08-30 00:15:47,215 DEBUG [http-bio-8080-exec-4] o.h.i.SessionImpl [SessionImpl.java:265] opened session at timestamp: 13462821472
2012-08-30 00:15:47,216 DEBUG [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [JpaTransactionManager.java:368] Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl#d49865b] for JPA transaction
2012-08-30 00:15:47,216 DEBUG [http-bio-8080-exec-4] o.h.t.JDBCTransaction [JDBCTransaction.java:78] begin
2012-08-30 00:15:47,217 DEBUG [http-bio-8080-exec-4] o.h.j.ConnectionManager [ConnectionManager.java:444] opening JDBC connection
2012-08-30 00:15:47,217 DEBUG [http-bio-8080-exec-4] o.s.j.d.DriverManagerDataSource [DriverManagerDataSource.java:162] Creating new JDBC DriverManager Connection to [jdbc:mysql://localhost:3306/Thesis]
2012-08-30 00:15:47,288 DEBUG [http-bio-8080-exec-4] o.h.t.JDBCTransaction [JDBCTransaction.java:83] current autocommit status: true
2012-08-30 00:15:47,289 DEBUG [http-bio-8080-exec-4] o.h.t.JDBCTransaction [JDBCTransaction.java:86] disabling autocommit
2012-08-30 00:15:47,290 DEBUG [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [JpaTransactionManager.java:400] Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#296fb592]
2012-08-30 00:15:47,292 DEBUG [http-bio-8080-exec-4] o.h.j.AbstractBatcher [AbstractBatcher.java:410] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
2012-08-30 00:15:47,293 DEBUG [http-bio-8080-exec-4] o.h.SQL [SQLStatementLogger.java:111] select card0_.id as id6_, card0_.active as active6_, card0_.alias as alias6_, card0_.cvc as cvc6_, card0_.expiry as expiry6_, card0_.pan as pan6_, card0_.USERID as USERID6_ from Card card0_
2012-08-30 00:15:47,297 DEBUG [http-bio-8080-exec-4] o.h.j.AbstractBatcher [AbstractBatcher.java:426] about to open ResultSet (open ResultSets: 0, globally: 0)
2012-08-30 00:15:47,300 DEBUG [http-bio-8080-exec-4] o.h.l.Loader [Loader.java:1322] result row: EntityKey[com.webapp.model.Card#1]
2012-08-30 00:15:47,301 DEBUG [http-bio-8080-exec-4] o.h.l.Loader [Loader.java:1322] result row: EntityKey[com.webapp.model.Card#2]
2012-08-30 00:15:47,303 DEBUG [http-bio-8080-exec-4] o.h.l.Loader [Loader.java:1322] result row: EntityKey[com.webapp.model.Card#3]
2012-08-30 00:15:47,317 DEBUG [http-bio-8080-exec-4] o.h.j.AbstractBatcher [AbstractBatcher.java:433] about to close ResultSet (open ResultSets: 1, globally: 1)
2012-08-30 00:15:47,317 DEBUG [http-bio-8080-exec-4] o.h.j.AbstractBatcher [AbstractBatcher.java:418] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
2012-08-30 00:15:47,318 DEBUG [http-bio-8080-exec-4] o.h.e.TwoPhaseLoad [TwoPhaseLoad.java:130] resolving associations for [com.webapp.model.Card#1]
2012-08-30 00:15:47,319 DEBUG [http-bio-8080-exec-4] o.h.e.TwoPhaseLoad [TwoPhaseLoad.java:255] done materializing entity [com.webapp.model.Card#1]
2012-08-30 00:15:47,320 DEBUG [http-bio-8080-exec-4] o.h.e.TwoPhaseLoad [TwoPhaseLoad.java:130] resolving associations for [com.webapp.model.Card#2]
2012-08-30 00:15:47,321 DEBUG [http-bio-8080-exec-4] o.h.e.TwoPhaseLoad [TwoPhaseLoad.java:255] done materializing entity [com.webapp.model.Card#2]
2012-08-30 00:15:47,322 DEBUG [http-bio-8080-exec-4] o.h.e.TwoPhaseLoad [TwoPhaseLoad.java:130] resolving associations for [com.webapp.model.Card#3]
2012-08-30 00:15:47,323 DEBUG [http-bio-8080-exec-4] o.h.e.TwoPhaseLoad [TwoPhaseLoad.java:255] done materializing entity [com.webapp.model.Card#3]
2012-08-30 00:15:47,339 DEBUG [http-bio-8080-exec-4] o.h.e.StatefulPersistenceContext [StatefulPersistenceContext.java:893] initializing non-lazy collections
2012-08-30 00:15:47,339 TRACE [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [AbstractPlatformTransactionManager.java:922] Triggering beforeCommit synchronization
2012-08-30 00:15:47,340 TRACE [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [AbstractPlatformTransactionManager.java:935] Triggering beforeCompletion synchronization
2012-08-30 00:15:47,341 DEBUG [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [AbstractPlatformTransactionManager.java:752] Initiating transaction commit
2012-08-30 00:15:47,341 DEBUG [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [JpaTransactionManager.java:507] Committing JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl#d49865b]
2012-08-30 00:15:47,342 DEBUG [http-bio-8080-exec-4] o.h.t.JDBCTransaction [JDBCTransaction.java:130] commit
2012-08-30 00:15:47,342 DEBUG [http-bio-8080-exec-4] o.h.e.d.AbstractFlushingEventListener [AbstractFlushingEventListener.java:134] processing flush-time cascades
2012-08-30 00:15:47,345 DEBUG [http-bio-8080-exec-4] o.h.e.d.AbstractFlushingEventListener [AbstractFlushingEventListener.java:177] dirty checking collections
2012-08-30 00:15:47,347 DEBUG [http-bio-8080-exec-4] o.h.e.d.AbstractFlushingEventListener [AbstractFlushingEventListener.java:108] Flushed: 0 insertions, 0 updates, 0 deletions to 12 objects
2012-08-30 00:15:47,348 DEBUG [http-bio-8080-exec-4] o.h.e.d.AbstractFlushingEventListener [AbstractFlushingEventListener.java:114] Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections
2012-08-30 00:15:47,349 DEBUG [http-bio-8080-exec-4] o.h.p.Printer [Printer.java:106] listing entities:
2012-08-30 00:15:47,354 DEBUG [http-bio-8080-exec-4] o.h.p.Printer [Printer.java:113] com.webapp.model.Card{id=2, alias=sadsdsdf, cvc=111, active=true, user=com.webapp.model.User#35, pan=5499999999999999, expiry=1214}
2012-08-30 00:15:47,355 DEBUG [http-bio-8080-exec-4] o.h.p.Printer [Printer.java:113] com.webapp.model.Card{id=3, alias=asdsdsdfsdf, cvc=122, active=false, user=com.webapp.model.User#47, pan=5411222222222222, expiry=1214}
2012-08-30 00:15:47,358 DEBUG [http-bio-8080-exec-4] o.h.p.Printer [Printer.java:113] com.webapp.model.Card{id=1, alias=sdfsdfsdfd, cvc=111, active=true, user=com.webapp.model.User#35, pan=5411111111111111, expiry=1214}
2012-08-30 00:15:47,361 DEBUG [http-bio-8080-exec-4] o.h.t.JDBCTransaction [JDBCTransaction.java:223] re-enabling autocommit
2012-08-30 00:15:47,363 DEBUG [http-bio-8080-exec-4] o.h.t.JDBCTransaction [JDBCTransaction.java:143] committed JDBC Connection
2012-08-30 00:15:47,363 DEBUG [http-bio-8080-exec-4] o.h.j.ConnectionManager [ConnectionManager.java:427] aggressively releasing JDBC connection
2012-08-30 00:15:47,364 DEBUG [http-bio-8080-exec-4] o.h.j.ConnectionManager [ConnectionManager.java:464] releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
2012-08-30 00:15:47,365 TRACE [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [AbstractPlatformTransactionManager.java:948] Triggering afterCommit synchronization
2012-08-30 00:15:47,365 TRACE [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [AbstractPlatformTransactionManager.java:964] Triggering afterCompletion synchronization
2012-08-30 00:15:47,366 DEBUG [http-bio-8080-exec-4] o.s.o.j.JpaTransactionManager [JpaTransactionManager.java:593] Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl#d49865b] after transaction
2012-08-30 00:15:47,367 DEBUG [http-bio-8080-exec-4] o.s.o.j.EntityManagerFactoryUtils [EntityManagerFactoryUtils.java:343] Closing JPA EntityManager
Any suggestions as to the cause of this error?
I'm using Spring 3.1.1.RELEASE by the way.
I have the same problem, and the reason is thymeleaf, after load the objects, close the database session, as stated by #garis-m-suero on my own post.
By now, this is the way thymeleaf view works, and quoting Mr. #garis-m-suero
you probably can make the scope of the model in spring to be session, but that is not worth it
EDIT:
Another option, that seems to work really fine for me is setting the OpenSessionInViewInterceptor on your configuration like this:
#Bean
public OpenSessionInViewInterceptor openSessionInViewInterceptor(){
OpenSessionInViewInterceptor openSessionInterceptor = new OpenSessionInViewInterceptor();
openSessionInterceptor.setSessionFactory(sessionFactory);
return openSessionInterceptor;
}
and them overriding the addInterceptor with this:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(thymeleafLayoutInterceptor());
registry.addInterceptor(applicationInterceptor());
registry.addWebRequestInterceptor(openSessionInViewInterceptor());
}
Found this solution on github

Resources