#Transactional with xml-defined bean not working. (OSGi) - java

I can't get #Transactional annotation to work with xml-defined bean. I don't know if xml definition has anything to do with it. Maybe it's the issue with OSGi.
<bean id="myDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="target" ref="myDao_t"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_MANDATORY,
timeout_60,
-Exception
</prop>
</props>
</property>
</bean>
When I specify a proxy with xml like above it works.
I have <tx:annotation-driven transaction-manager="txManager" /> specified in the same bundle-context.xml where the bean definition is.
MyDao is just a simple class implementing interface with one method.
There is no exception, it just doesn't create proxy for myDao.
What might be missing?
<bean id="myPlanner" class="com.something.planner.MyPlanner">
<property name="myDao" ref="myDao" />
</bean>

Try this:
The class of the bean myDao should be MyDao (the type of the DAO instead of TransactionProxyFactoryBean).
Put the annotation #Transactional on each public method in MyDao.java.
Spring should then automatically create a proxy for you. The approach in your question looks like "I try to create and configure the proxy factory myself".
While there surely is away to do that, I don't know exactly how you would do that. Instead, I rely on <tx:annotation-driven> and the #Transactional annotation.
EDIT You're using Spring 2.5.6A.
I just checked and #Transactional was added with Spring 1.2. But I'm not sure when <tx:annotation-driven> was added. The related EnableTransactionManagement was added with 3.1.
But the XML element is in this schema: http://www.springframework.org/schema/tx/spring-tx-2.5.xsd so it should be available in 2.5.
Maybe you're missing the necessary AOP libraries (cglib) on the classpath?

Related

Configure a Repository on Spring via XML

I have been surfing on Internet for hours trying to find a good example to configure a Spring's repository by using the XML instead of annotations (#Repository).
I found some good stuff (Hibernate 3):
<!-- Hibernate interceptor to manage the session outside any transaction scope. -->
<bean id="hibernateInterceptor"
class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- The configuration DAO -->
<bean id="configurationDAO"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="configurationDAOTarget"/>
<property name="proxyInterfaces" value="org.itracker.persistence.dao.ConfigurationDAO"/>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>
<bean id="configurationDAOTarget"
class="org.itracker.persistence.dao.ConfigurationDAOImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
But it seems that Hibernate 4 does not support HibernateInterceptor any longer.
Have any of you experience with this issue? A good solution? There's no other option rather than using the annotation?
Thanks in advance.
All #Repository does is meta-annotate a #Component and let the org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor create an AOP proxy which does exception translation. At that level it's all Hibernate independent. The different implementations then understand their own exceptions and translate to the common Spring DataAccessException hierarchy.
In terms of doing it with XML, you'd have to somehow apply that proxy to the DAO beans you care about. Take a look at the reference manual for that, but it's going to be painful and not win you much.
For the sake of completeness, you can change the annotation from #Repository to something else, but as I read your question, you don't want to use annotations at all.

TransactionRequiredException: no transaction is in progress with Spring Data JPA

I looked around for similar problems but couldn't find a solution for this:
I have a Spring Data JPA application that whenever I try to do a trasaction I get javax.persistence.TransactionRequiredException: no transaction is in progress.
I believe it has something to do with the Transaction Manager or Entity Manager Factory, but can't put my finger on it.
The context files are here (latest checked in are here), but here is the part that matters:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceMySQL" />
<property name="persistenceUnitName" value="spring-jpa" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
<property name="database" value="MYSQL" />
</bean>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSourceMySQL"/>
</bean>
<bean id="dataSourceMySQL" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/dbname"/>
<property name="username" value="user"/>
<property name="password" value="pass"/>
</bean>
<jpa:repositories base-package="com.simplecash.dal.repository" />
A sample Repository is here and then created a Repository Factory here, which I'm not sure if I need...
Then use it here (line 34).
public void populateWithTestData() {
Bank bank = new Bank();
bank.setName("ContentName");
bank.setCode("ContentCode");
RepositoryFactory.getEntityManager().getTransaction().begin();
BankRepository bankRepository = RepositoryFactory.getRepository(BankRepository.class);
bankRepository.save(bank);
bankRepository.flush();
RepositoryFactory.getEntityManager().getTransaction().commit();
}
A couple of things are wrong above, but I I've tried fixing it and can't:
Begin and Commit transactions are explicit.
bankRepository should be #Autowired, but when I do that I get null. However, in this testcase it is Autowired and works.
Has anyone faced a similar problem and knows what's going on?
Thanks a ton for taking the time to read this. Hope the answer to this question will help other folks.
Both answer provided here offer good points (using injection to get the proxied beans and using transaction-annotations), however, I'm pretty sure that for the annotation-driven transactions to work (#Transactional), you need to add the following to your xml-configuration:
<tx:annotation-driven transaction-manager="transactionManager"/>
Also make sure to add the tx-namespace in your beans-tag:
<beans
<!-- SNIP, other namespaces -->
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
<!-- SNIP, other locations -->
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
I think that in your setup the Transactions are managed by JTA, so you can't explicitly start/stop them (i.e. em.getTransaction().begin() will not work). Try telling Spring that you want a certain method to be part of a (JTA managed) transaction via annotation , like:
#Transactional
public void populateWithTestData() {
//...
}
Begin and Commit transactions are explicit.
What Spring does with your repository beans ( e.g. BankRepository ), it creates a proxy around it, and then it is ready to be injected into other collaborators, which in your case is DatabaseManagerDAO. However if you create the object yourself like you do:
BankRepository bankRepository = RepositoryFactory.getRepository(BankRepository.class);
Instead of expected Spring's proxy ( that already does transaction management for you ), you are getting a simple object that is not aware of anything beyond it is immediate declaration.
What you need to do instead is to trust Spring to do the plumbing for you and just inject a bankRepository bean into a DatabaseManagerDAO (although I don't really think you need both DAO and Repository, since those terms really mean the same thing :)
Repository Factory here, which I'm not sure if I need...
No need for another abstraction. Just inject it as a bean to whatever component needs it.
bankRepository should be #Autowired, but when I do that I get null. However, in this testcase it is Autowired and works.
In a case where it works you run your test with AbstractTransactionalJUnit4SpringContextTests, which knows about 'bankRepository' bean, hence autowires it. In your DatabaseManagerDAO, I see neither autowiring nor a setter for the bankRepository, in fact you create it manually from the factory.
EDIT to answer comments
What jpa:repositories in your XML config really does => it scans the package and creates Spring beans for each component that is either annotated as #Repository or implements a Repository interface.
With that in mind, what you should do in order to use a BankRepository repository in your DatabaseManagerDAO is to inject it. You can do it via "autowiring":
#Service
public class DatabaseManagerDAO {
#Autowired
BankRepository bankRepository;
...
}
instead of manually creating it trough your factory.
Again, DatabaseManagerDAO in your case is probably a service ( #Service ), and not a DAO, but I'll leave it up to you to decide on that.
Notice that a DatabaseManagerDAO should also be loaded by Spring in order for the autowiring to work, so make sure it has one of the Spring annotations ( #Service / #Component ) when you package scan it ( e.g. <context:component-scan base-package="org.example"/> ).
I had a similar issue when combining spring-batch and spring-jpa. In my batch XML, I had this line:
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
which caused an error since JPA needs a PlatformTransactionManager.

Spring not injecting DAOs into JSF managed beans with abstract superclass

I have a JSF 2.0 application and I am integrating Spring so I can make use of the hibernateTemplate. I already consulted the Spring documentation on JSF integration and have taken steps to set it up. All of my bean classes extend an abstract super class called SuperBean. SuperBean is the desired point of injection, saving me from having to declare all of my beans in Spring. I was hoping to just declare it as abstract="true" and any subclass bean extending the SuperBean class would have the dao injected. At runtime it is null.
<bean id="serviceTemplate" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="*"/>
</props>
</property>
</bean>
<bean id="daoServiceTarget" class="com.example.service.DaoService">
<property name="mainDAO" ref="mainDAO"/>
</bean>
<bean id="daoService" parent="serviceTemplate">
<property name="target" ref="daoServiceTarget"/>
</bean>
<bean id="superBean" class="com.example.beans.SuperBean" abstract="true">
<property name="daoService" ref="daoService"/>
</bean>
Am I able to simply declare this superclass SuperBean and expect Spring to inject the dao? I don't want to have to declare every bean class in spring.
I suppose the alternative option (from a performance perspective) would be to not use Spring beans but declare the DAO's as #applicationScoped and inject them into the SuperBean class using JEE's CDI. Would this be better performance-wise?
In the example above it looks serviceTemplate is providing an example of what you want. Note the parent="serviceTemplate". You need to do something similar to those who inherit from superbean. There are other options but since you have working code in the serviceTemplate that might be the best place to start. Then read here for more details:

Hibernate transaction manager configurations in Spring

In my project I use Hibernate with programmatic transaction demarcation.
Every time in my Service methods i write something similar to this.
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
.. perform operation here
session.getTransaction().commit();
Now I'm going to refactor my code with declarative transaction management. What I got now ...
<context:component-scan base-package="package.*"/>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="mySessionFactory"/>
</property>
</bean>
Service class:
#Service
public class TransactionalService {
#Autowired
private SessionFactory factory;
#Transactional
public User performSimpleOperation() {
return (User)factory.getCurrentSession().load(User.class, 1L);
}
}
And simple test -
#Test
public void useDeclarativeDem() {
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext("spring-config.xml");
TransactionalService b = (TransactionalService)ctx.getBean("transactionalService");
User op = b.performSimpleOperation();
op.getEmail();
When I try to get user email outside of Transactional method, I got lazy initialization exception, email is my case is a simple string. Hibernate does not even perform sql query, until I call any getters on my POJO.
what I am doing wrong here?
Is this approach valid?
Can you suggest any opensources project which works on spring/hibernate with annotation based configuration?
Update
For some reason if I replace getCurrentSession with openSession this code works fine. Can someone explain it please?
Ok, finally i realized what was the problem. In code above i used load instead of get. Session.load did not actually hit the databased. That's the reason why i get lazy-initialization exception outside of #Transactional method
If i use openSession instead of getCurrentSession, session is opened outside of scope spring container. As result session was not close and it allow me to read object properties outside of #Transactional method
The reason Hibernate does not perform any SQL queries until you call the getters is because I believe the FetchType is set to LAZY. To fix this problem you will need to change the FetchType to EAGER in your POJO:
#Entity
#Table(name = "user")
public class User {
/*Other data members*/
#Basic(fetch = FetchType.EAGER)
private String email;
}
I personally never had to specify Basic types to have an EAGER FetchType so I'm not entirely sure why your configuration requires this. If its only in your tests it could be due to the way you have your JUnit tests configured. It should have something like this on the class declaration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"/test-app-config.xml"})
#Transactional
public class UserServiceTest {
}
As for a good resource I always find SpringByExample to be helpful.
EDIT
So I'm not entirely sure what is wrong with your configuration. It does differ from the way I have mine set up so here is my typical configuration in hopes that it helps. The hibernate.transaction.factory_class could be a key property you are missing. I also use the AnnotationSessionFactoryBean:
<!-- DataSource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost/dbname"
p:username="root"
p:password="password"/>
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
p:dataSource-ref="dataSource">
<property name="packagesToScan" value="com.beans"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop>
</props>
</property>
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
From Hibernate documentation https://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html/ch11.html#objectstate-loading:
Be aware that load() will throw an unrecoverable exception if there is no matching database row. If the class is mapped with a proxy, load() just returns an uninitialized proxy and does not actually hit the database until you invoke a method of the proxy. This is useful if you wish to create an association to an object without actually loading it from the database. It also allows multiple instances to be loaded as a batch if batch-size is defined for the class mapping.
From above documentation in your case bean is mapped with spring proxy so load just returns. Hence you need to use get() instead of load() which always hits the database.

Spring transactions & hibernate: lazy initialization

From what I've read so far I had the understanding that using transactions would be the solution to hibernate's lazy loading problems. The session would be available during the whole transaction in the service layer without further adue.
So maybe I misconfigured my transaction management? I'm actually a newb when it comes to spring and hibernate, but maybe you guys could help me out.
My configuration:
<bean class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
id="sessionFactory">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<!-- Hibernate Template bean that will be assigned to DAOs. -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<!--
Transaction manager for a single Hibernate SessionFactory (alternative
to JTA)
-->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
My DAO implementation would simply have a #Repository annotation and a Hibernate-template bean injected using autowiring.
A typical header of a service Implementation would be:
#Service
#Transactional(readOnly=true)
public class LeerlingServiceImpl implements LeerlingService {
#Autowired
LeerlingDAO leerlingDAO;
#Autowired
LeerplanDAO leerplanDAO;
With a #Service(readOnly=false) annotation if anything is actually saved/updated in that particular method.
Do I need to configure something else to make sure that I can load the right associations in my Service, or is this normally handled by transactions?
Right now I am just a bit confused of what I should actually do, so please help me:)
Lazy-loading problems and transactions are not really related one to other. But that's another story :)
You've done all well, apart from the access to session in your beans. No sure how you are going to do this. The standard solution (in spring 2.x, not sure about 3.x, haven't looked yet) is to use HibernateDaoSupport as base class for classes were you are going to have an access to session. But personally that looks a little dodgy to me, because adds dependency on Spring-specific classes. Better way is to inject session into your beans. To do this you need to declare your session bean with definition similar to that one:
<bean name="hibernateSession" class="org.springframework.orm.hibernate3.SessionFactoryUtils" factory-method="getSession"
scope="prototype">
<constructor-arg index="0" ref="hibernateSessionFactory"/>
<constructor-arg index="1" value="false"/>
<aop:scoped-proxy/>
</bean>
and then just use it.
Here are details:
http://stas-blogspot.blogspot.com/2009/10/hibernate-spring-in-standalone.html
I think my understanding of Spring was just bad till now; there was indeed no real management for our session management. Basically what now happened was: you could get data from the DAO, but right after you received it you couldn't even get lazy collections loaded because the session was closed.
Now we are using the hibernate interceptor, which attaches the session to the thread at the beginning of each request and closes it when it ends. This is not always the most ideal solution, but for a school project I wouldn't bother too much.
The other solution seems to be: add AOP in a way that #around is used that the session is only available during a service method call. I think this is the best solution, though, I'm not going to dig that deeply right now for this project. The good thing is that I know it exists.
This article also helped me a lot: http://www.jroller.com/kbaum/entry/orm_lazy_initialization_with_dao
To those interested: here is what I had to add: In Spring MVC 3.0 there is a new feature called mvc:intereceptors which made me type less xml.
<!-- WEB-INF/applicationContext.xml or your own XML config file -->
<mvc:interceptors>
<bean
class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory">
<ref local="sessionFactory" />
</property>
</bean>
</mvc:interceptors>

Categories