0
votes

Preamble - using Spring

I am confused as to the purpose of the spring @Transactional annotation. I thought from a few blog posts I've read that it would allow me to simplify transaction management and just write this, and it would handle connection/commit/rollback automagically:

public class DaoImpl implements Dao {
   @Autowired
   private SessionFactory sessionFactory;

    @Transactional
    public void saveOrUpdateOne(final AdditionalDataItem item) {
        Session session = sessionFactory.getCurrentSession();
            session.saveOrUpdate(p_item);
    }
}

However this gives me an exception: " Calling method 'saveOrUpdate' is not valid without an active transaction"

If I instead change the save method to this, it all works - so my question is, what is @Transactional doing?

@Override
@Transactional
public void saveOrUpdateOne(final AdditionalDataItem p_item) {
    Session session = null;
    Transaction trans = null;
    try {
        session = sessionFactory.getCurrentSession();
        trans = session.beginTransaction();
        TransactionStatus status = trans.getStatus();
        session.saveOrUpdate(p_item);
        trans.commit();
    } catch (Exception e) {
        LOGGER.error("Exception saving data: {}", e.getMessage());
        if (trans != null) {
            try {
                trans.rollback();
            } catch (RuntimeException rbe) {
                LOGGER.error("Couldn’t roll back transaction", rbe);
            }
        }
    } finally {
        if (session != null && session.isOpen()) {
            try {
                session.close();
            } catch (HibernateException ne) {
                LOGGER.error("Couldn’t close session", ne);
            }
        }
    }
}

For reference, I'm using Java 11 with Spring Framework 5.3.7 and hibernate 5.5.7 and have appropriate dao, session factory and tx manager beans:

    <bean id="sessionFactory" 
      class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="${sessionFactory.datasource}" />
    <property name="configLocation" value="${sessionFactory.configLocation}" />
</bean>

<bean id="txManager" 
  class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="Dao" class="com.xxxxx.dao.DaoImpl">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
1
Is your daoimpl a spring component? - Nathan Hughes
yes, I've edited the question to show the DAO bean being defined. I also tried adding @Service to the bean but get the same result. - Steve Atkinson
where are you calling saveOrUpdateOne from? - Pedro
do you have <tx:annotation-driven/> in your xml, or alternatively the annotation EnableTransactionManagement in some @Configuration class? - Pedro

1 Answers

0
votes

@Transactional is used if you want to update 2 tables if one of them failed the other one will rollback automatic you can use it above method and you can call save or update using bean of a Repository class