26

Project use Hibernate (JPA), Spring and Maven. My entity and DAO in a separate JAR.

pom.xml:

<project ...>
    ...
    <artifactId>database</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>3.5.4-Final</version>
        </dependency>
    </dependencies>    
</project>

DAO:

public class AbstractDAO<T extends BaseEntity> implements GenericDAO<T> {


    private final Class<T> persistentClass;

    private EntityManager entityManager;

    public AbstractDAO(Class<T> entityClass) {
        super();
        this.persistentClass = entityClass;
    }

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }


    public EntityManager getEntityManager() {
        return entityManager;
    }

    ...

    public void fooBar() {
       //Exception from this line
       Session session = getEntityManager().unwrap(Session.class);
       ...
    }

    ....

}

I have a module, which use Spring.

pom.xml:

<project ...>
...
<artifactId>api</artifactId>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.version}</version>
    </dependency>
    ....
</dependencies>

 ...    
</project>

AppContext.xml:

<bean id="authService" scope="singleton" class="com.test.management.AuthServiceImpl" />

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" name="EntityManagerFactory">
        <property name="persistenceUnitName" value="default"></property>
        <property name="dataSource" ref="dataSource"></property>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="showSql" value="true" />
                <property name="generateDdl" value="true" />
                <property name="databasePlatform" value="${db.dialect}" />
            </bean>
        </property>     
    </bean>

    <!-- Values are defined in db.properties -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${db.driver}" />
        <property name="url" value="${db.url}" />
        <property name="username" value="${db.username}" />
        <property name="password" value="${db.password}" />
    </bean>

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

    <tx:annotation-driven />

    <bean id="userDAO" scope="singleton" class="com.test.database.dao.impl.UserDAOImpl">
    </bean>


    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

</beans> 

Service:

public class AuthServiceImpl implements AuthService {

    @Autowired
    private UserDAO userDAO;


    @Override
    public void authorization() {
        userDAO.fooBar();

    }
}

When I'm trying to get the session from EntityManager, I catch this exception:

java.lang.IllegalStateException: No transactional EntityManager available
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:223)
    at $Proxy121.unwrap(Unknown Source) 
Draken
  • 3,134
  • 13
  • 34
  • 54
Anthony Tsivarev
  • 881
  • 3
  • 13
  • 25
  • so.. what kind of entity manager you expect to be available? – eis Jan 25 '13 at 13:28
  • Sorry, I described in detail the question. What do you mean? Unfortunately, I'm new to Hibernate. – Anthony Tsivarev Jan 25 '13 at 13:45
  • Ok, thank you for the added information. Are you within a transaction when you call the method, getting the exception? – eis Jan 25 '13 at 13:59
  • Well... I thought that working with a transaction is in automatic mode, because i use `` – Anthony Tsivarev Jan 25 '13 at 14:07
  • 1
    it says it's annotation driven, you'll need to provide annotations to places that you need to be transactional. I don't see `@Transactional` annotations in your code. – eis Jan 25 '13 at 14:14

5 Answers5

56

You must annotate the method with the @Transactional annotation:

@Transactional
public void fooBar() {
   // Exception from this line
   Session session = getEntityManager().unwrap(Session.class);
   ...
}

And, if necessary e.g. when using plain Spring framework, enable the Spring @Transactional processing with the following declaration in your Spring's xml configuration file (where txManager is the ID of your manager):

<tx:annotation-driven transaction-manager="txManager" />
t0r0X
  • 4,212
  • 1
  • 38
  • 34
poussma
  • 7,033
  • 3
  • 43
  • 68
28

Try this ?

entityManager=entityManager.getEntityManagerFactory().createEntityManager();
Session session = (Session) entityManager.unwrap(Session.class);
bora.oren
  • 3,439
  • 3
  • 33
  • 31
  • 2
    This works for me, what is the magic behind it? why `@PersistenceContext EntityManager entityManager` is not `Transactional` but `entityManager.getEntityManagerFactory().createEntityManager();` is? – daydreamer May 25 '14 at 22:20
  • 1
    Shortly for my understanding; **@PersistenceContext :** is for application server usage (without transaction control if nothing configured). If you want it transactional you can add @Transactional annotation to make spring wrap it. **createEntityManager :** is for application control by spring) spring will make entityManager transactional (inject). – bora.oren Jul 03 '14 at 12:58
  • @baybora.oren do you mean `@Transactional @PersistenceContext private EntityManager entityManager`? That's not allowed – VB_ Dec 19 '14 at 17:16
  • @baybora.oren look at http://stackoverflow.com/questions/27570641/no-transactional-entitymanager-available-in-postconstruct please – VB_ Dec 19 '14 at 17:17
  • @V_B `@PersistenceContext private EntityManager entityManager;` we cant use `@Transactional` because of before transactional proxy created we create entity manager. – bora.oren Dec 24 '14 at 13:41
  • 1
    @baybora what I actually understand, Here `entityManager` is being created explicitly, that is actually **Application Managed Entity Managers** . Container like **Spring** is not resposible for maintaing the life cycle for the `EntityManager` created from it. But you can `@Autowire` `EntityManagerFactory` directly as the bean is already configured in the `applicationContext`. Hence this could be simple like this `emf.createEntityManager().unwrap(Session.class)' to get `Session` – Shafin Mahmud Mar 02 '17 at 16:28
  • It leaks connections. I have tested this code. We need to manage it manually. – royatirek Sep 02 '20 at 21:02
8

None of this was working for me, I finally found that the issue was that I was making my method @Transactional instead I needed the class to be @Transactional

CrispyOz
  • 89
  • 1
  • 3
0

In my case it was another issue (for those who have problems with @Transactional):

@Transactional to work requires a dynamic proxy to work. A proxy for it is needed precisely on the basis of interfaces (JDK Proxy. In this case CGLIB doesnt work). Therefore, making the interface and implementing it by service, the @Transactional annotation will work.

S.Daineko
  • 1,790
  • 1
  • 20
  • 29
0

In my case when I defined custom methods for example findStudentByFirstName this exception started appearing . The issue got solved by adding @Transactional annotation to repository class.

package com.sample.application.studentmanagementapplication.dao;


import com.sample.application.studentmanagementapplication.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import javax.transaction.Transactional;
import java.util.List;


@Repository
@Transactional
public interface StudentRepository extends JpaRepository<Student, Long> {

    List<Student> findByFirstName(String name);

}
RiyaV
  • 1