Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA without transaction

I´m new to JPA. I´m developing an application which uses JPA (Hibernate implementation) and Spring. I´ve declared a persistence unit in my persistence.xml and configuration about EntityManagerFactory in my Spring config files. Something like this:

<bean id="myEmf"   class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="packagesToScan" value="my.package" />
  <property name="jpaVendorAdapter">
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
  </property>
  <property name="jpaProperties">
     <props>
        <prop key="hibernate.hbm2ddl.auto">create-drop</prop>
        <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
     </props>
  </property>

Then I have some DAOs where I inject the entityManager with the @PersistenceContext annotation:

public MyDaoImpl implements MyDao{
   private EntityManager entityManager;

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

And finally, I have some services where DAOs are injected (by @Autowired Spring's annotation):

public MyServiceImpl implements MyService{
  @Autowired
  private MyDao myDao;

  public List<MyEntity> readOperation(){
   //
   return myDAo.searchAll();
 }
}

As its a read only operation I thought it wasn´t needed the @Transactional annotation, but without it, there is an exception:

java.lang.IllegalStateException: No transactional EntityManager available
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:223)
    at $Proxy121.unwrap(Unknown Source) 

I´ve read some other posts like this: java.lang.IllegalStateException: No transactional EntityManager available

And all is said is that the transactional annotation is needed. It´s true that it works with it, but I´d like to know (and why) if all methods (even read only operations) must be transactional.

like image 635
user1093643 Avatar asked Oct 21 '22 07:10

user1093643


2 Answers

A JPA Transaction is needed for all your methods - essentially a transaction is what opens a Hibernate session, and you need an open session to interact with it.

You can annotate the transactions as readonly or readwrite, and you can also annotate at the class level to save you annotating each method. For example:

@Transactional(readOnly = true)
public MyDaoImpl implements MyDao{
    private EntityManager entityManager;

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

    @Transactional(readOnly = false)
    public void saveItem(MyEntity entity) {
    }

    public List<MyEntity> searchAll() {
    }
} 
like image 76
John Farrelly Avatar answered Oct 23 '22 01:10

John Farrelly


You a need a transaction for all operations that change anything in DB (the only exception is SELECT queries, without locking). Check this answer.

like image 40
V G Avatar answered Oct 23 '22 02:10

V G