Reputation: 111
Have a simple Spring-Hibernate application with the following config:
App context:
<context:component-scan base-package="org.hibtests" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>org.hibtests.domain.Person</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
</bean>
<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/hibernatedb" />
<property name="username" value="dbuser" />
<property name="password" value="blahblah" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
The main application looks like
ApplicationContext context = new ClassPathXmlApplicationContext("simpleappcontext.xml");
PersonService personService = (PersonService) context.getBean("personService");
Person person = new Person();
person.setName("Alba");
person.setEmail("[email protected]");
personService.addPerson(person);
with the PersonService
being annotated @Transactional
:
package org.hibtests.service;
@Transactional
@Component
public class PersonService {
@Autowired
private PersonDao personDao;
public PersonDao getPersonDao() {
return personDao;
}
@Transactional(readOnly=false)
public void addPerson(Person person) {
getPersonDao().insert(person);
}
}
PersonDao.java:
package org.hibtests.dao;
@Repository
public class PersonDao {
@Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void insert(Person person) {
Session session = getSessionFactory().getCurrentSession();
session.persist(person);
}
produces the error
INFO: Using DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource@1fe4169] of Hibernate SessionFactory for HibernateTransactionManager
Exception in thread "main" org.hibernate.HibernateException: persist is not valid without active transaction
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:348)
at $Proxy16.persist(Unknown Source)
at org.hibtests.dao.PersonDao.insert(PersonDao.java:26)
at org.hibtests.dao.PersonService.addPerson(PersonService.java:27)
at org.hibtests.dao.PersonService$$FastClassByCGLIB$$403bca40.invoke(<generated>)
while I could use session.beginTransaction()
and session.getTransaction().commit()
before and after the persist
method, is it possible to just use Spring's @Transactional
annotations to manage the transaction? If so how?
Upvotes: 0
Views: 1672
Reputation: 124441
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
</props>
</property>
It is your own configuration that is breaking proper transaction support/integration. When using Spring for declarative transaction management never mess around with the hibernate.current_session_context_class
property. Unless you are using JTA then you need to integrate it with JTA.
Spring by default registers its own CurrentSessionContext
implementation for proper transaction integration with hibernate. It will register the SpringSessionContext
. However as soon as you start configuring the hibernate.current_session_context_class
this default will be overridden and as such transactions break.
Remove the line from your configuration.
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
</props>
</property>
This will properly let spring register its own contextual session management.
Upvotes: 2
Reputation: 556
You can annotate your insert method so Spring injects a transaction:
@Transactional
public void insert(Person person) {
And you PersonDao class should be implementing an interface. The "proxy" exception means Spring can't inject the transaction without an (annotated) interface. You need to add an interface an have PersonDao implement the interface.
Hope that helps.
Upvotes: 0
Reputation: 2819
Update your service class as follows
@Service
@Transactional(readOnly = true,propagation=Propagation.SUPPORTS)
public class PersonService {
}
OR you can do this way also
package org.hibtests.service;
@Service
public class PersonService {
@Autowired
private PersonDao personDao;
@Transactional(readOnly = true,propagation=Propagation.SUPPORTS)
public PersonDao getPersonDao() {
return personDao;
}
@Transactional(readOnly = true,propagation=Propagation.SUPPORTS)
public void addPerson(Person person) {
getPersonDao().insert(person);
}
}
hope this will help you
Upvotes: 0