Hibernate Hangs on saveOrUpdate - java

I am doing a standart getHibernateTemplate().saveOrUpdate() in Spring Hibernate application, but function never returns and does not print any errors.
Debug log is like below.
19:06:07.014 [qtp8540084-26] DEBUG o.s.t.a.AnnotationTransactionAttributeSource - Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
19:06:07.014 [qtp8540084-26] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of singleton bean 'transactionManager'
19:06:07.014 [qtp8540084-26] DEBUG o.s.o.h.HibernateTransactionManager - Found thread-bound Session [org.hibernate.impl.SessionImpl#13ca565] for Hibernate transaction
19:06:07.014 [qtp8540084-26] DEBUG o.s.o.h.HibernateTransactionManager - Creating new transaction with name [com.mydao.InventoryDAOImpl.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
19:06:07.014 [qtp8540084-26] DEBUG o.s.o.h.HibernateTransactionManager - Preparing JDBC Connection of Hibernate Session [org.hibernate.impl.SessionImpl#13ca565]
19:06:07.014 [qtp8540084-26] DEBUG o.h.transaction.JDBCTransaction - begin
19:06:07.014 [qtp8540084-26] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
19:06:07.014 [qtp8540084-26] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBCDriverManager Connection to [jdbc:hsqldb:file:hsqldb/MyDB]
19:06:07.014 [qtp8540084-26] DEBUG o.h.transaction.JDBCTransaction - current autocommit status: true
19:06:07.014 [qtp8540084-26] DEBUG o.h.transaction.JDBCTransaction - disabling autocommit
19:06:07.014 [qtp8540084-26] DEBUG o.s.o.h.HibernateTransactionManager - Exposing Hibernate transaction as JDBC transaction [org.hsqldb.jdbc.jdbcConnection#65335b]
19:06:07.030 [qtp8540084-26] DEBUG o.s.orm.hibernate3.HibernateTemplate - Found thread-bound Session for HibernateTemplate
19:06:07.030 [qtp8540084-26] DEBUG o.s.orm.hibernate3.HibernateTemplate - Not closing pre-bound Hibernate Session after HibernateTemplate
19:06:07.030 [qtp8540084-26] DEBUG o.s.o.h.HibernateTransactionManager - Initiating transaction rollback
19:06:07.030 [qtp8540084-26] DEBUG o.s.o.h.HibernateTransactionManager - Rolling back Hibernate transaction on Session [org.hibernate.impl.SessionImpl#13ca565]
19:06:07.030 [qtp8540084-26] DEBUG o.h.transaction.JDBCTransaction - rollback
19:06:07.030 [qtp8540084-26] DEBUG o.h.transaction.JDBCTransaction - re-enabling autocommit
19:06:07.030 [qtp8540084-26] DEBUG o.h.transaction.JDBCTransaction - rolled back JDBC Connection
19:06:07.030 [qtp8540084-26] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
19:06:07.030 [qtp8540084-26] DEBUG o.s.o.h.HibernateTransactionManager - Not closing pre-bound Hibernate Session [org.hibernate.impl.SessionImpl#13ca565] aftertransaction
19:06:07.030 [qtp8540084-26] DEBUG org.hibernate.impl.SessionImpl - disconnecting session
19:06:07.045 [qtp8540084-26] DEBUG org.hibernate.jdbc.ConnectionManager - releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
19:06:07.045 [qtp8540084-26] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
19:06:07.045 [qtp8540084-26] DEBUG o.s.a.f.a.ThrowsAdviceInterceptor - Found handler for exception of type [java.lang.Throwable]: public void org.springframework.flex.core.ExceptionTranslationAdvice.afterThrowing(java.lang.Throwable)throws java.lang.Throwable
19:06:07.077 [qtp8540084-26] DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'Spring MVC Dispatcher Servlet': assuming HandlerAdapter completed request handling
19:06:07.077 [qtp8540084-26] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
19:06:07.092 [qtp8540084-26] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Chainprocessed normally
19:06:07.092 [qtp8540084-26] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter -SecurityContextHolder now cleared, as request processing completed
19:06:07.092 [qtp8540084-26] DEBUG o.s.o.h.s.OpenSessionInViewFilter - Closing single Hibernate Session in OpenSessionInViewFilter
19:06:07.092 [qtp8540084-26] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Closing Hibernate Session
Regards.
Edit1: I can use this same method of DAO for other entities successfully. Also, I can update a persistent object of this entity, but i can not "save" or "create" a new one with saveOrUpdate.

This hang can be caused by a deadlock between transactions.
Such deadlocks are often caused by incorrect use of several transactions in a single thread (if transactions A and B are created by a single thread, transaction A waits for transaction B to release a lock, but control flow never reaches the point where B is to be committed).
So, make sure that Spring transaction management is configured properly and that you don't mix Spring-managed transactions with manually managed ones.
Another possible reason is a long-running transaction created by external system. If you have some external systems connected to the database in question (for example, administration tools), make sure that transactions created by these systems are committed.

It can also happen if any of the child entities are lazy fetched.changing to eager fetch will resolve the issue

Related

Spring opens a new transaction for each JpaRepository method that is called within an #Transactional annotated method

I have a method that is annotated with #Transactional. That should mean that any database queries that are fired within this method should all use the same transaction. But in reality that doesn't happen. What does happen is that a transaction is opened for the method itself but then when the first JpaRepository method is called a new transaction is opened for that particular method call.
To make matters more complex, For custom repository methods this new transaction is only opened when the JpaRepository or the JpaRepository custom method is annotated with #Transactional as well.
If not i get the following trace log statement about it:
No need to create transaction for
[org.springframework.data.jpa.repository.support.SimpleJpaRepository.findFirstByIdNotNull]:
This method is not transactional.
So it doesn't create a new transaction but it also doesn't seem to use the transaction created by the calling method either.
Heres the repository class:
#Repository
public interface LanguageDao extends JpaRepository<Language, Long> {
#Transactional
public Language findByLanguageCode(String languageCode);
public Language findByIdNotNull();
}
Heres the method that uses different repository methods.
#Transactional
public void afterSingletonsInstantiated() {
languageDao.findByLanguageCode(); //This custom method opens a new transaction, but only because i've annotated this method with #Transactional as well.
languageDao.findAll(); //This one as well because its a standard JpaRepository method.
languageDao.findByIdNotNull();//This custom method doesn't because it lacks its own #Transactional annotation.
}
Heres the #Configuration file, with transaction management and jpa repositories enabled
#EnableJpaRepositories(basePackages={"DAOs"}, transactionManagerRef = "customTransactionManager", enableDefaultTransactions = true)
#EnableTransactionManagement
#Configuration
public class RootConfig implements InitializingBean {
#Bean(name = "customTransactionManager")
JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
if (shouldCreateInitialLuceneIndex) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
createInitialLuceneIndex(entityManager);
entityManager.close();
}
return transactionManager;
}
}
Relevant application.properties settings
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.database-platform = org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.open-in-view = false
A bit of actual logs. The first line shows that a transaction for the method afterSingletonsInstantiated is created.
[TRACE] 2021-11-08 15:32:40.811 [main] TransactionInterceptor - Getting transaction for [config.StartupChecks$$EnhancerBySpringCGLIB$$134b7631.afterSingletonsInstantiated]
[INFO ] 2021-11-08 15:32:40.815 [main] StartupChecks - Calling sequence table reset procedure
[DEBUG] 2021-11-08 15:32:40.833 [main] SQL - {call RESET_SEQUENCE_TABLE_VALUES_TO_LATEST_ID_VALUES()}
[INFO ] 2021-11-08 15:32:41.087 [main] StartupChecks - Sequence tables reset call finished!
[INFO ] 2021-11-08 15:32:41.087 [main] StartupChecks - doing stuff
[INFO ] 2021-11-08 15:32:41.087 [main] StartupChecks - testing!
[TRACE] 2021-11-08 15:32:41.087 [main] TransactionInterceptor - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
[DEBUG] 2021-11-08 15:32:41.088 [main] SQL - select language0_.id as id1_77_, language0_.dateCreated as datecrea2_77_, language0_.englishLanguageName as englishl3_77_, language0_.languageCode as language4_77_, language0_.rightToLeft as righttol5_77_, language0_.translatedLanguageName as translat6_77_ from languages language0_
[TRACE] 2021-11-08 15:32:41.091 [main] TransactionInterceptor - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
[INFO ] 2021-11-08 15:32:41.091 [main] StartupChecks - end test!
[TRACE] 2021-11-08 15:32:41.091 [main] TransactionInterceptor - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findByLanguageCode]
[DEBUG] 2021-11-08 15:32:41.112 [main] SQL - select language0_.id as id1_77_, language0_.dateCreated as datecrea2_77_, language0_.englishLanguageName as englishl3_77_, language0_.languageCode as language4_77_, language0_.rightToLeft as righttol5_77_, language0_.translatedLanguageName as translat6_77_ from languages language0_ where language0_.languageCode=?
[TRACE] 2021-11-08 15:32:41.113 [main] TransactionInterceptor - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findByLanguageCode]
[TRACE] 2021-11-08 15:32:41.113 [main] TransactionInterceptor - No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findFirstByIdNotNull]: This method is not transactional.
[DEBUG] 2021-11-08 15:32:41.115 [main] SQL - select authority0_.ID as id1_7_, authority0_.dateCreated as datecrea2_7_, authority0_.NAME as name3_7_ from AUTHORITY authority0_ where authority0_.ID is not null limit ?
[TRACE] 2021-11-08 15:32:41.120 [main] TransactionInterceptor - No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findFirstByIdNotNull]: This method is not transactional.
Here is a list of the things that i've already tried.
Annotate languageDao with #Transactional(propagation = Propagation.SUPPORTS) or
#Transactional(propagation = Propagation.NESTED). NESTED isn't supported by hibernate and thus this causes an error, This error remains even when i set nestedTransactionAllowed to true on the transactionmanager. The setting SUPPORTS is ignored. The repository still starts a new transaction for each method that is called. (Update: Propagation.MANDATORY has no effect either)
I've named my transactionmanager customTransactionManager and added this as a parameter to #EnableJpaRepositories like so: #EnableJpaRepositories(basePackages={"DAOs"}, transactionManagerRef = "customTransactionManager")
I've set enableDefaultTransactions of #EnableJpaRepositories to false. This causes default methods like findAll() and save() to no longer be executed in a transaction by default. However it doesn't force them to use the transaction of the calling method that was annotated with #Transactional.
So my question is: How do i make the (custom) jpa repositories use the transaction that was started by the calling method?
EDIT: Here JPA - Spanning a transaction over multiple JpaRepository method calls a similar problem is described. According to the user spring only uses the existing transaction when the repository implements Repository instead of CrudRepository or JpaRepository. But this is a workaround.
EDIT 2: My #Transactional annotations keep working when i remove #EnableTransactionManagement. According to this post that can occur when i use spring-boot-starter-jdbc or spring-boot-starter-data-jpa as a dependency, which i do. Could these dependencies somehow interfere with the normal working of the transaction manager?
Here is my attempt at understanding your problem. I would recommend enabling extra debug
logging.level.org.springframework.orm.jpa.JpaTransactionManager=DEBUG
My test Service class - note that this is marked as transactional - for now that's the only place it is put as that's what we intend - to create a transactional boundary.
#Service
public class LanguageService {
#Autowired
private LanguageRepository languageRepository;
#Transactional
public void runAllMethods() {
languageRepository.findByLanguageCode("en");
languageRepository.findAll();
languageRepository.findByIdNotNull();
}
}
Next is the repository - there are no transactional annotations.
public interface LanguageRepository extends JpaRepository<Language, Long> {
public Language findByLanguageCode(String languageCode);
public Language findByIdNotNull();
}
Now on hitting the service via a controller - I get below logs. Notice the line where it says "Creating new transaction with name [com.shailendra.transaction_demo.service.LanguageService.runAllMethods]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT" - meaning that the transaction was created at the beginning of method invocation.
Also note the statement "Participating in existing transaction" which indicates that method is participating in transaction.
2021-11-09 11:43:06.061 DEBUG 24956 --- [nio-8181-exec-1] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(2084817241<open>)] for JPA transaction
2021-11-09 11:43:06.061 DEBUG 24956 --- [nio-8181-exec-1] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [com.shailendra.transaction_demo.service.LanguageService.runAllMethods]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2021-11-09 11:43:06.069 DEBUG 24956 --- [nio-8181-exec-1] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#3107a702]
2021-11-09 11:43:06.069 TRACE 24956 --- [nio-8181-exec-1] o.s.t.i.TransactionInterceptor : Getting transaction for [com.shailendra.transaction_demo.service.LanguageService.runAllMethods]
2021-11-09 11:43:06.099 TRACE 24956 --- [nio-8181-exec-1] o.s.t.i.TransactionInterceptor : No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findByLanguageCode]: This method is not transactional.
Hibernate: select language0_.id as id1_0_, language0_.date_created as date_cre2_0_, language0_.english_language_name as english_3_0_, language0_.language_code as language4_0_, language0_.right_to_left as right_to5_0_, language0_.translated_language_name as translat6_0_ from language language0_ where language0_.language_code=?
2021-11-09 11:43:06.333 DEBUG 24956 --- [nio-8181-exec-1] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(2084817241<open>)] for JPA transaction
2021-11-09 11:43:06.333 DEBUG 24956 --- [nio-8181-exec-1] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
2021-11-09 11:43:06.333 TRACE 24956 --- [nio-8181-exec-1] o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
Hibernate: select language0_.id as id1_0_, language0_.date_created as date_cre2_0_, language0_.english_language_name as english_3_0_, language0_.language_code as language4_0_, language0_.right_to_left as right_to5_0_, language0_.translated_language_name as translat6_0_ from language language0_
2021-11-09 11:43:06.348 TRACE 24956 --- [nio-8181-exec-1] o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll]
2021-11-09 11:43:06.348 TRACE 24956 --- [nio-8181-exec-1] o.s.t.i.TransactionInterceptor : No need to create transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findByIdNotNull]: This method is not transactional.
Hibernate: select language0_.id as id1_0_, language0_.date_created as date_cre2_0_, language0_.english_language_name as english_3_0_, language0_.language_code as language4_0_, language0_.right_to_left as right_to5_0_, language0_.translated_language_name as translat6_0_ from language language0_ where language0_.id is not null
2021-11-09 11:43:06.348 TRACE 24956 --- [nio-8181-exec-1] o.s.t.i.TransactionInterceptor : Completing transaction for [com.shailendra.transaction_demo.service.LanguageService.runAllMethods]
2021-11-09 11:43:06.348 DEBUG 24956 --- [nio-8181-exec-1] o.s.orm.jpa.JpaTransactionManager : Initiating transaction commit
2021-11-09 11:43:06.348 DEBUG 24956 --- [nio-8181-exec-1] o.s.orm.jpa.JpaTransactionManager : Committing JPA transaction on EntityManager [SessionImpl(2084817241<open>)]
For readonly methods - like findAll - you would see "No need to create transaction" - that's because although the default Repository implementation "SimpleJpaRepository" is marked as transactional - the readonly methods are not marked transactional.
#Repository
#Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
After having tried different things, including using a TransactionTemplate i've settled for the following solution:
First i've turned off the default transaction policy for the jparepository methods by annotating a configuration class with the following:
#EnableJpaRepositories(enableDefaultTransactions = false)
enableDefaultTransactions = false causes any inherited method of JpaRepository to stop creating a transaction whenever they're called. Only jpa methods that are explicitly annotated with #Transactional will continue to create a new transaction when called.
All the other ones will now use any transaction that is started by the calling method, for instance a service method that is annotated with #Transactional.
This isn't obvious though because the This method is not transactional log trace message will still be generated for any jpa method that isn't explicitly annotated with #Transactional. This can be a bit confusing.
However i've proven that these methods really do use the transaction of the calling method by testing it with the following custom update method.
#Modifying
#Query("UPDATE User u SET u.userStatus = 1 WHERE u.userStatus = 0")
public void resetActiveUserAccountsToStatusOffline();
Such a method needs to have a transaction or else the exception javax.persistence.TransactionRequiredException: Executing an update/delete query is thrown. But as you can see this jpa method wasn't annotated with #Transactional so it really did use the transaction that was started by the calling service method.
There is one small disadvantage to setting enableDefaultTransactions = false and that is that the transaction type of inherited methods like findAll will not always use a transaction that is read only. This really depends on whether the service level transaction is readonly or not. However you could still override the findAll method and explictly annotate it with Transactional(readOnly = false). Another thing to beware of is that any calling method must always be annotated with #Transactional or the jpa method will run outside a transaction.
I think the advantage far outweighs these small disadvantages though. Because it is very costly performance wise when a new transaction is created for every jpa method call. So this is the solution i'll settle for right now.
To test your own transactions you'll need to add this to your application.properties
logging.level.org.springframework.transaction.interceptor=TRACE
If the setting doesn't work please add Log4j2 to your project.
EDIT:
These additional transactions that are opened by the JpaMethods are only logical transactions when a physical transaction has already been created by the calling method. More about this here: https://docs.spring.io/spring-framework/docs/current/reference/html/data-access.html#transaction
These jpa methods still use the transaction created by the calling method.
The last answer in this SO thread also explains the difference between logical and physical transactions well: Difference between physical and logical transactions in spring
Experienced same issue while having multiple datasources, hence multiple transaction managers. Apparently the problem was that service methods marked #Transactional used the primary transaction manager, while the repositories were configured to use custom transaction manager:
#EnableJpaRepositories(
basePackageClasses = {
MyRepository.class
},
entityManagerFactoryRef = "customEntityManager",
transactionManagerRef = "customTransactionManager"
)
Solved the issue using spring's annotation on service methods with transactionManager param specified #Transactional(transactionManager = "customTransactionManager")

Spring #Transactional across JPA and JDBC

Setup:
spring-boot-starter-parent:2.5.3
spring-boot-starter-data-jpa (version ommitted, defined by parent)
PostgreSQL (latest version)
One datasource configured via spring.datasource properties
Description:
I have a method that uses JdbcOperations (JdbcTemplate) to insert a value into a table.
This table has a foreign key constraint to another table which is managed by a JPA CrudRepository.
The method in question looks like this:
private static final String SAVE_SQL = "INSERT INTO table (entity_id, value) VALUES (?, ?) ON CONFLICT (entity_id, value) DO UPDATE SET value = EXCLUDED.value";
#Transactional
public void save(long id, String value) {
this.otherService.getOrCreateEntity(id);
this.jdbcOperations.update(SAVE_SQL, (ps) -> {
ps.setLong(id);// this is a foreign key to the JPA managed table
ps.setString(value);
});
}
The method of otherService looks like this:
#Transactional
public Entity getOrCreateEntity(long id) {
final Optional<Entity> optionalEntity = this.crudRepository.findById(id);
Entity entity;
if (optionalEntity.isEmpty()) {
entity = new Entity();
entity.setId(id);
entity = this.crudRepository.save(entity);
} else {
entity = optionalEntity.get();
}
return entity;
}
I added the following logging settings to see which transactions are being used:
logging:
level:
org.springframework.orm.jpa: DEBUG
org.springframework.transaction: DEBUG
When the save(long, String) method is called, I can see that a new transaction is created. The otherService.getOrCreateEntity(long)-Method inserts a new Entity and returns it to the method in question.
When the method in question tries to insert its own value using JdbcOperations, I get a DataIntegrityViolationException : violates foreign key constraint.
This is the transaction log:
2021-09-09 21:42:29.704 DEBUG 16077 --- [nio-9000-exec-7] o.s.orm.jpa.JpaTransactionManager : Creating new transaction with name [TheJdbcOperationsUsingService.save]: PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED
2021-09-09 21:42:29.704 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Opened new EntityManager [SessionImpl(2113410426<open>)] for JPA transaction
2021-09-09 21:42:29.704 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#1e809ae2]
-- Call to otherService.getOrCreateEntity(long) start
2021-09-09 21:43:17.710 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(2113410426<open>)] for JPA transaction
2021-09-09 21:43:17.711 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
2021-09-09 21:43:17.712 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(2113410426<open>)] for JPA transaction
2021-09-09 21:43:17.713 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
2021-09-09 21:43:17.719 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Found thread-bound EntityManager [SessionImpl(2113410426<open>)] for JPA transaction
2021-09-09 21:43:17.720 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Participating in existing transaction
-- Call to otherService.getOrCreateEntity(long) finished
2021-09-09 21:43:51.374 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Initiating transaction rollback
2021-09-09 21:43:51.374 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Rolling back JPA transaction on EntityManager [SessionImpl(2113410426<open>)]
2021-09-09 21:43:51.376 DEBUG 16327 --- [nio-9000-exec-6] o.s.orm.jpa.JpaTransactionManager : Closing JPA EntityManager [SessionImpl(2113410426<open>)] after transaction
I tried with different Propagation and Isolation Settings on both sides, but with no luck.
The problem you're running into is that the EntityManager is keeping a cache of unsaved changes in memory until the transaction closes, and so when you try to insert your data via JDBC directly the database still hasn't seen it.
To fix this, you can use the more specific interface JpaRespository, which has a saveAndFlush method that instructs the EntityManager to immediately write out the insert and not to batch the writes later.

Transaction is not committed when spring boot application is run from java -jar

We developed an application using maven spring-boot.
When we run project with NetDeans IDE, everything works fine. But when we build it and run it from java -jar command, it seems that working and do not do database updates. On the other hand, it can read from database.
We are using #Transactional annotations with Jpa repositories. When we set loggers to ALL level, we could see differences between debug logs and build logs.
Debug is handling Transactions with org.springframework.orm.jpa.JpaTransactionManager, but build is not. Build is using org.springframework.jdbc.datasource.DataSourceTransactionManager
As you can see below, logs have some differences
Working one
[DEBUG] 2019-12-20 10:50:32,431 org.springframework.orm.jpa.JpaTransactionManager getTransaction - Creating new transaction with name [com.sportbook.bets.services.BetsServices.updateScheduledTasks]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'transactionManager'
[TRACE] 2019-12-20 10:50:32,431 org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl openSession - Opening Hibernate Session. tenant=null, owner=null
[TRACE] 2019-12-20 10:50:32,431 org.hibernate.internal.SessionImpl <init> - Opened Session [4685449c-c855-4806-a2a0-9ae8cdcd3e10] at timestamp: 1576835432431
[DEBUG] 2019-12-20 10:50:32,432 org.springframework.orm.jpa.JpaTransactionManager doBegin - Opened new EntityManager [SessionImpl(127972401PersistenceContext[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 JPA transaction
[DEBUG] 2019-12-20 10:50:32,432 org.hibernate.engine.transaction.internal.TransactionImpl <init> - On TransactionImpl creation, JpaCompliance#isJpaTransactionComplianceEnabled == false
[DEBUG] 2019-12-20 10:50:32,432 org.hibernate.engine.transaction.internal.TransactionImpl begin - begin
[TRACE] 2019-12-20 10:50:32,432 org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor begin - Preparing to begin transaction via JDBC Connection.setAutoCommit(false)
[TRACE] 2019-12-20 10:50:32,459 org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor begin - Transaction begun via JDBC Connection.setAutoCommit(false)
[TRACE] 2019-12-20 10:50:32,460 org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl afterBeginCallback - ResourceLocalTransactionCoordinatorImpl#afterBeginCallback
[DEBUG] 2019-12-20 10:50:32,460 org.springframework.orm.jpa.JpaTransactionManager doBegin - Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#640b7957]
[TRACE] 2019-12-20 10:50:32,460 org.springframework.transaction.support.TransactionSynchronizationManager bindResource - Bound value [org.springframework.jdbc.datasource.ConnectionHolder#67406405] for key [HikariDataSource (HikariPool-1)] to thread [default_task_executor_thread1]
[TRACE] 2019-12-20 10:50:32,460 org.springframework.transaction.support.TransactionSynchronizationManager bindResource - Bound value [org.springframework.orm.jpa.EntityManagerHolder#7c8d5edd] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6f59896c] to thread [default_task_executor_thread1]
[TRACE] 2019-12-20 10:50:32,460 org.springframework.transaction.support.TransactionSynchronizationManager initSynchronization - Initializing transaction synchronization
[TRACE] 2019-12-20 10:50:32,460 org.springframework.transaction.interceptor.TransactionInterceptor prepareTransactionInfo - Getting transaction for [com.sportbook.bets.services.BetsServices.updateScheduledTasks]
[TRACE] 2019-12-20 10:50:32,460 org.springframework.transaction.support.TransactionSynchronizationManager bindResource - Bound value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata#7e8e7c41] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] to thread [default_task_executor_thread1]
[DEBUG] 2019-12-20 10:50:32,461 org.springframework.data.repository.core.support.TransactionalRepositoryProxyPostProcessor$CustomAnnotationTransactionAttributeSource getTransactionAttribute - Adding transactional method 'save' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
[TRACE] 2019-12-20 10:50:32,461 org.springframework.beans.factory.support.DefaultListableBeanFactory doGetBean - Returning cached instance of singleton bean 'transactionManager'
[TRACE] 2019-12-20 10:50:32,461 org.springframework.transaction.support.TransactionSynchronizationManager getResource - Retrieved value [org.springframework.orm.jpa.EntityManagerHolder#7c8d5edd] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6f59896c] bound to thread [default_task_executor_thread1]
[DEBUG] 2019-12-20 10:50:32,461 org.springframework.orm.jpa.JpaTransactionManager doGetTransaction - Found thread-bound EntityManager [SessionImpl(127972401PersistenceContext[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 JPA transaction
[TRACE] 2019-12-20 10:50:32,461 org.springframework.transaction.support.TransactionSynchronizationManager getResource - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder#67406405] for key [HikariDataSource (HikariPool-1)] bound to thread [default_task_executor_thread1]
[DEBUG] 2019-12-20 10:50:32,461 org.springframework.orm.jpa.JpaTransactionManager handleExistingTransaction - Participating in existing transaction
[TRACE] 2019-12-20 10:50:32,461 org.springframework.transaction.interceptor.TransactionInterceptor prepareTransactionInfo - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
[TRACE] 2019-12-20 10:50:32,464 org.springframework.beans.CachedIntrospectionResults <init> - Getting BeanInfo for class [com.sportbook.bets.entities.ScheduledTasksLog]
[TRACE] 2019-12-20 10:50:32,465 org.springframework.beans.CachedIntrospectionResults <init> - Caching PropertyDescriptors for class [com.sportbook.bets.entities.ScheduledTasksLog]
[TRACE] 2019-12-20 10:50:32,466 org.springframework.beans.CachedIntrospectionResults <init> - Found bean property 'class' of type [java.lang.Class]
[TRACE] 2019-12-20 10:50:32,466 org.springframework.beans.CachedIntrospectionResults <init> - Found bean property 'id' of type [java.lang.Integer]
Not working one
[DEBUG] 2019-12-20 10:45:27,177 org.springframework.jdbc.datasource.DataSourceTransactionManager getTransaction - Creating new transaction with name [com.sportbook.bets.services.BetsServices.updateScheduledTasks]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'transactionManager'
[DEBUG] 2019-12-20 10:45:27,177 org.springframework.jdbc.datasource.DataSourceTransactionManager doBegin - Acquired Connection [HikariProxyConnection#32188486 wrapping com.mysql.cj.jdbc.ConnectionImpl#1dc5318] for JDBC transaction
[DEBUG] 2019-12-20 10:45:27,177 org.springframework.jdbc.datasource.DataSourceTransactionManager doBegin - Switching JDBC Connection [HikariProxyConnection#32188486 wrapping com.mysql.cj.jdbc.ConnectionImpl#1dc5318] to manual commit
[TRACE] 2019-12-20 10:45:27,201 org.springframework.transaction.support.TransactionSynchronizationManager bindResource - Bound value [org.springframework.jdbc.datasource.ConnectionHolder#13277ad] for key [HikariDataSource (HikariPool-1)] to thread [default_task_executor_thread2]
[TRACE] 2019-12-20 10:45:27,201 org.springframework.transaction.support.TransactionSynchronizationManager initSynchronization - Initializing transaction synchronization
[TRACE] 2019-12-20 10:45:27,201 org.springframework.transaction.interceptor.TransactionInterceptor prepareTransactionInfo - Getting transaction for [com.sportbook.bets.services.BetsServices.updateScheduledTasks]
[TRACE] 2019-12-20 10:45:27,201 org.springframework.transaction.support.TransactionSynchronizationManager bindResource - Bound value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata#1b7705] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] to thread [default_task_executor_thread2]
[TRACE] 2019-12-20 10:45:27,201 org.springframework.transaction.support.TransactionSynchronizationManager getResource - Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder#13277ad] for key [HikariDataSource (HikariPool-1)] bound to thread [default_task_executor_thread2]
[DEBUG] 2019-12-20 10:45:27,201 org.springframework.jdbc.datasource.DataSourceTransactionManager handleExistingTransaction - Participating in existing transaction
[TRACE] 2019-12-20 10:45:27,201 org.springframework.transaction.interceptor.TransactionInterceptor prepareTransactionInfo - Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
[DEBUG] 2019-12-20 10:45:27,201 org.springframework.orm.jpa.EntityManagerFactoryUtils doGetTransactionalEntityManager - Opening JPA EntityManager
I could not place all log outputs, but i think these small parts could provide some aspect. Any idea why this can happen?
UPDATE
My datasource configuration:
#Configuration
#EnableJpaRepositories(
basePackages = "com.appdomain.testApp.repositories",
entityManagerFactoryRef = "testAppEntityManagerFactory",
transactionManagerRef = "transactionManager"
)
#EnableTransactionManagement
public class TestAppDataSourceConfig {
#Autowired
private Environment env;
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource.data1")
public DataSourceProperties testAppDataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
public DataSource testAppDataSource() {
DataSourceProperties testAppDataSourceProperties = testAppDataSourceProperties();
return DataSourceBuilder.create()
.driverClassName(testAppDataSourceProperties.getDriverClassName())
.url(testAppDataSourceProperties.getUrl())
.username(testAppDataSourceProperties.getUsername())
.password(testAppDataSourceProperties.getPassword())
.build();
}
#Bean
#Primary
public PlatformTransactionManager transactionManager() {
EntityManagerFactory factory = testAppEntityManagerFactory().getObject();
return new JpaTransactionManager(factory);
}
#Bean(name="testAppEntityManagerFactory")
#Primary
public LocalContainerEntityManagerFactoryBean testAppEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(testAppDataSource());
factory.setPackagesToScan(new String[]{"com.appdomain.testApp.entities"});
factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("spring.jpa.hibernate.ddl-auto"));
jpaProperties.put("hibernate.show-sql", env.getProperty("spring.jpa.show-sql"));
jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
factory.setJpaProperties(jpaProperties);
return factory;
}
#Bean
#Primary
public DataSourceInitializer testAppDataSourceInitializer() {
DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
dataSourceInitializer.setDataSource(testAppDataSource());
dataSourceInitializer.setEnabled(env.getProperty("spring.datasource.data1.initialize", Boolean.class, false));
return dataSourceInitializer;
}
}
My transactional service method:
#Transactional("transactionManager")
public ScheduledTasksLog updateScheduledTasks(ScheduledTasksLog scheduledTasksLog) {
return scheduledTasksLogRepository.save(scheduledTasksLog);
}
#Transactional("transactionManager")
public ScheduledTasksLog getScheduledTasksLogByTaskName(String taskName) {
return scheduledTasksLogRepository.findByTaskName(taskName);
}
My entity repository:
#Repository
public interface ScheduledTasksLogRepository extends
JpaRepository<ScheduledTasksLog, Integer> {
ScheduledTasksLog findByTaskName(String taskName);
}
My appsetting.properties:
jms.enabled=true
debug=true
spring.datasource.auto-commit=false
spring.datasource.data1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.data1.url=jdbc:mysql://localhost:3306/xx?useSSL=false
spring.datasource.data1.username=
spring.datasource.data1.password=
spring.datasource.data1.initialize=true
spring.datasource.data2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.data2.url=jdbc:mysql://localhost:3306/xxx?useSSL=false
spring.datasource.data2.username=
spring.datasource.data2.password=
spring.datasource.data2.initialize=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database=default
eureka.client.enabled=false
# port
server.port=8667
proxyclient.baseuri =http://localhost:9999
spring.batch.job.enabled=false
spring.batch.initialize-schema=always
spring.main.allow-bean-definition-overriding=true
My scheduled task that calls transactional service methods:
#EnableAsync
#Component
#ComponentScan(basePackages = "com.domain.message")
#EnableScheduling
public class ScheduledTasks {
#Autowired
private Sender sender;
#Autowired
private TestService testService;
#Autowired
private Environment env;
#Async
#Scheduled(fixedRate = 40000)
public void testtask() {
try {
logger.info("The time is now:" + dateFormat.format(new Date()));
ScheduledTasksLog scheduledTasksLog = testService.getScheduledTasksLogByTaskName("testtask");
long interval = 0;
if (scheduledTasksLog != null) {
interval = TimeUnit.SECONDS.convert(Math.abs(new Date().getTime() - scheduledTasksLog.getLastRunDate().getTime()), TimeUnit.MILLISECONDS);
interval += 3;
scheduledTasksLog.setLastRunDate(new Timestamp(new Date().getTime()));
} else {
interval = 180;
scheduledTasksLog = new ScheduledTasksLog();
scheduledTasksLog.setTaskName("testtask");
scheduledTasksLog.setLastRunDate(new Timestamp(new Date().getTime()));
}
testService.updateScheduledTasks(scheduledTasksLog);
} catch (Exception e) {
logger.info(e.getMessage());
}
}
}
We use same application.properties file both with in debug and java -jar command.
JpaRepository handles transactions itself. We do not rollback or commit. How can we commit it manually?
Transaction commit part of logs:
Working one:
[TRACE] 2019-12-20 10:50:32,552 org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor commit - Preparing to commit transaction via JDBC Connection.commit()
[TRACE] 2019-12-20 10:50:32,581 org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor commit - Transaction committed via JDBC Connection.commit()
[TRACE] 2019-12-20 10:50:32,581 org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor resetConnection - re-enabling auto-commit on JDBC Connection after completion of JDBC-based transaction
[TRACE] 2019-12-20 10:50:32,609 org.springframework.jms.listener.DefaultMessageListenerContainer doReceiveAndExecute - Consumer [ActiveMQMessageConsumer { value=ID:DESKTOP-LNDR73U-54344-1576835431439-1:1:1:1, started=true }] of session [ActiveMQSession {id=ID:DESKTOP-LNDR73U-54344-1576835431439-1:1:1,started=true} java.lang.Object#1012d727] did not receive a message
[TRACE] 2019-12-20 10:50:32,609 org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor afterTransaction - LogicalConnection#afterTransaction
[TRACE] 2019-12-20 10:50:32,609 org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl releaseResources - Releasing JDBC resources
[TRACE] 2019-12-20 10:50:32,609 org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl afterCompletionCallback - ResourceLocalTransactionCoordinatorImpl#afterCompletionCallback(true)
[TRACE] 2019-12-20 10:50:32,610 org.hibernate.resource.transaction.internal.SynchronizationRegistryStandardImpl tracef - SynchronizationRegistryStandardImpl.notifySynchronizationsAfterTransactionCompletion(3)
[TRACE] 2019-12-20 10:50:32,610 org.hibernate.internal.SessionImpl afterTransactionCompletion - SessionImpl#afterTransactionCompletion(successful=true, delayed=false)
[TRACE] 2019-12-20 10:50:32,610 org.springframework.orm.jpa.JpaTransactionManager triggerAfterCommit - Triggering afterCommit synchronization
[TRACE] 2019-12-20 10:50:32,610 org.springframework.transaction.support.TransactionSynchronizationManager clearSynchronization - Clearing transaction synchronization
[TRACE] 2019-12-20 10:50:32,610 org.springframework.orm.jpa.JpaTransactionManager triggerAfterCompletion - Triggering afterCompletion synchronization
[TRACE] 2019-12-20 10:50:32,610 org.springframework.transaction.support.TransactionSynchronizationManager doUnbindResource - Removed value [org.springframework.orm.jpa.EntityManagerHolder#7c8d5edd] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#6f59896c] from thread [default_task_executor_thread1]
[TRACE] 2019-12-20 10:50:32,610 org.springframework.transaction.support.TransactionSynchronizationManager doUnbindResource - Removed value [org.springframework.jdbc.datasource.ConnectionHolder#67406405] for key [HikariDataSource (HikariPool-1)] from thread [default_task_executor_thread1]
[DEBUG] 2019-12-20 10:50:32,610 org.springframework.orm.jpa.JpaTransactionManager doCleanupAfterCompletion - Closing JPA EntityManager [SessionImpl(127972401PersistenceContext[entityKeys=[EntityKey[com.domain.testapp.entities.ScheduledTasksLog#2]],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])] after transaction
[TRACE] 2019-12-20 10:50:32,610 org.hibernate.internal.SessionImpl closeWithoutOpenChecks - Closing session [4685449c-c855-4806-a2a0-9ae8cdcd3e10]
[TRACE] 2019-12-20 10:50:32,610 org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl close - Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl#18320c9f]
[TRACE] 2019-12-20 10:50:32,610 org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl releaseResources - Releasing JDBC resources
[TRACE] 2019-12-20 10:50:32,611 org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl close - Closing logical connection
[TRACE] 2019-12-20 10:50:32,611 org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl releaseResources - Releasing JDBC resources
[TRACE] 2019-12-20 10:50:32,611 org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl close - Logical connection closed
Not working one:
[TRACE] 2019-12-20 10:45:27,229 org.hibernate.type.descriptor.sql.BasicExtractor extract - extracted value ([lastrund2_2_0_] : [TIMESTAMP]) - [2019-12-20 08:00:06.0]
[TRACE] 2019-12-20 10:45:27,229 org.hibernate.type.descriptor.sql.BasicExtractor extract - extracted value ([taskname3_2_0_] : [VARCHAR]) - [testtask]
[TRACE] 2019-12-20 10:45:27,229 org.hibernate.loader.Loader processResultSet - Done processing result set (1 rows)
[TRACE] 2019-12-20 10:45:27,229 org.hibernate.loader.Loader initializeEntitiesAndCollections - Total objects hydrated: 1
[DEBUG] 2019-12-20 10:45:27,229 org.hibernate.engine.internal.TwoPhaseLoad doInitializeEntity - Resolving associations for [com.domain.testapp.entities.ScheduledTasksLog#2]
[DEBUG] 2019-12-20 10:45:27,229 org.hibernate.engine.internal.TwoPhaseLoad doInitializeEntity - Done materializing entity [com.domain.testapp.entities.ScheduledTasksLog#2]
[TRACE] 2019-12-20 10:45:27,230 org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl release - Releasing statement [HikariProxyPreparedStatement#32276991 wrapping com.mysql.cj.jdbc.ClientPreparedStatement: select scheduledt0_.id as id1_2_0_, scheduledt0_.lastrundate as lastrund2_2_0_, scheduledt0_.taskname as taskname3_2_0_ from scheduled_tasks scheduledt0_ where scheduledt0_.id=2]
[TRACE] 2019-12-20 10:45:27,230 org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl close - Closing result set [HikariProxyResultSet#20385840 wrapping com.mysql.cj.jdbc.result.ResultSetImpl#139168f]
[TRACE] 2019-12-20 10:45:27,230 org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl close - Closing prepared statement [HikariProxyPreparedStatement#32276991 wrapping com.mysql.cj.jdbc.ClientPreparedStatement: select scheduledt0_.id as id1_2_0_, scheduledt0_.lastrundate as lastrund2_2_0_, scheduledt0_.taskname as taskname3_2_0_ from scheduled_tasks scheduledt0_ where scheduledt0_.id=2]
[TRACE] 2019-12-20 10:45:27,230 org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl afterStatementExecution - Starting after statement execution processing [ON_CLOSE]
[TRACE] 2019-12-20 10:45:27,230 org.hibernate.engine.internal.StatefulPersistenceContext initializeNonLazyCollections - Initializing non-lazy collections
[DEBUG] 2019-12-20 10:45:27,230 org.hibernate.loader.Loader loadEntity - Done entity load
[TRACE] 2019-12-20 10:45:27,230 org.springframework.transaction.interceptor.TransactionInterceptor commitTransactionAfterReturning - Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
[TRACE] 2019-12-20 10:45:27,230 org.springframework.transaction.support.TransactionSynchronizationManager doUnbindResource - Removed value [org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$DefaultCrudMethodMetadata#1b7705] for key [public abstract java.lang.Object org.springframework.data.repository.CrudRepository.save(java.lang.Object)] from thread [default_task_executor_thread2]
[TRACE] 2019-12-20 10:45:27,230 org.springframework.transaction.interceptor.TransactionInterceptor commitTransactionAfterReturning - Completing transaction for [com.domain.testapp.services.testservice.updateScheduledTasks]
[TRACE] 2019-12-20 10:45:27,231 org.springframework.jdbc.datasource.DataSourceTransactionManager triggerBeforeCommit - Triggering beforeCommit synchronization
[TRACE] 2019-12-20 10:45:27,231 org.springframework.jdbc.datasource.DataSourceTransactionManager triggerBeforeCompletion - Triggering beforeCompletion synchronization
[TRACE] 2019-12-20 10:45:27,231 org.springframework.transaction.support.TransactionSynchronizationManager doUnbindResource - Removed value [org.springframework.orm.jpa.EntityManagerHolder#1093840] for key [org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#155cf22] from thread [default_task_executor_thread2]
[TRACE] 2019-12-20 10:45:27,231 org.hibernate.internal.SessionImpl closeWithoutOpenChecks - Closing session [55b47b79-008e-4f4a-b6d7-4c33c302171e]
[TRACE] 2019-12-20 10:45:27,231 org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl close - Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl#afa702]
[TRACE] 2019-12-20 10:45:27,231 org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl releaseResources - Releasing JDBC resources
[TRACE] 2019-12-20 10:45:27,231 org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl close - Closing logical connection
[TRACE] 2019-12-20 10:45:27,231 org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl releaseResources - Releasing JDBC resources
[TRACE] 2019-12-20 10:45:27,231 org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl close - Logical connection closed
[DEBUG] 2019-12-20 10:45:27,231 org.springframework.jdbc.datasource.DataSourceTransactionManager processCommit - Initiating transaction commit
[DEBUG] 2019-12-20 10:45:27,231 org.springframework.jdbc.datasource.DataSourceTransactionManager doCommit - Committing JDBC transaction on Connection [HikariProxyConnection#32188486 wrapping com.mysql.cj.jdbc.ConnectionImpl#1dc5318]
[TRACE] 2019-12-20 10:45:27,253 org.springframework.jdbc.datasource.DataSourceTransactionManager triggerAfterCommit - Triggering afterCommit synchronization
[TRACE] 2019-12-20 10:45:27,253 org.springframework.transaction.support.TransactionSynchronizationManager clearSynchronization - Clearing transaction synchronization
[TRACE] 2019-12-20 10:45:27,254 org.springframework.jdbc.datasource.DataSourceTransactionManager triggerAfterCompletion - Triggering afterCompletion synchronization
[TRACE] 2019-12-20 10:45:27,254 org.springframework.transaction.support.TransactionSynchronizationManager doUnbindResource - Removed value [org.springframework.jdbc.datasource.ConnectionHolder#13277ad] for key [HikariDataSource (HikariPool-1)] from thread [default_task_executor_thread2]
[DEBUG] 2019-12-20 10:45:27,295 org.springframework.jdbc.datasource.DataSourceTransactionManager doCleanupAfterCompletion - Releasing JDBC Connection [HikariProxyConnection#32188486 wrapping com.mysql.cj.jdbc.ConnectionImpl#1dc5318] after transaction
After days of trying different solutions i finally found solution.
Cause of this situation is that we use Spring Batch and it wires a jdbc transaction manager named "transactionManager". Our jpa repository entities could not be persisted in it. So we can not add or update to database.
Solution is that we named our primary transaction manager to "primaryTransactionManager" and use it in our services. Also we used it on spring batch step configuration. Everything works as expected.
TLDR: JPA entities does not work with DataSourceTransactionManager.
I noticed below the log entry from the working one.
[TRACE] 2019-12-20 10:50:32,459 org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor begin - Transaction begun via JDBC Connection.setAutoCommit(false)
I noticed below the log entry from the not working one.
[DEBUG] 2019-12-20 10:45:27,177 org.springframework.jdbc.datasource.DataSourceTransactionManager doBegin - Switching JDBC Connection [HikariProxyConnection#32188486 wrapping com.mysql.cj.jdbc.ConnectionImpl#1dc5318] to manual commit
So after comparing these two, I think the probable possible solutions to your problem are listed below.
Use <property name="hibernate.connection.autocommit" value="true" /> in the persistence.xml
(Use this link and this link for more information)
Use this spring.datasource.auto-commit=false in application.properties and commit it from your code.
(Here is the answer to you why! I wonder you must be having one!)
Setting autoCommit to false is the right thing to do.
All RDBMS that I know of commit the transaction at the end unless explicitly rolled back. Do you see a different behavior? If you suspect something is wrong, one option is to turn on logging in the database server, where you would be able to see the commit request.

HibernateTemplate , bulkUpdate and flush mode

We are using hibernateTemplate for our dao's within my current project. I have a situation where I want to have a transaction that rolls back if either operation within the transaction fails (not rocket science, right?).. so basically, here is the method:
// Reserve a deal and add the 'pending order' all in one transaction
#Transactional(propagation = Propagation.REQUIRES_NEW)
private MyUserOrder reserveQuantity(MyUserOrder userOrder, Date updatedOn) throws MyAPIException{
userOrder.setOrderStatus(OrderStatus.PENDING);
int orderReserved = orderDao.reserveQuantity(userOrder);
//for some reason hibernate is flushing on the above line???
if (dealsReserved < 1)
throw new MyAPIException(ExceptionCode.INSUFFICIENT_QUANTITY);
userOrder = userOrderDao.save(userOrder);
//hibernate flushes again!
return userOrder;
}
So, basically we reserve X orders from the databases order availability table... and then save the pending order to the database. I'd like both statements to execute in the same transaction, so if one fails they both roll back. Unfortunately, it looks like the statement for .reserveQuantity is being committed immediately, even though the whole method should run within it's own transaction.
Here is the log..
13:09:28.007 [5253145#qtp-25442933-1] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13291529680
13:09:28.008 [5253145#qtp-25442933-1] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Registering Spring transaction synchronization for new Hibernate Session
13:09:28.009 [5253145#qtp-25442933-1] DEBUG o.s.orm.hibernate3.HibernateTemplate - Found thread-bound Session for HibernateTemplate
13:09:28.011 [5253145#qtp-25442933-1] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
13:09:28.011 [5253145#qtp-25442933-1] DEBUG org.hibernate.jdbc.ConnectionManager - opening JDBC connection
13:09:28.012 [5253145#qtp-25442933-1] DEBUG o.s.j.d.DriverManagerDataSource - Creating new JDBC DriverManager Connection to [jdbc:db2://172.26.10.144:60000/devdb]
13:09:28.189 [5253145#qtp-25442933-1] DEBUG org.hibernate.SQL - update deal set remaining_quantity=remaining_quantity-?, updated_on=?, updated_by=? where id=? and remaining_quantity>=?
13:09:28.242 [5253145#qtp-25442933-1] DEBUG org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
13:09:28.243 [5253145#qtp-25442933-1] DEBUG org.hibernate.jdbc.ConnectionManager - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
13:09:28.244 [5253145#qtp-25442933-1] DEBUG o.s.orm.hibernate3.HibernateTemplate - Not closing pre-bound Hibernate Session after HibernateTemplate
13:09:28.245 [5253145#qtp-25442933-1] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Flushing Hibernate Session on transaction synchronization
13:09:28.246 [5253145#qtp-25442933-1] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Registering Hibernate Session for deferred close
13:09:30.524 [5253145#qtp-25442933-1] DEBUG o.s.o.hibernate3.SessionFactoryUtils - Opening Hibernate Session
13:09:30.525 [5253145#qtp-25442933-1] DEBUG org.hibernate.impl.SessionImpl - opened session at timestamp: 13291529705
13:09:30.534 [5253145#qtp-25442933-1] DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
13:09:30.537 [5253145#qtp-25442933-1] DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
13:09:30.540 [5253145#qtp-25442933-1] DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
13:09:30.543 [5253145#qtp-25442933-1] DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
13:09:30.549 [5253145#qtp-25442933-1] DEBUG o.h.e.def.AbstractSaveEventListener - delaying identity-insert due to no transaction in progress
13:09:30.551 [5253145#qtp-25442933-1] DEBUG o.s.orm.hibernate3.HibernateTemplate - Eagerly flushing Hibernate session
13:09:30.552 [5253145#qtp-25442933-1] DEBUG o.h.e.d.AbstractFlushingEventListener - processing flush-time cascades
13:09:30.554 [5253145#qtp-25442933-1] DEBUG o.h.e.d.AbstractFlushingEventListener - dirty checking collections
13:09:30.556 [5253145#qtp-25442933-1] DEBUG org.hibernate.engine.Collections - Collection found: [<redacted>.UserOrder.dealOrderSet#<delayed:8>], was: [<unreferenced>] (initialized)
13:09:30.558 [5253145#qtp-25442933-1] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 5 insertions, 0 updates, 0 deletions to 5 objects
13:09:30.559 [5253145#qtp-25442933-1] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 1 (re)creations, 0 updates, 0 removals to 1 collections
As you can see, two flush operations occurred.. one about halfway through the log (when I reserve) and another at the end when I try to save the order bean. Here is my data sources config.
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dealsdbDataSource" />
<property name="packagesToScan" value="<redacted>.common"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.archive.autodetection">class</prop>
<prop key="hibernate.show_sql">${hibernate-show-sql}</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.hbm2ddl.import_files">${hibernate.hbm2ddl.import_files}</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate" name="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<constructor-arg ref="sessionFactory" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Also upon investigation, it looks like my flushmode is AUTO in hibernateTemplate.
Any ideas??
Can you please check , if you have declared #Transactional in the orderDao class.
I suppose that could be the cause.
best practice is to have #Transactional at the service layer and not to have any at the DAO layer.

Auditing db-rollbacks

I'm wondering if there is a build-in/standard way to audit db-rollbacks in an Spring (3.1), Hibernate/JPA environment.
Greatful for any hints.
Thanks
Jonny
I thing enabling "hibernate.show_sql" and using the logging configuration
log4j.logger.org.hibernate.SQL=DEBUG, SQL_APPENDER
log4j.additivity.org.hibernate.SQL=false
should help you log SQL statements.
If you want to monitor rollbacks you can setup logging for org.hibernate.transaction package
13:50:28,597 DEBUG http-8080-1 org.hibernate.transaction.JDBCTransaction - begin
13:50:28,657 DEBUG http-8080-1 org.hibernate.transaction.JDBCTransaction - current autocommit status: true
13:50:28,657 DEBUG http-8080-1 org.hibernate.transaction.JDBCTransaction - disabling autocommit
13:50:28,714 DEBUG http-8080-1 org.hibernate.transaction.JDBCTransaction - commit
13:50:28,773 DEBUG http-8080-1 org.hibernate.transaction.JDBCTransaction - re-enabling autocommit
13:50:28,828 DEBUG http-8080-1 org.hibernate.transaction.JDBCTransaction - committed JDBC Connection
If you want to take some action upon transaction rollback, you can use AOP to create an aspect and map it to org.hibernate.Transaction.rollback() method execution.
#Aspect
public class TransactionMonitoringAspect {
#Before("execution(* org.hibernate.Transaction.rollback())")
public void deviceLoad(String deviceSerial) {
//do something here
}
}
you can use various annotations from org.aspectj.lang.annotation package to execute various methods around rollback() method.

Categories

Resources