Spring Boot Starter : Retry Transaction Question - spring

I'm using the mybatis-spring-boot-starter (2.0.1) and I'm having an issue where sometimes I get a deadlock writing to mysql:
com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:123)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql.cj.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:637)
at com.mysql.cj.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:418)
at com.mysql.cj.jdbc.ClientPreparedStatement.execute(ClientPreparedStatement.java:370)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.execute(ProxyPreparedStatement.java:44)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.execute(HikariProxyPreparedStatement.java)
at org.apache.ibatis.executor.statement.PreparedStatementHandler.update(PreparedStatementHandler.java:47)
at org.apache.ibatis.executor.statement.RoutingStatementHandler.update(RoutingStatementHandler.java:74)
at org.apache.ibatis.executor.SimpleExecutor.doUpdate(SimpleExecutor.java:50)
at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:117)
at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:76)
at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197)
at jdk.internal.reflect.GeneratedMethodAccessor107.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
This is transient and I think it happens with load and I also think it is normal and can be solved with a simple retry.
However, I'm not sure where/how to implement the retry. I know spring supports AOP and also the #retry annotation, etc. but since the s-b-s makes things so easy, I only declare a datasource in my config and a bunch of #Mapper interfaces and s-b-s takes care of everything else.
I'm curious if the s-b-s has a simple way to add/enable retry on failed deadlock exceptions.

You can try using the Spring Retry. Spring Retry provides an ability to automatically re-invoke a failed operation. Please note this is helpful where the errors may be transient in nature (like a momentary network glitch). Spring Retry provides declarative control of the process and policy-based behavior that is easy to extend and customize.
Check out the GitHub repo and Spring docs

Related

Do I need hystrix dependency when I need #Retry and use spring initializr?

I gonna use #Retry in my Spring Boot MVC application while storing a data to DB with optimistic locking via #Version.
I gonna retry multiple times when OptimisticLockException exception happens. And fall down after 100 times (for my logic it's a trigger to check something wrong happened)
So is it a Circuit Breaker pattern described above? Should I use Hystrix dependency for it when creating a project in Spring initializr? Or can I just add spring-retry dependency in gradle/maven and use #Retry?
I confused, please help
You don't need Hystrix for retrying a database call when it fails. You can use the declarative retry (e.g. #Retryable and other annotations) or the imperative API from spring-retry.
As far as dependencies go, yes - just add spring-retry and, if using the declarative retry, there is an additional runtime dependency on AOP classes.
(all of the links above point to the same GitHub Spring project)

Spring-Cloud, Hystrix and JPA - LazyInitializationException

I have the following problem trying to integrate Hystrix into an existent Spring Boot application. I am using boot with spring data (jpa repositories). The structure of the app is pretty simple,
we have Resources -> Services -> Repositories.
I enabled Hystrix support and annotated one of the service methods that returns an entity as follow:
#HystrixCommand(fallback="getDealsFallback")
public Page<Deal> getDeals(...) {
// Get the deals from the Index Server.
return indexServerRepository.findDealsBy(...);
}
public Page<Deal> getDealsFallback(...) {
// If IndexServer is down, query the DB.
return dealsRepository.findDealsBy(...);
}
So this works as expected, the real problem resides actually when I return the Entity to the client. I am using OpenEntityManagerInViewFilter so I can serialize my model with its relations.
When I use #HystrixCommand in my service method, I get a LazyInitializatioException when It tries to serialize.
I know the cause (or at least I suspect what is the problem), and is because Hystrix is executing in another thread
so is not part of the transaction. Changing the Hystrix isolation strategy from THREAD to SEMAPHORE, works correctly since its the same thread, but I understand that is not the correct way to approach the problem.
So my question is, How can I make the Hystrix executing thread be part of the transaction. Is there any workaround that I can apply?
Thanks!
It is a little old thread, but maybe someone meets this problems too. There is an issue in github about this.
The reason is, hystrix will run in separate thread, which is different from where the previous transaction is. So the transaction and serialization for lazy will not work.
And the 'THREAD' is the recommended execution strategy too. So if you want to use both hystrix and transaction, you should use them in 2 level calls. Like, in first level service function, use transaction, and in second level service function, use hystrix and call first level transactional function.

Spring Boot Tests within a Container

I have coded a Spring Boot based web application, which is expected to be run in WildFly server. The applications runs great, but the issue is with testing.
I have the database connections, caching and transaction management dealt by the server. Now, I need to be able to test them. While I was able to get through database connection problem through a mock JNDI connection and the transaction management, I'm not sure how to deal with testing of the caching.
One solution is to use Arquillian project. But, either this project is unable to recognize Spring Boot/ I'm doing something wrong, which is causing me pain to test the application.
Can someone please suggest on solving the issue? Below are my hibernate specific properties
spring.jpa.hibernate.naming_strategy=org.hibernate.cfg.EJB3NamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.SQLServer2008Dialect
spring.jpa.properties.hibernate.cache.region.factory_class=org.jboss.as.jpa.hibernate4.infinispan.InfinispanRegionFactory
spring.jpa.properties.hibernate.cache.infinispan.cachemanager=java:jboss/infinispan/container/hibernate
spring.jpa.properties.hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.show_sql=false
spring.jpa.properties.hibernate.cache.use_query_cache=false
spring.jpa.properties.hibernate.hbm2ddl.auto=none
spring.jpa.properties.hibernate.generate_statistics=true
spring.jpa.properties.hibernate.cache.infinispan.statistics=true
spring.jpa.properties.hibernate.search.default.directory_provider=infinispan
spring.jpa.properties.hibernate.search.infinispan.cachemanager_jndiname=java:jboss/infinispan/container/hibernate
I would suggest creating a separate configuration for tests. This configuration would contain a definition of a TransactionManager bean - here is an example from other post. The next step is to provide your own implementation of TransactionManagerLookup and applying it to Transport configuration - as described in the manual.

Spring transaction support in Netty handlers

I am using the following versions:
Spring 3.1.1.RELEASE
Netty 3.4.0.Final
Hibernate 3.5.6-Final
Now, I have a Netty server that works fairly well - the root of the server, the pipeline factories and the base "stub" of the server that owns everything are all set up with Spring. In this stub, spring #Transactional annotations work just fine.
However, in the handlers, which are stateful and created dynamically depending on what state the user is in - #Transactional doesn't work. I'm fairly sure I understand why. I even have a "solution" - but it's not very good.
After the decoders and encoders, I add an ExecutionHandler:
pipeline.addLast("execution", new ExecutionHandler(new OrderedMemoryAwareThreadPoolExecutor(16,1000000, 1000000)));
This appears to be where the Spring transaction support is breaking. Since Spring is unaware of these threads, it can't bind any transactions to them. The classes are proxied correctly, but in debug they have no associated transactions.
My solution is crappy, and it needs to be replaced by a real solution:
Session sess = SessionFactoryUtils.getSession(getSessionFactory(), true);
That's bad because it relies on me to release the session, and it may not even be transactional, I haven't checked. It sucks in a lot of ways.
Anyway - the root of the question. Given the above tech, what's my path to getting my #Transactional notations working on the Netty handlers?
Write an ExecutionHandler that's Spring aware?
NOTE: I can't upgrade to Hibernate 4, due to lack of compatibility with Spring-Flex, used in another project in the group. Probably the same story for the Spring version, can't remember.
I suggest you create these netty's handler inside spring container and inject the service or persistence layer into the handlers so you can have these layers independence from netty and of course these are old school spring beans.

Is there a better way of detecting if a Spring DB transaction is active than using TransactionSynchronizationManager.isActualTransactionActive()?

I have some legacy code that I am now trying to re-use under Spring. This code is deeply nested in other code so it's not practical to redesign and is called in many situations, only some of which are through Spring. What I'd like to do is to use the Spring transaction if one has been started; otherwise, continue to use the existing (legacy) db connection mechanism. Our first thought was to make our legacy class a bean and use an injected TransactionPlatformManager, but that does not seem to have any methods germane to our situation. Some research showed that Spring has a class called TransactionSynchronizationManager which has a static method isActualTransactionActive(). My testing indicates this method is a reliable way of detecting if a Spring transaction is active:
When called via Spring service without the #Transactional annotation, it returns false
When called via Spring service with #Transactional, it returns true
In my legacy method called the existing way, it returns false
My question: Is there a better way of detecting if a transaction is active?
No better way than the TransactionSynchronizationManager.isActualTransactionActive(). It is the utility method used by spring to handle the transactions. Although it is not advisable to use it within your code, for some specific cases you should - that's why it's public.
Another way might be to use the entity manager / session / connection and check there if there's an existing transaction, but I'd prefer the synchronization manager.

Resources