Spring #Transactional - JPA context in transaction problem - spring

I'm using Spring + JSF + JPA configuration hosted on Glassfish v3.1.
I'm experiencing some strange (at least for me) behavior of #Transactional annotation. Here is my simplified example:
#Transactional
public void associateGroupToRole(String role, String group) throws MyServiceException {
GroupEntity groupEntity = userDao.getGroupByName(group);
RoleEntity roleEntity = userDao.getRoleByName(role);
//some stuff
if(!roleEntity.getGroups().contains(groupEntity)) {
roleEntity.getGroups().add(groupEntity);
}
}
#Transactional
public void associateGroupToRole(RoleEntity roleEntity, GroupEntity groupEntity) throws MyServiceException {
//some stuff
if(!roleEntity.getGroups().contains(groupEntity)) {
roleEntity.getGroups().add(groupEntity);
}
}
It turns out that "associateGroupToRole" with Entities as arguments works correctly and the one with String - does not. After small modification and coping code from one method to another:
#Transactional
public void associateGroupToRole(String role, String group) throws MyServiceException {
GroupEntity groupEntity = userDao.getGroupByName(group);
RoleEntity roleEntity = userDao.getRoleByName(role);
if(!roleEntity.getGroups().contains(groupEntity)) {
roleEntity.getGroups().add(groupEntity);
}
}
The code runs without any problems and everything is committed to database. My question is: What might be wrong in above example, what is happening to transaction context (when accessing from one annotated method to another), and why my entities are no longer in managed state?
Here is my Spring configuration:
<context:annotation-config />
<context:component-scan base-package="com.mypackage"/>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
<tx:jta-transaction-manager/>
<tx:annotation-driven/>
As you can see I'm using persistence.xml file and my EntityManager uses JNDI to connect to DB.

Unfortunately there was a bug in some other piece of DAO code. Please vote for close this question.

Related

How to set the Transaction isolationlevel using Spring with MyBatis

I like to set the Isolationlevel by my self, using the transactionmanager from the Spring Framework combined with myBatis. I was trying a lot of tutorial, but nothing worked.
My application is build as MVC Pattern, that means i have views, models, interfaces used for the dependency-injection from mybatis and a controller class.
I hope someone can give me advice i am new in mybatis and spring. The whole application is running very well but I like to take over controll over the isolationlevels.
This is the spring-configuration.xml file
<!--<mybatis-spring:scan base-package="de.hrw.model.**"/> -->
<mybatis-spring:scan base-package="de.hrw.*" />
<context:component-scan base-package="de.hrw.*" />
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/carrental">
</property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="autoCommit" value="false"></property>
<property name="registerMbeans" value="true"></property>
<property name="transactionIsolation"
value="TRANSACTION_SERIALIZABLE">
</property>
</bean>
<bean id="sqlSessionFactoryBean"
class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:mybatis-config.xml">
</property>
</bean>
<bean id="carController" class="de.hrw.controller.CarController">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="carSearchView" class="de.hrw.view.CarSearchView">
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
I am using the dependecy-injection of mybatis to get data from and to the database
example of an iterface
package de.hrw.mgmtDAO;
import java.util.List;
import de.hrw.model.CarModel;
public interface ICarMgmt {
public CarModel selectCarById(final int carId);
public List<CarModel> selectAllCars();
}
this is the main-class where i include a view (frame)
public class Carrental_main {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
CarController carController = (CarController) context.getBean("carController");
carController.openSearchView();
carController.getCarSearchView().setVisible(true);
}
}
this is the controller. Here i try to set the isolation level to SERIALIZABLE but it is always set to default (-1)
#Transactional(propagation=Propagation.REQUIRES_NEW , isolation = Isolation.SERIALIZABLE)
public class CarController {
#Autowired
private ICarMgmt carMgmt;
private CarSearchView carSearchView;
private ApplicationContext applicationContext;
#Autowired
private PlatformTransactionManager transactionManager;
private TransactionStatus transactionStatus;
private TransactionDefinition defaultTransactionDefinition;
private DataSource dataSource;
public void openSearchView() {
this.setApplicationContext();
this.setDefaultTransactionDefinition();
this.setTransactionStatus();
this.carSearchView = (CarSearchView) applicationContext
.getBean("carSearchView");
try {
List<CarModel> carList = carMgmt.selectAllCars();
// this.carSearchView.setResultList(carList);
this.carSearchView.setLabelList(carList);
this.carSearchView.createTextFieldList();
this.carSearchView.createLabelFieldList();
transactionManager.commit(transactionStatus);
} catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
transactionManager.rollback(transactionStatus);
throw e;
}
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void setDefaultTransactionDefinition() {
this.defaultTransactionDefinition = new DefaultTransactionDefinition();
}
public void setApplicationContext() {
applicationContext = new ClassPathXmlApplicationContext(
"spring-config.xml");
}
public void setTransactionManager(
PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void setTransactionStatus() {
this.transactionStatus = transactionManager.getTransaction(defaultTransactionDefinition);
}
I've finally found a solution. I changed the TransactionDefinition object in the controller to DefaultTransactionDefinition object
private DefaultTransactionDefinition defaultTransactionDefinition;
former it was
private TransactionDefinition defaultTransactionDefinition;
but the TransactionDefinition doesn't provide any setting methods. I was wondering, because in the documentation I found such methods to set the isolationlevel, but this methods are just provided by the DefaultTransactionDefinition. After I've found this failure i added the the following to lines of codes and it finally works
defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
defaultTransactionDefinition.setIsolationLevel(DefaultTransactionDefinition.ISOLATION_REPEATABLE_READ);
Thx, for all your advises. If someone knows a really good tutorial for MyBatis + Spring and the transaction manager please post a link :D
You can apply transaction as shown below in mapper interface(though it is recommended to apply transaction annotation for class, however in mybatis, transaction defined in interface will be applied to proxy class)
import java.util.List;
import de.hrw.model.CarModel;
#Transactional
public interface ICarMgmt {
#Transactional(isolation = Isolation.SERIALIZABLE)
public CarModel selectCarById(final int carId);
public List<CarModel> selectAllCars();
}

how to open session for query execution in Hibernate

I am using struts2-spring-hibernate in my project.
I am handling the DB connection through spring, so I dont need of hibernate.cfg.xml
I need to execute my query and I need the result
I am successfully getting the result, by using these methods
Mannually open and close the session:
1. Session session = sessionFactory.openSession();
2. Session newSession = HibernateUtil.getSessionFactory().openSession();
Not handling the session mannually
1. getHibernateTemplate().find();
2. getSession().createSQLQuery();
I dont know which method is best one, please suggest me, which one is best for session
when the session will open and close by getHibernateTemplate() and getSession().
I will show the way I use these frameworks together. I avoid the need of HibernateTemplate, I reckon this class is too limited, I prefer to use the Session directly.
Once you have Spring in your project, it should inject the Hibernate SessionFactory in your Daos, so you can handle the Session. First of all, you need to configure the SessionFactory in your applicationContext.xml:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
Now you can inject the SessionFactory with the #Autowired annotation:
#Repository
public class HibernateProductDao implements ProductDao {
private final SessionFactory factory;
#Autowired
public HibernateProductDao(final SessionFactory factory) {
this.factory = factory;
}
public List<Product> findAll() {
return factory.getCurrentSession().createCriteria(Product.class).list();
}
public void add(final Product product) {
factory.getCurrentSession().save(product);
}
}
There are here some important thing, you should use the method getCurrentSession() because this way you allow Spring to control the Session lifecycle. If you use getSession() instead, it become your responsability, for instance, close the Session.
Now, let's configure Struts 2. In your web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
You need the file struts.xml too, to say that Spring will fabricate the objects:
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.objectFactory" value="spring" />
</struts>
Finally, you can inject the Dao in your action:
public class ProductAction {
private ProductDao dao;
#Autowired
public ProductAction(ProductDao dao) {
this.dao = dao;
}
}
Of course, since you're using Spring annotations, you need to scan the packages with component-scan.
That's the best way I found to integrate this frameworks, I hope it's helpful.

Upgrading to spring-3.1 seems to break my CustomWebArgumentResolver

I'm trying to upgrade a spring MVC app from 3.0.6 to 3.1.2 and some controllers that used to work don't seem to work anymore. I've read the spring docs, but I'm confused about what's compatible with what.
We've got a CustomWebArgumentResolver that looks for any request parameter named "asOf" and coverts its value to a date. We call it, unimaginatively, the "AsOfDateConverter." When upgrading to spring-3.1.2, I took advantage of the new namespace functionality and added this to my applicationContext:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:argument-resolvers>
<bean id="customWebArgumentResolver" class="my.converters.CustomWebArgumentResolver">
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
The CustomWebArgumentResolver is straightforward:
public class CustomWebArgumentResolver implements WebArgumentResolver {
private AsOfDateConverter asOfDateConverter;
#Override
public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception {
if (isAsOfDateParameter(methodParameter)) {
return asOfDateConverter.convert(webRequest.getParameter("asOf"));
}
return UNRESOLVED;
}
Then an example controller might look something like this:
#Controller
#Secured({BaseController.ROLE_LOGGED_IN})
#org.springframework.transaction.annotation.Transactional
public class DashboardController extends BaseController {
public static final String URL = "/dashboard";
#RequestMapping(value=URL, method=RequestMethod.GET)
public ModelAndView get(#RequestParam(required=false) String requestedMeterType, #AsOf Date asOf) {
debug(log, "Rendering dashboard asOf %s", asOf);
etc etc
The "asOf" parameter is coming in null, and I'm sure I'm missing something obvious. If anyone out there neck deep in the latest MVC 3.1 stuff could point me in the right direction I'd be grateful.
Thanks!
Tom
EDIT:
The AsOf annotation:
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.RUNTIME)
public #interface AsOf {
}
More of my applicationContext:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:argument-resolvers>
<bean class="[blah].AsOfDateHandlerMethodArgumentResolver">
<property name="asOfDateConverter">
<bean class="[blah].AsOfDateConverter"/>
</property>
</bean>
</mvc:argument-resolvers>
</mvc:annotation-driven>
<!-- Added to re-support #Controller annotation scanning after upgrading to spring-3.1. -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="[blah].converters.CustomerConverter"/>
<bean class="[blah].converters.AccountConverter"/>
<bean class="[blah].converters.DateConverter"/>
<bean class="[blah].converters.CustomerCommunicationInstanceConverter"/>
<bean class="[blah].converters.MeterTypeConverter"/>
<bean class="[blah].converters.AreaAmountConverter" p:precision="0"/>
<bean class="[blah].converters.LengthAmountConverter" p:precision="1"/>
</set>
</property>
</bean>
The API has changed with Spring 3.1 - the interface to implement to resolve a controller argument is HandlerMethodArgumentResolver. You can continue to use CustomWebArgumentResolver, by adapting it to a HandlerMethodArgumentResolver
However changing the code to use HandlerMethodArgumentResolver also will be easy:
public class CustomWebArgumentResolver implements HandlerMethodArgumentResolver {
private AsOfDateConverter asOfDateConverter;
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
if (isAsOfDateParameter(methodParameter)) {
return asOfDateConverter.convert(webRequest.getParameter("asOf"));
}
return UNRESOLVED;
}
#Override
public boolean supportsParameter(MethodParameter parameter) {
return (methodParameter.getParameterAnnotation(AsOf.class)!=null)
}
Edit
After looking through your comments, I think I have an idea about what could be going wrong. Can you please check your #AsOf annotation, you probably have not declared the retention of Runtime, which could be the reason why the the WebArgumentResolver is not taking effect:
#Retention(RetentionPolicy.RUNTIME)
public #interface AsOf {
}
Anyway here is a gist with a full working test along the same lines:
https://gist.github.com/3703430

Passing Dynamic arguments using setter injection in Springs

Iam trying to pass dynamic argument values i.e username from request using spring ioc.But iam unable to seen username value in userdaoimp.
UserDAOImpl.java
public class UserDAOImpl implements UserDAO {
private DataSource dataSource;
private JdbcTemplate jdbctemplate;
private String username;
public void setUsername(String username) {
this.username = username;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
this.jdbctemplate =new JdbcTemplate (dataSource);
}
public int getUserListSize() {
System.out.println("UserDAOImpl::getUserListSize()"+username);
int count=this.jdbctemplate.queryForInt("SELECT COUNT(*) FROM USER_INFO");
return count;
}
}
epis.dao.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="userdao" class="com.epis.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="username"/>
</bean>
</beans>
UserService
In the XML you can assing properties only to the surrounding bean.
so
will not work, because UserService does not have a filed username and therefor the spring should not start.
You can write it in two different ways:
<bean id="userdao" class="com.epis.dao.UserDAO">
<property name="dataSource" ref="dataSource" />
<property name="username" value="aaa"/>
</bean>
<bean ... class="...UserService">
<property name="userdao" ref="userdao" />
<bean>
or
<bean ... class="...UserService">
<property name="userdao">
<bean class="com.epis.dao.UserDAO">
<property name="dataSource" ref="dataSource" />
<property name="username" value="aaa"/>
</bean>
</property>
<bean>
But you can not mix both styles for one property.
Form the comment
Actually my requirement is the username value is getting based on other business logic in UserService.This username will be forwarded into userdao constructor.How can I forward that value to userdao.
This is not possible or at least not without a lot of handwritten magic. The reason is simple: The objects descriped in the XML file are created when the application starts, and the values are set while starting.
But in general I think you can achieve your aim with some scoped beans. But I have highly doubt that scoped beans can be used for the database connection.
I highly recommend to ask a new question hat focus on the dynamic requirement with the explanation you gave in the comment of this answer. (but without the bugy xml example) )
#See Spring Reference Chapter 3.5 Bean scopes
If you make username a property of the UserDaoImpl then it not longer be thread-safe, i.e. what would happen if two calls come in at the same time? The second call will overwrite the setting of the username property possibly before the getUserListSize() has been called the first time. You'd have to create a new UserDao object for every single call, which is not very efficient.
The easiest way is to use a parameter for your methods:
So in UserDao:
public int getUserListSize(String username);
In UserDaoImpl:
public int getUserListSize(String username) {
logger.debug("UserDAOImpl::getUserListSize():"+username);
int count = this.jdbctemplate.queryForInt(
"SELECT COUNT(*) FROM USER_INFO WHERE USER_NAME = ?", username);
return count;
}
And in UserService:
public int getUserListSize() {
String username = someBusinessLogicObtainsUsername();
return this.userDao.getUserListSize(username);
}

#Transactional on aspect advice possible?

Can I apply the #Transactional tag to an aspect advice? I'm trying to wrap all calls to the service layer (com.mycompany.app.myapp.service.*) in a transaction using aspects. My aspect is properly intercepting the calls to the service layer, but I can't figure out how to start a transaction. I thought I could apply the #Transactional tag and because I've got the tag, it'd pick it up and begin the transaction. What am I missing?
XML configuration:
<bean id="systemArchitectureAspect" class="com.mycompany.app.myapp.aspect.SystemArchitecture"/>
<bean id="transactionAspect" class="com.mycompany.app.myapp.aspect.MyAspect"/>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="AtomikosTransactionManager" />
<property name="userTransaction" ref="AtomikosUserTransaction" />
</bean>
<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
</bean>
<bean id="AtomikosUserTransaction"
class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="10" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
Aspect w/pointcuts:
package com.mycompany.app.myapp.aspect;
#Aspect
public class SystemArchitecture {
#Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
public void inServiceLayer() {};
#Pointcut( "execution(* com.mycompany.data..*.*(..))" )
public void inDataAccessLayer() {};
}
The advice I'm trying to apply to my pointcuts:
package com.mycompany.app.myapp.aspect;
#Aspect
public class TransactionAspect {
#Transactional
#Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
{
return pjp.proceed();
}
}
Below I have an example that shows how you can use #Transactional together with your inServiceLayer() Pointcut. I have chosen to separate the normal flow from the exception flow. That is why I do not use the #Around advice.
#Aspect
public class TransactionAspect {
private TransactionService transactionService = new TransactionServiceNull();
#Pointcut( "execution(* com.mycompany.app.myapp.service..*.*(..))" )
public void inServiceLayer() {};
#Pointcut("execution(#org.springframework.transaction.annotation
.Transactional * *(..))")
public void transactionalMethod() {}
#Before("transactionalMethod() && inServiceLayer()")
public void beforeTransactionalMethod(JoinPoint joinPoint) {
transactionService.beginTransaction();
}
#AfterReturning("transactionalMethod() && inServiceLayer()")
public void afterTransactionalMethod(JoinPoint joinPoint) {
transactionService.commit();
}
#AfterThrowing(pointcut = "transactionalMethod() && inServiceLayer()",
throwing = "e")
public void afterThrowingFromTransactionalMethod(JoinPoint joinPoint,
RuntimeException e) {
transactionService.rollback();
}
public void setTransactionService(
final TransactionService transactionService) {
this.transactionService = transactionService;
}
}
After a quick look on your code I have to ask why you have annotated your Pointcut with #Transactional? You should only mark your business methods that you want to be executed in a transaction with that.
I hope this helps!
As #Espen said you should apply #Transactionalon your business methods directly as the Annotation itself causes Spring to create an Aspect that applies transactions to your method. So there is no need to create an aspect manually.
However, if you want to apply transactions to all you service methods and whatever else you selected with those pointcuts you should do use the xml configuration to create the transactions. Look for declarative transaction management in the documentation
Also I don't think you can apply #Transactional to an Advice. At least it is not working for me.
Spring transaction annotation at run time creates a proxy object. So if you apply transactional annotation on an advice which is advicing the service then the transaction will be for the advice and not for the service since the advice works on a proxy object of the service and your transactional annotation would work on a proxy object of the advice and not the main method of the advice. Ideally you should not be having an advice which is an extension of the functionality of the service. This defeats the purpose of the proxy pattern.
robgmills
#Transactional
#Around( "com.mycompany.app.myapp.aspect.SystemArchitecture.inServiceLayer()" )
public Object interceptServiceLayer( ProceedingJoinPoint pjp ) throws Throwable
{
return pjp.proceed();
}
You can use above Around advice but need to do couple of small changes.
Add (propagation = Propagation.REQUIRES_NEW) to #Transactional
in above.
Add #Transactional annotation to the service method for which you have added the pointcut inServiceLayer().

Resources