I get this error when trying to invoke "persist" method to save entity model to database in my Spring MVC web application. Can't really find any post or page in internet that can relate to this particular error. It seems like something's wrong with EntityManagerFactory bean but i'm fairly new to Spring programming so for me it seems like everything is initialized fine and according to various tutorial articles in web.
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/data/repository
http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.2.xsd">
<context:component-scan base-package="wymysl.Controllers" />
<jpa:repositories base-package="wymysl.repositories"/>
<context:component-scan base-package="wymysl.beans" />
<context:component-scan base-package="wymysl.Validators" />
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>
<bean id="passwordValidator" class="wymysl.Validators.PasswordValidator"></bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:xe" />
<property name="username" value="system" />
<property name="password" value="polskabieda1" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath:./META-INF/persistence.xml" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.H2Dialect" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
</props>
</property>
</bean>
<mvc:annotation-driven />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
</bean>
<bean name="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:resources mapping="/resources/*" location="/resources/css/"
cache-period="31556926"/>
</beans>
RegisterController.java
#Controller
public class RegisterController {
#PersistenceContext
EntityManager entityManager;
#Autowired
PasswordValidator passwordValidator;
#InitBinder
private void initBinder(WebDataBinder binder) {
binder.setValidator(passwordValidator);
}
#RequestMapping(value = "/addUser", method = RequestMethod.GET)
public String register(Person person) {
return "register";
}
#RequestMapping(value = "/addUser", method = RequestMethod.POST)
public String register(#ModelAttribute("person") #Valid #Validated Person person, BindingResult result) {
if(result.hasErrors()) {
return "register";
} else {
entityManager.persist(person);
return "index";
}
}
I had the same problem and I annotated the method as #Transactional and it worked.
UPDATE: checking the spring documentation it looks like by default the PersistenceContext is of type Transaction, so that's why the method has to be transactional (http://docs.spring.io/spring/docs/current/spring-framework-reference/html/orm.html):
The #PersistenceContext annotation has an optional attribute type,
which defaults to PersistenceContextType.TRANSACTION. This default is
what you need to receive a shared EntityManager proxy. The
alternative, PersistenceContextType.EXTENDED, is a completely
different affair: This results in a so-called extended EntityManager,
which is not thread-safe and hence must not be used in a concurrently
accessed component such as a Spring-managed singleton bean. Extended
EntityManagers are only supposed to be used in stateful components
that, for example, reside in a session, with the lifecycle of the
EntityManager not tied to a current transaction but rather being
completely up to the application.
I got this exception while attempting to use a deleteBy custom method in the spring data repository. The operation was attempted from a JUnit test class.
The exception does not occur upon using the #Transactional annotation at the JUnit class level.
This error had me foxed for three days, the situation I faced produced the same error. Following all the advice I could find, I played with the configuration but to no avail.
Eventually I found it, the difference, the Service I was executing was contained in a common jar, the issue turned out to be AspectJ not treating the Service instantiation the same. In effect the proxy was simply calling the underlying method without all the normal Spring magic being executed before the method call.
In the end the #Scope annotation placed on the service as per the example solved the issue:
#Service
#Scope(proxyMode = ScopedProxyMode.INTERFACES)
#Transactional
public class CoreServiceImpl implements CoreService {
#PersistenceContext
protected EntityManager entityManager;
#Override
public final <T extends AbstractEntity> int deleteAll(Class<T> clazz) {
CriteriaDelete<T> criteriaDelete = entityManager.getCriteriaBuilder().createCriteriaDelete(clazz);
criteriaDelete.from(clazz);
return entityManager.createQuery(criteriaDelete).executeUpdate();
}
}
The method I have posted is a delete method but the annotations affect all persistence methods in the same way.
I hope this post helps someone else who has struggled with the same issue when loading a service from a jar
boardRepo.deleteByBoardId(id);
Faced the same issue. GOT javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread
I resolved it by adding #Transactional annotation above the controller/service.
You need to add #Transactional to your methode
I had the same error because I switched from XML- to java-configuration.
The point was, I didn't migrate <tx:annotation-driven/> tag, as Stone Feng suggested.
So I just added #EnableTransactionManagement as suggested here
Setting Up Annotation Driven Transactions in Spring in #Configuration Class, and it works now
Adding the org.springframework.transaction.annotation.Transactional annotation at the class level for the test class fixed the issue for me.
I had the same problem and I added tx:annotation-driven in applicationContext.xml and it worked.
I had the same error when accessing an already transactional-annotated method from a non-transactional method within the same component:
Before:
#Component
public class MarketObserver {
#PersistenceContext(unitName = "maindb")
private EntityManager em;
#Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
public void executeQuery() {
em.persist(....);
}
#Async
public void startObserving() {
executeQuery(); //<-- Wrong
}
}
//In another bean:
marketObserver.startObserving();
I fixed the error by calling the executeQuery() on the self-referenced component:
Fixed version:
#Component
public class MarketObserver {
#PersistenceContext(unitName = "maindb")
private EntityManager em;
#Autowired
private GenericApplicationContext context;
#Transactional(value = "txMain", propagation = Propagation.REQUIRES_NEW)
public void executeQuery() {
em.persist(....);
}
#Async
public void startObserving() {
context.getBean(MarketObserver.class).executeQuery(); //<-- Works
}
}
Just a note for other users searching for answers for thie error. Another common issue is:
You generally cannot call an #transactional method from within the same class.
(There are ways and means using AspectJ but refactoring will be way easier)
So you'll need a calling class and class that holds the #transactional methods.
If you have
#Transactional // Spring Transactional
class MyDao extends Dao {
}
and super-class
class Dao {
public void save(Entity entity) { getEntityManager().merge(entity); }
}
and you call
#Autowired MyDao myDao;
myDao.save(entity);
you won't get a Spring TransactionInterceptor (that gives you a transaction).
This is what you need to do:
#Transactional
class MyDao extends Dao {
public void save(Entity entity) { super.save(entity); }
}
Unbelievable but true.
Without #Transactional annotation you can achieve the same goal with finding the entity from the DB and then removing that entity you got from the DB.
CrudRepositor -> void delete(T var1);
For us, the problem came down to same context settings in multiple configuration files. Check you've not duplicated the following in multiple config files.
<context:property-placeholder location="classpath*:/module.properties"/>
<context:component-scan base-package="...." />
I had the same error code when I used #Transaction on a wrong method/actionlevel.
methodWithANumberOfDatabaseActions() {
methodA( ...)
methodA( ...)
}
#Transactional
void methodA( ...) {
... ERROR message
}
I had to place the #Transactional just above the method methodWithANumberOfDatabaseActions(), of course.
That solved the error message in my case.
I removed the mode from
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
to make this work
I already had the #Transactional but still wasn't working. Turns out I had to get rid of parallelism to make it work.
If you are doing things in parallel, DON'T.
I had this issue for days and nothing I found anywhere online helped me, I'm posting my answer here in case it helps anyone else.
In my case, I was working on a microservice being called through remoting, and my #Transactional annotation at the service level was not being picked up by the remote proxy.
Adding a delegate class between the service and dao layers and marking the delegate method as transactional fixed this for me.
This helped us, maybe it can help others in the future. #Transaction was not working for us, but this did:
#ConditionalOnMissingClass("org.springframework.orm.jpa.JpaTransactionManager")
I got the same error when I executed the Spring JPA deleteAll() method from Junit test cases. I simply used the deleteInBatch() & deleteAllInBatch() and its perfectly works. We do not need to mark #Transactional at the test cases level.
For anyone with the same issue as I had, I was calling a public method method1 from within another class.
method1 then called another public method method2 within the same class.
method2 was annotated with #Transactional, but method1 was not.
All that method1 did was transform some arguments and directly call method2, so no DB operations here.
The issue got solved for me once I moved the #Transactional annotation to method1.
Not sure the reason for this, but this did it for me.
Calling the repository method was being called within a class with #Component, taking that method out of that class and placing it inside another with #Service worked.
It's like you are using the shared EntityManager when you are getting it Autowired so for persisting spring tells that this EntityManager bean is a shared bean and for persisting it needs a hold of this bean till the data persist doesn't get completed so for that we have to use #Transactional so that it gonna start and commit the persistence in a transaction so the data or operation gets completely saved or get rollback completely.
To fix this in a test, you can use #DataJpaTest or #AutoConfigureTestDatabase.
I am trying to nest transactions with different transaction managers wherein if the nested transaction fails the outer main transaction needs to rollback as well
#Transactional(transactionManager = "txManager1", propagation = Propagation.REQUIRED)
public int doOps() {
doSuccessfulDatabaseThings();
doOps2();
}
#Transactional(transactionManager = "txManager2", propagation = Propagation.REQUIRED)
public int doOps2() {
//this throws error
}
My spring config file has
<bean id="dataSource1" class ="com.mchange.v2.c3p0.ComboPooledDataSource">
...
</bean>
<bean id="txManager1" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource1" />
</bean>
<!-- txManager2 defined similarly -->
<tx:annotation-driven/>
However, when doOps2() fails, the transaction in doOps() doesn't rollback. How to make the rollback work?
Bold Statement
You're doing it wrong.
Based on you description,
you want a ChainedTransactionManager.
Create a transaction manager for each of your datasources,
then pass the transaction manager to the ChainedTransactionManager
constructor.
Name the ChainedTransactionManager bean and reference the name in a
#Transactional annotation.
I think the property is named "transactionManager".
For example,
#Transactional(transactionManager = "chainedTransactionManagerBeanName")
When you are referencing the method inside the same bean, the #Transaction will be ignored. These annotations are only used when referenced via Spring bean management, which will make a proxy:
https://www.javacodegeeks.com/2016/05/understanding-transactional-annotation-spring.html#:~:text=At%20a%20high%20level%2C%20when,has%20no%20knowledge%20of%20it.
So calling doOps2 doesnt do anything with the #Transactional txmanager2
I know destroy-method is used to ask spring to call a specific method to clean up. Source. I am using Spring Transaction Manager in my code. I am wondering if using this attribute is useful. If yes, how can I use it? If not when is it useful?
I know that Spring automatically call that method, but when should I use that? Which parts are not handled by Spring that I would need such method?
DataSource attribute
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
...
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Service
#Service
public MyServiceImpl implements MyService{
#Transactional
public void saveData(MyData data){
...
}
#Transactional(readOnly = true)
public List<MyData) readData(long id){
...
}
}
Repository
#Repository
public MyReposImpl implements MyRepos{
#Autowired
SessionFactory sessionFactory;
public void saveData(MyData data) throws HibernateException{
sessionFactory.getCurrentSession().save(data);
}
public List<MyData> readData(long id) throws HibernateException{
...
}
You don't call destroy. You're telling Spring the name of the method so it can call the method when the bean is no longer used, i.e. needs to be destroyed. For singletons, that happens when the Spring container is stopped.
I'm using Spring 3.0.6, with Hibernate 3.2.7.GA in a Java-based webapp. I'm declaring transactions with #Transactional annotations on the controllers (as opposed to in the service layer). Most of the views are read-only.
The problem is, I've got some DAOs which are using JdbcTemplate to query the database directly with SQL, and they're being called outside of a transaction. Which means they're not reusing the Hibernate SessionFactory's connection. The reason they're outside the transaction is that I'm using converters on method parameters in the controller, like so:
#Controller
#Transactional
public class MyController {
#RequestMapping(value="/foo/{fooId}", method=RequestMethod.GET)
public ModelAndView get(#PathVariable("fooId") Foo foo) {
// do something with foo, and return a new ModelAndView
}
}
public class FooConverter implements Converter<String, Foo> {
#Override
public Foo convert(String fooId) {
// call FooService, which calls FooJdbcDao to look up the Foo for fooId
}
}
My JDBC DAO relies on SimpleJdbcDaoSupport to have the jdbcTemplate injected:
#Repository("fooDao")
public class FooJdbcDao extends SimpleJdbcDaoSupport implements FooDao {
public Foo findById(String fooId) {
getJdbcTemplate().queryForObject("select * from foo where ...", new FooRowMapper());
// map to a Foo object, and return it
}
}
and my applicationContext.xml wires it all together:
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="FooConverter"/>
<!-- other converters -->
</set>
</property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
FooConverter (which converts a path variable String to a Foo object) gets called before MyController#get() is called, so the transaction hasn't been started yet. Thus when FooJdbcDAO is called to query the database, it has no way of reusing the SessionFactory's connection, and has to check out its own connection from the pool.
So my questions are:
Is there any way to share a database connection between the SessionFactory and my JDBC DAOs? I'm using HibernateTransactionManager, and from looking at Spring's DataSourceUtils it appears that sharing a transaction is the only way to share the connection.
If the answer to #1 is no, then is there a way to configure OpenSessionInViewFilter to just start a transaction for us, at the beginning of the request? I'm using "on_close" for the hibernate.connection.release_mode, so the Hibernate Session and Connection are already staying open for the life of the request.
The reason this is important to me is that I'm experiencing problems under heavy load where each thread is checking out 2 connections from the pool: the first is checked out by hibernate and saved for the whole length of the thread, and the 2nd is checked out every time a JDBC DAO needs one for a query outside of a transaction. This causes deadlocks when the 2nd connection can't be checked out because the pool is empty, but the first connection is still held. My preferred solution is to make all JDBC DAOs participate in Hibernate's transaction, so that TransactionSynchronizationManager will correctly share the one single connection.
Is there any way to share a database connection between the SessionFactory and my JDBC DAOs? I'm using HibernateTransactionManager, and from looking at Spring's DataSourceUtils it appears that sharing a transaction is the only way to share the connection.
--> Well you can share database connection between SessionFactory and JdbcTemplate. What you need to do is share same datasource between the two. Connection pooling is also shared between the two. I am using it in my application.
What you need to do is configure HibernateTransactionManager for both transactions.
Add JdbcDao class(with properties jdbcTemplate and dataSource with getter-setter) in your existing package structure(in dao package/layer), Extend your jdbc implementation classes by JdbcDao. If you have configured, hibernateTxManager for hibernate, you will not need to configure it.
The problem is, I've got some DAOs which are using JdbcTemplate to query the database directly with SQL, and they're being called outside of a transaction. Which means they're not reusing the Hibernate SessionFactory's connection.
--> You may be wrong here. You may be using same connection, I think, only problem may lie in HibernateTransaction configuration.
Check HibernateTransactionManager javadoc : This transaction manager is appropriate for applications that use a single Hibernate SessionFactory for transactional data access, but it also supports direct DataSource access within a transaction (i.e. plain JDBC code working with the same DataSource). This allows for mixing services which access Hibernate and services which use plain JDBC (without being aware of Hibernate)!
Check my question : Using Hibernate and Jdbc both in Spring Framework 3.0
Configuration : Add dao classes and service classes with your current hibernate classes, do not make separate packages for them, If you want to work with existing configuration. Otherwise configure HibernateTransactionManager in xml configuration and Use #Transactional annotation.
Mistake in your code :
#Controller
#Transactional
public class MyController {......
Use #Transactional annotation in service classes(best practice).
Correction :
#Transactional(readOnly = true)
public class FooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
// do something
}
}
I'm using spring based validation in combination with hibernate validator enabled by the following in my application context:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
....
<property name="jpaPropertyMap">
<map>
<entry key="javax.persistence.validation.factory" value-ref="validator" />
</map>
</property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
I've implemented a custom validator that accesses a database to check validity constraints for a particular object using a spring injected DAO. This results in a java.lang.StackOverflowError as it appears that the validation is called every time an object is loaded from the database from within the validator, causing an infinite loop. To get around this, I have tried setting the flush mode on my entity manager to commit from within the validator with the following code:
entityManager.setFlushMode(FlushModeType.COMMIT);
This results in an "collection not process by flush()" exception from hibernate.
Is there an example of best practice in accessing the database from within a custom validator which will allow me to get around both of these issues?
After much experimentation, it would appear that the best way to do this to is to use the EntityManagerFactory directly from within the code. In the initialize(...) method of the validator class I have the following code:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu_name");
entityManager = emf.createEntityManager();
The downside is that you don't get Spring's DI features, but you can access the database nonetheless.
I ran into this issue as well, here is how I solved it:
#Autowired bean works with #Valid on controller but fails with CRUD repository
In a few words, I also got a reference to the EntityManagerFactory object. However, I set setFlushMode to FlushModeType.COMMIT just before calling my service method. Finally I set it back to FlushModeType.AUTO:
Here is an example:
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {
#PersistenceContext
private EntityManager em;
#Autowired
UserService userService;
#Override
public void initialize(UniqueUsername constraintAnnotation) {
}
#Override
public boolean isValid(String username, ConstraintValidatorContext context) {
try {
em.setFlushMode(FlushModeType.COMMIT);
return userService.findByUsername(username) == null;
} finally {
em.setFlushMode(FlushModeType.AUTO);
}
}
}