No transactional entitymanager available in @PostConstruct
Asked Answered
D

2

1

Problem: entityManager.unwrap(SessionImplementor.class) cause no transactional entitymanager available exception.

Code:

@Component
public class HibernateEventWiring {

    @Autowired
    private ViewListener listener;

    @PersistenceContext(unitName = "config-punit")
    private EntityManager entityManager;

    @PostConstruct
    public void registerListeners() {
        SessionFactory sessionFactory = getSessionFactory();
        EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(
                EventListenerRegistry.class);
        registry.getEventListenerGroup(EventType.PRE_UPDATE).appendListener(listener);
    }

    @Transactional
    private SessionFactory getSessionFactory() {
        // EXCEPTION: No transactional entitymanager available
        return entityManager.unwrap(SessionImplementor.class).getFactory(); 
    }
}
Deration answered 19/12, 2014 at 17:3 Comment(2)
https://mcmap.net/q/512857/-java-lang-illegalstateexception-no-transactional-entitymanager-available/1391249, https://mcmap.net/q/110526/-spring-transaction-method-call-by-the-method-within-the-same-class-does-not-work/1391249 Additionally, you should not have inadvertently imported javax.transaction.Transactional (Java EE 7) in place of org.springframework.transaction.annotation.Transactional.Butts
I assume you are using org.springframework.transaction.annotation.Transactional instead of javax.transaction.Transactional annotation. Is that true?Overtrade
R
5

According to this excelent answer:

In the @PostConstruct (as with the afterPropertiesSet from the InitializingBean interface) there is no way to ensure that all the post processing is already done, so (indeed) there can be no Transactions.

As I see, you do not need a transaction nor an entity manager bean, but rather an entity manager factory bean. I think you should simply autowire the EntityManagerFactory and then unwrap the Hibernate SessionFactory from it.

@Autowired
private EntityManagerFactory entityManagerFactory;

@PostConstruct
public void registerListeners() {
    SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
    ...
}
Rockey answered 19/12, 2014 at 17:45 Comment(3)
EntityManagerFactory hasn't unwrap method. Update your answer to ((HibernateEntityManagerFactory) entityManagerFactory).getSessionFactory() pleaseDeration
Since version 2.1 of JPA there is the unwrap method on EntityManagerFactory class. (javaee 7 javadoc)Rockey
I ended using a slight variation of your answer by using entityManager.getEntityManagerFactory().unwrap(SessionFactory.class) (which was inspired by this answer) since the entityManager was already being injected to the class by Spring.Rew
P
0

It works for me like this to initialize DB in my unit test:

   @Autowired
   private EntityManagerFactory entityManagerFactory;

   @PostConstruct
   public void initDb() {
         Request request = new Request();
         request.setAction("test action");
         EntityManager em = entityManagerFactory.createEntityManager();
         EntityTransaction transaction = em.getTransaction();
         transaction.begin();
         em.persist(request);
         em.flush();
         transaction.commit();

   }
Payoff answered 2/5 at 10:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.