JPA. No transactional EntityManager available - spring

I'm use JPA (Hibernate 4 vendor) and Spring 3.2.x.
I use this code for get Session and re-attach my detached entity.
Session session = entityManager.unwrap(Session.class);
My code look like this :
#Service
public class SchedulerServiceImpl implements SchedulerService {
#PersistenceContext
private EntityManager entityManager;
#Override
#Transactional
#Scheduled(fixedDelay = 5000)
public void executeTasks() {
.. code ..
while (tasksIterator.hasNext()) {
SchedulerTask readyTask = recalculation(currentTask);
}
.. code ...
}
#Override
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public Deposit recalculation(SchedulerTask schedulerTask) {
boolean asda = entityManager.isOpen(); // get TRUE
Session session = entityManager.unwrap(Session.class); // Exception here
session.update(schedulerTask);
... code ...
}
}
What's wrong?
error :
00:21:52,180 ERROR [org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler]
(pool-10-thread-1) Unexpected error occurred in scheduled task.:
java.lang.IllegalStateException: No transactional EntityManager
available
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invokeSharedEntityManagerCreator.java:224)
[spring-orm-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at com.sun.proxy.$Proxy36.unwrap(Unknown Source)
at com.jar.dom.service.SchedulerServiceImpl.recalculation(SchedulerServiceImpl.java:133)
[classes:]
at com.jar.dom.service.SchedulerServiceImpl.executeTasks(SchedulerServiceImpl.java:92)
[classes:]

I solved this adding this lines on spring configuration
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories("com.blablabla")
class ApplicationConfig {
....
}

Related

#Transactional not starting transactions with Spring Boot 3 / Hibernate 6

I am currently migrating to Spring Boot 3 / Hibernate 6.
Hibernate is correctly parsing all the entities and repos, connecting to the database, etc...
However, it seems #Transactional is not starting transactions correctly.
Small example:
#Component
public class Test {
#Autowired
private EntityManagerFactory entityManager;
#Transactional
public void test() {
Session s = entityManager.unwrap(SessionFactory.class).getCurrentSession();
s.createQuery("FROM sometable").list();
}
}
Error:
Caused by: org.hibernate.HibernateException: Calling method 'createQuery' is not valid without an active transaction (Current status: NOT_ACTIVE)
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:341)
Relevant Config:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages="com.somepackage")
#EntityScan(basePackages="com.somepackage")
public class TransactionConfig {
...
}
session context class in application.properties
...
spring.jpa.properties.hibernate.current_session_context_class=thread
...
If I remove the above setting of session_content_class=thread,
I get this error:
Caused by: org.hibernate.HibernateException: No CurrentSessionContext configured
Edit 1:
The below still results in the same error "is not valid without an active transaction"
#PersistenceUnit
private EntityManagerFactory entityManager;
Edit 2:
If I do not unwrap a session and just call a class with extends extends JpaRepository, it works... but it creates a new transaction and ignores the parent #Transaction
Fix was the following:
#PersistenceContext
private EntityManager entityManager;
and to unwrap:
Session s = entityManager.unwrap(Session.class);

Transactional test in Spring Boot - how to acquire current session?

Spring documentation warns about False Positives in Transactional tests and suggest the following:
// ...
#Autowired
SessionFactory sessionFactory;
#Transactional
#Test // no expected exception!
public void falsePositive() {
updateEntityInHibernateSession();
// False positive: an exception will be thrown once the Hibernate
// Session is finally flushed (i.e., in production code)
}
#Transactional
#Test(expected = ...)
public void updateWithSessionFlush() {
updateEntityInHibernateSession();
// Manual flush is required to avoid false positive in test
sessionFactory.getCurrentSession().flush();
}
// ...
I have the following base class:
#SpringBootTest
#Transactional
#AutoConfigureMockMvc
public abstract class BaseSpringBootTest {
and a class that extends it where I want to apply this practice of injecting the sessionFactory:
public class EmployeeRepositoryTest extends BaseSpringBootTest {
#Autowired
SessionFactory sessionFactory
but I am getting:
NoSuchBeanDefinitionException: No qualifying bean of type 'org.hibernate.SessionFactory' available
I also tried injecting
#Autowired
EntityManagerFactory entityManagerFactory;
and then calling:
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
sessionFactory.getCurrentSession();
but this throws the following Exception:
org.hibernate.HibernateException: No CurrentSessionContext configured!
How do I get a reference to currentSession in a test, so that I can finally call:
sessionFactory.getCurrentSession().flush();
as documented in Spring Boot documentation?

How I can use transactions in TestNG #BeforeClass?

I use TestNG + Spring + hibernate.
When I use transaction in #BeforeClass, I get:
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
Code example:
#Transactional(transactionManager = "transactionManager")
#Rollback
#ContextConfiguration(locations = "/WEB-INF/testing/applicationTestContext.xml")
#TestExecutionListeners(listeners = {
ServletTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
SqlScriptsTestExecutionListener.class,
WithSecurityContextTestExecutionListener.class
})
public abstract class ExampleOfTest extends AbstractTestNGSpringContextTests{
#Autowired
private SessionFactory sessionFactory;
#BeforeClass
public void setUpClass() {
sessionFactory.getCurrentSession().beginTransaction(); // get HibernateException
sessionFactory.getCurrentSession().getTransaction().commit();
}
....
}
How I can use transaction in #BeforeClass?
I want to use this for one-time data entry used in all class tests.
Problem would be #EnableTransactionManagement should be in your spring context
or
Try something like
// BMT idiom with getCurrentSession()
try {
UserTransaction tx = (UserTransaction)new InitialContext()
.lookup("java:comp/UserTransaction");
tx.begin();
// Do some work on Session bound to transaction
sessionFactory.getCurrentSession().persist(...);
tx.commit();
}
catch (RuntimeException e) {
tx.rollback();
throw e; // or display error message
}
getCurrentSession is like restricted, it should run in a active transaction.
I think this may help.

Spring - get EntityManager from #Configuration class

I'm using Spring + Jpa and I'd like to have EntityManager into my #Configuration class.
Now my class is something like this:
#Configuration
#PropertySource("classpath:base.properties")
public class Config {
private static final Logger log = Logger.getLogger(Config.class);
#Bean
public SpringContextManager contextManager() {
return new SpringContextManager(new DefaultApplication());
}
#Bean(initMethod = "start", destroyMethod = "stop")
public ServerSession serverSession() throws Exception {
try {
ServerSession serverSession = new ServerSession(urlGateway, useSsl, hostGateway, portGateway);
serverSession.setDefaultTimeToLive(5000);
return serverSession;
} catch (Throwable e) {
log.error("", e);
return null;
}
}
#Bean
public PluginManager pluginManager() {
PluginManager pluginManager = new PluginManager();
ThreadLocalManager.set(pluginManager);
return pluginManager;
}
I know that I can't add #PersistenceContext to #Configuration class, so I don't know how to get entityManager at this point.
The goal of this is have entityManager asap the app start because I need to set it into a ThreadLocal class ( i need this class to use entityManager inside a JPA entitylistener where inject of persistenceContext don't work).
Now I'm getting the entityManager from a service annotated with #Service but it would be cleaner to made this settings into #Configuration class. Seems more clean.
Thanks for your help.
I found a nice example to solve my problem. This is the link of the tutorial: link

Using Junit 4's Timeout #Rule with Spring's AbstractTransactionalJUnit4SpringContextTests

When i use Junit's org.junit.rules.Timeout with spring's base class AbstractTransactionalJUnit4SpringContextTests, i get this exception:
org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
The log output shows:
2010-07-20 09:20:16 INFO [TransactionalTestExecutionListener.startNewTransaction] Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager#6a1fbe]; rollback [true]
2010-07-20 09:20:16 INFO [TransactionalTestExecutionListener.endTransaction] Rolled back transaction after test execution for test context [[TestContext#17b60b6 testClass = MyIntegrationTest, locations = array<String>['classpath:/context.xml', 'classpath:/junit-context.xml'], testInstance = MyIntegrationTest#10a4d7c, testMethod = myTest#MyIntegrationTest, testException = org.springframework.dao.InvalidDataAccessApiUsageException: no transaction is in progress; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress]]
Here is my test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/context.xml", "classpath:/junit-context.xml"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional
public class MyIntegrationTest extends AbstractTransactionalJUnit4SpringContextTests{
#Rule public Timeout globalTimeout = new Timeout(30000);
#Test
public void myTest() {
// transactional code here saving to the database...
}
}
However whenever i comment out the rule, it all works fine.
How can i marry these two together to work correctly?
Ahh, i worked it out. The way i solved it was to setup the transaction programatically.
#Autowired TransactionManager transactionManager;
#Test
public void test() {
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
status.setRollbackOnly();
// DO YOUR TEST LOGIC HERE
}
});
}
Hope it helps.
LOL.
You can simply also annotate your test method with #Transactional(timeout = 30) for a 30 second timeout. Which is a lot simpler.

Resources