22

I have a Spring MVC 4.0 application, and I am learning JPA. I use Hibernate as the JPA implementation.

I can configure Hibernate as described in this tutorial. It works fine, but I have to use Hibernate's Session object:

@Autowired
SessionFactory sessionFactory;

...

Session session = sessionFactory.openSession();

Now, I want to use JPA's EntityManager instead. I have followed this tutorial on the same web site (the configuration is very similar). And I tried to obtain an EntityManager object this way:

@PersistenceContext
EntityManager entityManager;

I got a runtime message:

java.lang.IllegalStateException: No transactional EntityManager available

Then, I followed the suggestion in this answer, and tried to use the following code:

@PersistenceContext
EntityManager entityManager;

...

entityManager=entityManager.getEntityManagerFactory().createEntityManager();

It works a few times (about 9 repetitive method invocations), and then the application freezes.

What is the right way to get EntityManager in Spring + Hibernate configuration?

I do not need any Spring transaction functionality for now. I just want to get an access to EntityManager and play with JPA.

Spring/Hibernate configuration file (hibernate.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:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="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/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

    <bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/test_db" />
        <property name="username" value="test" />
        <property name="password" value="test" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="net.myproject" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />

    <tx:annotation-driven />

</beans>

The class where I attempt to use EntityManager

@Repository
public class ProductsService {

    @PersistenceContext
    EntityManager entityManager;

    @Transactional
    public GridResponse<Product> getProducts(GridRequest dRequest) {

        // The following line causes the exception: "java.lang.IllegalStateException: No transactional EntityManager available"
        Session session = entityManager.unwrap(Session.class);

        //...
    }

...
Community
  • 1
  • 1
Alex
  • 883
  • 4
  • 11
  • 23
  • [This](http://ankursinghal86.blogspot.in/2014/08/v-behaviorurldefaultvmlo.html) might help you. – Ankur Singhal Aug 12 '14 at 10:34
  • 1
    For the `@PersistenceContext EntityManager entityManager;` approach, add `tx:annotation-driven` and mark your methods where you use entityManager as `@Transactional`. – Andrei Stefan Aug 12 '14 at 11:20
  • @Andrei thanks for your response. I have already tried these things in my previous experiments, and I have tried it once more just now. I got the same error message: `java.lang.IllegalStateException: No transactional EntityManager available`. (I get the same exception without `` and `@Transactional`). – Alex Aug 12 '14 at 11:45
  • Post some more source code, like where you use that EntityManager (the method and the class definitions with any annotations you might have placed on the class). Is it a webapp? If so, post the `web.xml` and specify in which .xml file the configuration you already posted can be found. – Andrei Stefan Aug 12 '14 at 11:58
  • Can you post `spring-mvc-servlet.xml` as well? – Andrei Stefan Aug 12 '14 at 12:45
  • @Andrei I have posted everything that you suggested. – Alex Aug 12 '14 at 12:53
  • Perform a small test: move all bean definitions from `hibernate.xml` to `spring-mvc-servlet.xml` and give it another try. – Andrei Stefan Aug 12 '14 at 12:55
  • @Andrei I think I found the problem. This line: `Session session = entityManager.unwrap(Session.class);` does not work, but I can use the `entityManager` without a problem for executing queries. As I move from Hibernate API to JPA, I do not need Hibernate's `Session`s any more and I can remove that line completely. However, my code works only with `` in place. So your first response was correct. I would accept it if you put it as an answer. – Alex Aug 12 '14 at 13:24
  • You are correct that using JPA/EntityManager means you no longer need access to the Session. But FYI only - to get at the Session I'm pretty sure you'd have to do `org.hibernate.ejb.EntityManagerImpl em = entityManager.unwrap(org.hibernate.ejb.EntityManagerImpl.class);` then `em.getSession()` – FGreg Aug 12 '14 at 13:42
  • @FGreg Thanks! I'll keep it in mind in case I ever need the `Session` object again. – Alex Aug 13 '14 at 01:03

2 Answers2

15

For the @PersistenceContext EntityManager entityManager; approach, add tx:annotation-driven to your .xml configuration and mark your methods where you use entityManager as @Transactional.

Andrei Stefan
  • 51,654
  • 6
  • 98
  • 89
  • 1
    This line: `Session session = entityManager.unwrap(Session.class);` throws the exception, but I can use the `entityManager` without a problem for executing queries. As I move from Hibernate API to JPA, I do not need Hibernate's `Session`s any more and I can remove that line completely. However, my code works only with `` in place. So this response is correct. – Alex Aug 12 '14 at 13:33
4

It can be use with @Autowired as shown in https://stackoverflow.com/a/33742769/2028440

@Autowired
private EntityManager entityManager;
Bằng Rikimaru
  • 1,512
  • 2
  • 24
  • 50
  • 2
    An additional tip is to call `@Autowired` on the constructor of the class where possible to avoid having to use it individually on each property. – EM-Creations Oct 12 '17 at 14:17