#Transactional on service layer not rolling back Spring MVC+Hibernate - spring

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.

Related

Spring :: #Transactional not working

I am new to Spring and learning the transaction concepts. Unable to get the #Transactional to work.
Use Case:
Data insert of Employee and Employee details should rollback when getEmployee() throws RunTimeException. But the rollback is not happening.
I am using Oracle database 11g and spring 4.3.1.RELEASE. Below is the standalone java code am running.
Code
public static void main( String[] args )
{
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("spring-bean.xml");
ctx.registerShutdownHook();
Employee emp = new Employee("149518", "Mickey", "Mouse", "15 years", "tennis");
IEmployee empIntfc = (IEmployee)ctx.getBean("empService");
try {
empIntfc.createEmployee(emp);
empIntfc.createEmployeeDetails(emp);
//Below will throw RunTime Exception
empIntfc.getEmployee(2);
}catch (Exception e ) {
e.printStackTrace();
} finally {
ctx.close();
}
}
EmployeeService.java
public class EmployeeService implements IEmployee {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
jdbcTemplate = new JdbcTemplate(this.dataSource);
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
#Override
#Transactional
public int createEmployee(Employee emp) {
String sql1 = "INSERT INTO TEST_T1(EMP_ID, EMP_FNAME, EMP_LNAME) values
(?,?,?)";
return getJdbcTemplate().update(sql1, emp.getEmpId(),
emp.getEmpFirstName(), emp.getEmpLastName());
}
#Override
#Transactional
public int createEmployeeDetails(Employee emp) {
String sql = "INSERT INTO TEST_T2(EMP_ID, EXP, SKILLS) values (?,?,?)";
return getJdbcTemplate().update(sql, emp.getEmpId(), emp.getExp(),
emp.getSkills());
}
#Override
#Transactional(readOnly = true, noRollbackFor=RuntimeException.class)
public Employee getEmployee(int empId) {
throw new RuntimeException("Intentional runtime exception");
}
}
spring-bean.xml
<beans xmlns="http://www.springframework.org/schema/beans">
<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#//xxxx:1521/xxxx"/>
<property name="username" value="user"/>
<property name="password" value="user"/>
</bean>
<bean id="empService" class="com.service.EmployeeService">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
Your main method is not transactional ... means : entering 'createEmployee' creates a new transaction and commits it, 'createEmployeeDetails' creates a new transaction and commits it .

Why is my #Autowired field null here?

This is not a duplicate of this question. So please don't close it for "is duplicate of" reasons..
I am trying to autowire a private field in my service class using this tutorial. My problem is that restaurantOwnerRepository remains null and does not get initialized.
servlet-context.xml
<context:component-scan base-package="com.mahlzeit.web.server" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="restaurantOwnerRepository" class="com.mahlzeit.web.server.dao.RestaurantOwnerRepository">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
Service code:
#Component
public class RestaurantInformationServiceImpl extends XsrfProtectedServiceServlet implements RestaurantInformationService {
private static final long serialVersionUID = -4088840947018614411L;
#Autowired
private RestaurantOwnerRepository restaurantOwnerRepository;
private final static Logger logger = Logger.getLogger(RestaurantInformationServiceImpl.class);
#Override
public List<RestaurantDTO> getAvailableRestaurants() {
// restaurantOwnerRepository is 'null'
List<Restaurant> availableRestaurants = restaurantOwnerRepository.getAvailableRestaurants(getSessionId());
return null;
}
private String getSessionId() {
HttpServletRequest httpRequest = getThreadLocalRequest();
return httpRequest.getSession().getId();
}
}
RestaurantOwnerRepository.java
public class RestaurantOwnerRepository implements RestauranOwnerDAO {
private SessionFactory sessionFactory;
public RestaurantOwnerRepository(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
// ..
}
What could be the reason for this?
here is a sample controller for your example , you should define the bean in your context.xml or if you place it in this package : com.mahlzeit.web.server it will be managed by spring automatically , cause as i see you have placed the context:component-scan
#Controller
public class RestaurantInformationServiceImpl {
#Autowired
private RestaurantOwnerRepository restaurantOwnerRepository;
#RequestMapping(value="/")
public #ResponseBody ModelAndView getRestaurants(
HttpServletRequest request,
HttpServletResponse response) {
ModelAndView model = new ModelAndView("yourPage");
List<?> rests = restaurantOwnerRepository.getAvailableRestaurants(httpRequest.getSession().getId());
model.addObject("restList", rests );
return model;
}
}

JPA - Entities are not stored in database

I am facing a problem, when I tried to insert a data into Database through JPA (#persistanceContex)
Observations
Not getting any errors;
Record is not storing into database (save)
When I tried with listAll() ; it retrieving the data from database
Domain
#Entity
public class Test {
#Id
private int id;
#Column(name="full_name")
private String fullName;
#Column(name="mobile_number")
private int mobileNumber;
.....
}
DAO Class
#Repository("testDAO")
#Transactional
public class TestDAO {
private EntityManager entityManager;
#PersistenceContext(unitName="CRUD_Test_Annotation")
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void save(Test test){
entityManager.persist(test);
}
}
Service
#Service("testService")
#Transactional
public class TestService {
private static final Logger logger = LoggerFactory.getLogger(TestService.class);
#Autowired(required=true)
private TestDAO testDAO;
public void save(Test test){
logger.info("TestService::save()");
testDAO.save(test);
}
public void list(){
testDAO.getAll();
}
}
Controller
#RequestMapping(value = "/add", method = RequestMethod.GET)
public String add(Locale locale, Model model) {
Test test = new Test();
test.setId(xx);
test.setFullName("xxxxx");
test.setMobileNumber(yyyyyy);
testService.save(test);
return "home";
}
application-context.xml
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Declare a JPA entityManagerFactory-->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property>
<property name="persistenceUnitName" value="CRUD_Test_Annotation" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<!-- Declare a transaction manager-->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
First of all, you don't need two transaction boundaries, I suggest you remove #Transactional from your DAO and keep the one in your service.
Start by verifying that spring-transaction has initiated a transaction: Use the debugger and stop the application after the transaction boundary, for instance in your TestService.save-method. If transactions are running, you will see org.springframework.transaction.interceptor.TransactionInterceptor#invoke in the call stack. If you don't see the TransactionInterceptor, then that's your problem. Post your persistence.xml file if transactions are running.

Hibernate SessionFactory vs Spring LocalSessionFactoryBean

I am trying to move a spring3.2.x + hibernate4.x setup from a xml to java configuration.
Heres a snippet of the existing code:
import org.hibernate.SessionFactory;
import org.hibernate.Query;
import org.hibernate.Session;
public class StockDaoImpl implements StockDao{
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void save(Stock stock){
Session session = getSessionFactory().openSession();
try{
session.save(stock);
}
finally{
session.close();
}
}
The spring config file
<!-- Stock Data Access Object -->
<bean id="stockDao" class="com.data.dao.StockDaoImpl" >
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="dataSource">
.....
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
......
</property>
<property name="mappingResources">
.......
</property>
</bean>
This works fine - but how do i re-define this config in java?
Heres an attempt -
#Bean
public StockDao stockDao() {
StockDaoImpl dao=new StockDaoImpl();
dao.setSessionFactory(sessionFactory());
return dao;
}
......
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] { .....});
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
But this wont compile as the sessionFactory being referred to is not Spring's LocalSessionFactoryBean?
How do I reconcile this?
LocalSessionFactoryBean is a FactoryBean<SessionFactory>. It means that it allows creating instances of SessionFactory.
So you just need
public StockDao stockDao() {
StockDaoImpl dao=new StockDaoImpl();
dao.setSessionFactory(sessionFactory().getObject());
return dao;
}
But I wouldn't create DAOs explicitel like that. Simply annotate your DAO with #Repository, and autowire the session factory using #Autowired. Make sure the Java config class is annotated with #ComponentScan("the.base.package.of.daos")
Missing getObject() call in return.
Substituite with return sessionFactory.getObject() (and change return type,too!)
JB Nizet's answer helped me, but I needed to declare the beans separately for it to work:
#Bean
public LocalSessionFactoryBean sessionFactoryBean(final DataSource dataSource,
final Properties hibernateProperties,
final List<String> hibernateMappings) {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
sessionFactoryBean.setMappingResources(hibernateMappings.toArray(new String[hibernateMappings.size()]));
return sessionFactoryBean;
}
#Bean
public SessionFactory sessionFactory(LocalSessionFactoryBean sessionFactoryBean) {
return sessionFactoryBean.getObject();
}

Spring Transactions Propagation

JMS/Datasource are full-XA 2PC and are managed by the Weblogic JTA Transaction manager.
The message listener is not transactional annotated...(but it seems that is able to participate in transactions, maybe because of the definition of the JMS container?)
If any unchecked exception is thrown from ServiceB, the transaction gets rollbacked and the message is put back to the JMS queue?
The exception is the caught in serviceA, logged and the dao.update(res) is happening in a new transaction, so it will always executed, regardless of the result in ServiceB.
If dao.update(res) fails, everything will get roll-backed
Can somebody confirm the above? Is my logic correct or am I missing something?
Please for comments and suggestions.
public class MyMessageListener
#Autowired
private ServiceA serviceA;
//I am not declaring this as a transcational.
public void onMessage(Message m) {
serviceA.methodA(m);
}
public class ServiceA {
#Autowired
private ServiceB serviceB;
#Autowired
private DAO dao;
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void methodA() {
try{
String res = ServiceB.methodB(m);
} catch (Exception e) {
log.(e);
}
dao.update(res);
}
public class ServiceB {
#Autowired
private DAO dao;
#Transactional
public void methodB(String m) {
dao.read()
callExtSystem() //this can throw unchecked exception
dao.insert()
}
public class DAO {
#Transactional
public read() {}
#Transactional
public insert(){}
#Transactional(propagation=Propagation.REQUIRES_NEW)
public update(){}
}
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="messageListener"/>
<property name="transactionManager" ref="transactionManager"/> //Weblogic JTA Manager
<property name="concurrentConsumers" value="10"/>
</bean>
<tx:jta-transaction-manager/>

Resources