DataSourceTransactionManager and test for active transaction - spring

I have a simple app that use org.springframework.jdbc.datasource.DataSourceTransactionManager to manage the transactions.
My spring config is as follow:
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
I have annotated the method with #Transactional and print out the TransactionSynchronizationManager.isActualTransactionActive()
But the out put is false. What have i done wrong ?
Edit: i forgot to say that i test that with SpringJUnit4ClassRunner.class. I included the TransactionalTestExecutionListener.class and this will not work. Now it worked after i extend the class with AbstractTransactionalJUnit4SpringContextTests

I think you forgot to add the below to your cfg file. this is required when you are using annotations. Have you added this?
<tx:annotation-driven/>
Here is the namespace
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

Did you use the required annotations on your test class?
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/spring-....xml")
#TestExecutionListeners({TransactionalTestExecutionListener.class, DependencyInjectionTestExecutionListener.class})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional(readOnly = false)
public class MyTest {
...
}
I'm not sure whether the last two are really necessary, I want my test cases to have an active transaction that's why I need those. The first three should be enough in order to get transactional proxies for your annotated beans.

I had the same problem, you should use this instead:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

Related

#Autowired entityManagerFactory is null

My app can't autowire entityManagerFactory.
My applicationContext.xml:
<tx:annotation-driven/>
<context:component-scan base-package="top.level.package" />
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocation">
<value>classpath:jpa-persistence.xml</value>
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
My java class:
#Component
public class Engine {
#Autowired
#Qualifier("entityManagerFactory")
private EntityManagerFactory entityManagerFactory;
......
}
Question:
Why entityManagerFactory is null?
For spring to do autowring using annotations you have to tell spring that. In your xml configuration (assuming you don't already have context:component-scan element) add a context:annotation-config. This will instruct the spring application context to scan for annotations (like #Autowired, #Inject, #Resource etc.) to do autowiring.
Also make sure that the class you want the EntityManagerFactory to be injected into (the Engine class) is a spring managed bean. Spring will only inject references into spring managed beans.
Have you tried with this ?
private EntityManagerFactory entityManagerFactory;
#Autowired
#PersistenceUnit(unitName = "myUnitName")
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
I had the same error some time ago, and I found this a solution.
If you craeate your Engine with new Engine() (as stated in one of your comments), it's not managed by Spring. #Component has no effect then and dependencies won't be injected. You need to inject your engine.

Is JTA manager necessary to use transaction features in hibernate 4

I'm following the tutorial here:
http://www.javacodegeeks.com/2013/05/hibernate-4-with-spring.html
to enable the "#Transactional annotation" in my Java web application but failed to make it run properly. Please advise if the JTA manager is really required, and why?
Please note that my webapp is based on Spring 3 + Hibernate 4 + Tomcat 7.
Background and my doubts:
My current web application uses my own custom class (implements HandlerInterceptor) to enable one-hibernatesession-per-request basis. Now I want to improve my application's maintainability by using the "#Transactional annotation" instead since that could save many lines of code.
According to my understanding, the #Transactional basically relies on the AOP concept to ensure the session (Hibernate session) is ready for use in the annotated method. This seems nothing to do with the JTA. But I wonder why can't I make it work on my webapp in Tomcat 7 (without JTA-provider).
After few searches on google, it looks like the JTA is required. This confuses me since this seems to be a very basic functionality that shouldn't have the complicated JTA-provider as a requirement.
Here is the error I got:
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:988)
...
This is the code I use for testing:
....
#Autowired
org.hibernate.SessionFactory sessionFactory;
#Transactional
#RequestMapping(method = RequestMethod.GET)
protected String home() {
Session session = sessionFactory.getCurrentSession(); // I expected the session is good to use now
Province p = (Province) session.get(Province.class, 1L); // This causes no session found error :(
return "home";
}
The spring XML:
....
<tx:annotation-driven/>
<context:component-scan base-package="..."/>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/..."/>
<property name="lookupOnStartup" value="true"/>
<property name="proxyInterface" value="javax.sql.DataSource"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
....
Thank you !
Just a speculation:
Your controller is defined in some kind of dispatcher-servlet.xml therefore seperates from the applicationContext in which < tx:annotation-driven/> is defined. The compoment you want to enhance with #Transactional need to be within the same context with < tx:annotation-driven> if I'm not mistaken. So the #Transactional does not work.
That was my silly mistake. The Spring uses CGLIB to proxy methods with #Transactional annotated and it seems like CBLIB can't enhance protected method.
protected String home() {
Changing this to
public String home() {
fixed the problem.

Many classes/interfaces with general project template

I am looking for a general project template to build a web applications with the following technologies: JSF2, Spring3 and Hibernate4
I found an article that proposes a template but I hesitated beacause for each table in my database I need 5 classes/interfaces:
2 interfaces (dao + service)
2 classes for implementations
1 bean
so is it normal? can someone help with a better architecture?
I would build the architecture on top of the Spring Data JPA module. That would leave you with one class for the entity and one interface (under normal circumstances) for the repository.
For more information take a look at the Spring docs.
Shortened Example:
Spring config:
<!-- Directory to scan for repository classes -->
<jpa:repositories
base-package="x.y.z.repositories" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database" value="HSQL" />
</bean>
</property>
</bean>
Entity:
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#NotNull
private String name;
}
Repository:
public interface ProductRepository extends CrudRepository<Product, Long> {
public List<Product> findByName(String name);
}
In order to use the repository, you simply need to inject it:
#Autowired
private ProductRepository productRepository;
If you include CGLib as a dependency, you can get rid of the interfaces. You won't need them unless you have different implementations of your services from the beginning. Only introduce them if they're really necessary (1:1 Service:ServiceImpl is an anti pattern if you ask me).
Hibernates/JPAs EntityManager is already a generic CRUD DAO, so you don't have to create a DAO for every entity. Introduce them as soon as they are necessary and use EntityManager within your service until then.
Disclaimer: This is a lean approach to Java EE, very close to what Adam Bien recommends in his book Java EE Patterns. We adapted this for spring and it works fine so far.
Great question by the way, java folks often forget to ask themselfs "do we really need this?".

org.hibernate.HibernateException: No Session found for current thread

I'm getting the above exception with Spring3 and Hibernte4
The following is my bean xml file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
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-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<context:annotation-config/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/GHS"/>
<property name="username" value="root"/>
<property name="password" value="newpwd"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.example.ghs.model.timetable</value>
</list>
</property>
</bean>
<bean id="baseDAO"
class="com.example.ghs.dao.BaseDAOImpl"/>
</beans>
My BaseDAO class looks like this
public class BaseDAOImpl implements BaseDAO{
private SessionFactory sessionFactory;
#Autowired
public BaseDAOImpl(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
#Override
public Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
}
The following code throws the exception in the title
public class Main {
public static void main(String[] args){
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("dao-beans.xml");
BaseDAO bd = (BaseDAO) context.getBean("baseDAO");
bd.getCurrentSession();
}
}
Does anyone have an idea about how to solve this problem?
getCurrentSession() only makes sense inside a scope of transaction.
You need to declare an appropriate transaction manager, demarcate boundaries of transaction and perform data access inside it. For example, as follows:
<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
.
PlatformTransactionManager ptm = context.getBean(PlatformTransactionManager.class);
TransactionTemplate tx = new TransactionTemplate(ptm);
tx.execute(new TransactionCallbackWithoutResult() {
public void doInTransactionWithoutResult(TransactionStatus status) {
// Perform data access here
}
});
See also:
10. Transaction Management
13.3 Hibernate
I came across same problem and got solved as below
Added #Transactional on daoImpl class
Added trnsaction manager in configuration file:
<tx:annotation-driven/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
I'll just add something that took me some time to debug : don't forget that a #Transactional annotation will only work on "public" methods.
I put some #Transactional on "protected" ones and got this error.
Hope it helps :)
http://docs.spring.io/spring/docs/3.1.0.M2/spring-framework-reference/html/transaction.html
Method visibility and #Transactional
When using proxies, you should apply the #Transactional annotation
only to methods with public visibility. If you do annotate protected,
private or package-visible methods with the #Transactional annotation,
no error is raised, but the annotated method does not exhibit the
configured transactional settings. Consider the use of AspectJ (see
below) if you need to annotate non-public methods.
Which package u have put the BaseDAOImpl class in.. I think It requires a package name similar to the one u have used in the application context xml and it requires a relevant annotation too.

What's the link between #Transactional and cascading?

There seems to be a link between the presence of the #Transactional annotation on a Spring JUnit test and cascading when persisting/merging a JPA2 entity.
I don't have the configuration at hand for the moment, but maybe this rings a bell to somebody in here ?
Assume a simple case of JPA entities on three levels: Entity A references an entity of class B and that instance of class B references an instance of class C.
A -> B -> C
Class A does cascading ALL to B. And B does cascading ALL to C. And Class C has an event listener method annotated with #PrePersist and #PreUpdate. It logs a message to prove the cascading made it to there.
Now, modify entity C in some way and ask the entity manager to merge or persist the instance of A. Logically entity C will eventually be persisted or merged also. Because of cascading has been set to ALL from class A to B to C.
When the Spring unit test is not annotated with #Transactional, the log message from the event listener method of class C prints its message. OK.
But when it is annotated with #Transactional, no message at all is printed. And indeed, nothing has been committed to the database for class C. Only for class A. Hence, I conclude the cascading didn't make it from A to C.
Removing the annotation fixes the problem.
Anybody any clue? :-) Logically I would think transactions and cascading are two totally separated matters.
A typical test case configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/test-beans.xml")
#TransactionConfiguration
#Transactional
public class MyUnitTest {
...
#Test
public void testSomething() {}
...
}
An extract of the Spring xml configuration file - nothing fancy there I think ...
<context:annotation-config />
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="com.foo.bar" />
<bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="/META-INF/persistence.xml"/>
<property name="persistenceUnitName" value="bar" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
Extract from persistence.xml
<persistence-unit name="bar" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/bar" />
<property name="hibernate.connection.username" value="bar" />
<property name="hibernate.connection.password" value="pwd" />
<property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="dialect" value="org.hibernate.dialect.MySQLDialect" />
</properties>
</persistence-unit>
Libraries
Spring 3.0.6 ORM/CONTEXT/TEST
Hibernate 3.6.7.Final
JUnit 4.9
JPA2
Found it ! An improper entity manager usage was turning bad when transactions were enabled. It wasn't related to the persistence but was done right before it. Causing the persistence to fail in some way.
I implemented a Query result iterator for which an EntityManager was required. I thought I could create it from the EntityManagerFactory of the jpaTemplate.
final EntityManager em = jpaTemplate.getEntityManagerFactory().createEntityManager();
return new QueryIterator<T>(em.createQuery("FROM Foo"));
Obviously not. It seems the EntityManager has to be obtained in a different way. As described underneath.
jpaTemplate.execute(new JpaCallback() {
#Override
public Object doInJpa(final EntityManager em) throws PersistenceException {
return new QueryIterator<T>(em.createQuery("FROM Foo"));
}
});
Now it all works ok. As it is supposed to be, regardless of transactions being present or not. :-)

Resources