I have 3 classes (UserSrvImpl in service layer, MailDaoImpl and UserDaoImpl in dao (repository) layer). In my service layer (UserSrvImpl), i have a method that calls a method from MailDaoImpl and a method from UserDaoImpl. These 2 dao methods have to save objects in 2 different tables. These 2 tables have a OneToOne relasionship. My problem is when the first insertion succeeds and the second fails, there is no roll back. I'm struggling with this problem since a week. I applied all the solutions that i found in google, but still no success. Can you please give me a help. Here is my service layer:
@Service
public class UserSrvImpl implements IUserSrv {
@Autowired
private IUserDao userDao;
@Autowired
private IMailDao mailDao;
@Override
@Transactional
public boolean create(UserDto userDto) {
boolean result = false;
try {
User userToSave = transformDtoToEntity(userDto);
MailToken mailToken = createMailTokenForNewUser(userToSave);
userToSave.setMailToken(mailToken);
if (mailDao.createMailToken(mailToken)) {
result = userDao.create(userToSave);
}
} catch (Exception ex) {
}
return result;
}
The service is calling the dao's method mailDao.createMailToken and userDao.create. If the first succeeds and the second fails, there is no roll back on the first table in the database. Below is the code in MailDao:
@Repository
public class MailDao implements IMailDao {
@Autowired
private SessionFactory sessionFactory;
public Session getSession() {
Session sess = this.sessionFactory.getCurrentSession();
if (sess == null) {
sess = this.sessionFactory.openSession();
}
return sess;
}
@Override
public boolean createMailToken(MailToken mailToken) {
try {
getSession().save(mailToken);
return true;
} catch (HibernateException ex) {
} catch (Exception ex) {
// TODO: handle exception
}
return false;
}
Below is the code in UserDaoImpl:
@Repository
public class UserDaoImpl implements IUserDao {
@Autowired
private SessionFactory sessionFactory;
public Session getSession() {
Session sess = this.sessionFactory.getCurrentSession();
if (sess == null) {
sess = this.sessionFactory.openSession();
}
return sess;
}
@Override
public boolean create(User userToSave) {
try {
getSession().save(userToSave);
return true;
} catch (HibernateException ex) {
ex.printStackTrace();
} catch (Exception ex) {
// TODO: handle exception
}
return false;
}
This is my spring configuration:
<bean id="hibernate5AnnotatedSessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan">
<array value-type="java.lang.String">
<value>com.pointsante.dao.domaine</value>
</array>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Please can you tell me why the @Transactional on the method in the service layer is not working. Thank you.
you should probably use the HibernateTransactionManager instead of DataSourceTransactionManager.
use
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
instead of
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
also check from where the service is called. if you call it from within the service class itself, the proxy which handles the transaction management wont be used.