Reputation: 891
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)
Upvotes: 26
Views: 72418
Reputation: 13
In my case, I was trying to perform some action on ApplicationReadyEvent
,
i.e. one time action on application startup. Marking my method with @Transactional
didn't resolve the problem at first, because my method was private
. You can check this answer for more information, but in short, I had to make the method public
and @Transactional
.
Upvotes: 0
Reputation: 7301
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" />
Upvotes: 56
Reputation: 1
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);
}
Upvotes: 0
Reputation: 1948
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.
Upvotes: 0
Reputation: 99
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
Upvotes: 8
Reputation: 3499
Try this ?
entityManager=entityManager.getEntityManagerFactory().createEntityManager();
Session session = (Session) entityManager.unwrap(Session.class);
Upvotes: 28