The test below was working in my application with Hibernate3. When I upgraded it to hibernate4, it started failing.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(inheritLocations=false,locations={
"/hibernate/spring-SF-tests.xml",
"/hibernate/spring-transaction.xml",
"/hibernate/testBeans.xml"
,"/hibernate/spring-audit.xml",
"/hibernate/iwrs-mail-beans-test.xml",
"/hibernate/fake-audit-meaning.xml"
})
#TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
public class CodeAuditIntegrationTest extends CodeIntegrationTest {
#Autowired
private SessionFactory auditFactory;
#Before
public void cleanAudit(){
auditFactory.getCurrentSession().createQuery("delete from AuditLogRecord").executeUpdate();
}
#Test
public void clinicalTrialAssociationTest() {
super.clinicalTrialAssociationTest();
}
}
Which is failing with:
org.hibernate.HibernateException: No Session found for current thread
at
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
at
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:881)
I have 2 different session factories in my app: sessionFactory and auditFactory. Both are configured in spring (see [1]).
The problem is that in an hibernate4 configuration the property exposeTransactionAwareSessionFactory was removed. I had that set to true for my auditFactory. I believe removing this property makes the injected auditFactory not being able to pick up the session in the transaction (as txManger is configured for sessionFactory), therefore yielding the error.
Questions:
how can I make the auditFactory have transactions managed by spring on this test?
Is that what was happening with the exposeTransactionAwareSessionFactory property in hibernate 3?
The only alternative I see is to wrap all the code that uses auditFactory in a Helper class annotated with #Transactional(otherTxManager). I did try that, but I got a couple of additional problems there:
I needed to use a separate DataSource (else I'd get [2])
Using 2 separate datasources I'll get a similar error on my Cucumber tests, now related with the transactionManager [3]
[1] The relavant XML configuration:
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="sessionFactory" scope="singleton"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2dll}</prop>
<prop key="hibernate.hbm2ddl.import_files">${hibernate.sql_scripts}</prop>
</props>
</property>
<property name="packagesToScan">...</property>
<property name="annotatedPackages">...</property>
<property name="mappingLocations">...</property>
<property name="dataSource" ref="c3p0DataSource" />
<property name="entityInterceptor" ref="auditInterceptor" />
</bean>
<bean id="auditFactory" scope="singleton"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="exposeTransactionAwareSessionFactory"> -->needs to be removed in hibernate4!
<value>true</value>
</property>
<property name="mappingLocations">...</property>
<property name="packagesToScan">...</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2dll}</prop>
</props>
</property>
<property name="dataSource" ref="c3p0DataSource" />
</bean>
[2] Problem with using the same dataSource for the two factories:
org.springframework.transaction.IllegalTransactionStateException: Pre-bound JDBC Connection found! HibernateTransactionManager does not support running within DataSourceTransactionManager if told to manage the DataSource itself. It is recommended to use a single HibernateTransactionManager for all transactions on a single DataSource, no matter whether Hibernate or JDBC access.
at org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:329)
[3] Problem in cucumber tests due to declaring 2 transaction managers:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single bean but found 2: txAudit,txManager
Related
when I try persist some data that I recovered from my csv file on my database using my job processor in spring batch this error appear in the console , for my dao i'm using hibernate
I already tried 2 methode but the same probleme !
first :
Session session = factory.getCurrentSession();
session.saveOrUpdate(p);
second :
Session session = factory.openSession();
session.beginTransaction();
session.save(p);
session.getTransaction().commit();
session.close();
data source in my spring xml config :
all my spring xml config here https://pastebin.com/RZPr1GKL
<bean name="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/yassir" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>tp.entities.Personne</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven />
the error :
javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.internal.SessionImpl.checkTransactionNeeded(SessionImpl.java:3450)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1418)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1414)
...
When we use spring batch especially for tasklet in spring boot project #EnableBatchProcessing annotations will create its own transactions (Spring Batch Transactions) for its default tables.
Hence if you want to perform any insert, update or delete in your application tables(acutal table performing CRUD). We have to explicitly mention JpaTransactionManager instead of default spring batch transactions.
#Configuration
#EnableBatchProcessing
public class MyJob extends DefaultBatchConfigurer {
#Autowired
private DataSource dataSource;
#Bean
#Primary
public JpaTransactionManager jpaTransactionManager() {
final JpaTransactionManager tm = new JpaTransactionManager();
tm.setDataSource(dataSource);
return tm;
}
}
#Primary is most important one to mention else two transaction managers will be loaded. Mention jpaTransactionManager() in your job.
return stepBuilderFactory.get("stepOne")
.transactionManager(jpaTransactionManager())
.<DetailDTO,DetailDTO>chunk(100)
.reader(reportReader)
.processor(reportProcessor)
.writer(reportWriter)
.build();
Error which i got - Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress.
Click Up Vote if this is useful for you.
You configured Spring Batch to use a DataSourceTransactionManager to drive transactions. This transaction manager knows nothing about your Hibernate context. You need to use the HibernateTransactionManager to make the Hibernate Session in your writer participate in Spring Batch managed transactions.
I would also recommend to use the HibernateItemWriter instead of creating a custom writer (PersonneWriter) and manually creating the session and managing transactions.
A similar question/answer can be found here: Spring Batch JpaItemWriter vs HibernateItemWriter and why HibernateTransactionManager is needed when HibernateItemWriter is used
Hope this helps.
I am quite confused with Spring and Hibernate transactions. I have the following sample code.
I am wondering if
This is a correct way of retrieval or not.
Should I use getCurrentSession().beginTransaction() as well, should I use it in conjunction with #Transactional at all?
Configuration
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:2000/HiberProject" />
<property name="username" value="jack" />
<property name="password" value="jack" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
depends-on="dataSource">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.hiberproject.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Service
#Service
public class SampleRecordsServiceImpl implements SampleRecordsService{
#Autowired
SampleRecordsRepository sampleRecordsRepository;
#Override
#Transactional(readOnly=true)
public Record retrieveRecord(long id){
return sampleRecordsRepository.retrieveRecord(id);
}
}
Repository
#Repository
public class SampleRecordsRepository implements SampleRecordsRepository{
#Autowired
SessionFactory sessioFactory;
#Override
public Record retrieveRecord(long id){
return (Record) sessionFactory.getCurrentSession().get(Record.class,id);
}
}
The #Transactional annotation itself defines the scope of a single database transaction. The database transaction happens inside the scope of a persistence context.
The persistence context is just a synchronizer object that tracks the state of a limited set of Java objects and makes sure that changes on those objects are eventually persisted back into the database.
For #Transactional annotation you can set propagation attribute, using Propagation you can handle your tarnsaction in different way like Propagation.REQUIRES_NEW(if you need new transaction on every request) . the default propagation is REQUIRED.
session.beginTransaction() will also either begin a new Transaction if one isn't present, or it will use an existing transaction to begin the unit of work specified.
So you should use either one of approach to manage the transaction.
Yes that's Okay to use only #Transactional annotation like this when you use Spring to manage your transaction.
No. You don't need to do that! If you use #Transactional annotation in your service, then Spring takes care of your persistence layer to manage transaction. All you need is to declare persistence layer specific transaction manager in your Spring configuration. So you do not need to manage transaction with hibernate sessions by using session.beginTransaction() together with #Transactional.
For more information please see the documentation of using #Transactional.
I am using the Spring configuration to test Spring-Hibernate Transactions.
<beans ...>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- hibernate 4 onwards annotationsessionfactorybean is replaced with localsessionfactory bean -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.fg.arch.test.transaction.Foo</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>
<!-- <prop key="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</prop> -->
</props>
</property>
</bean>
</beans>
My service layer is annotated with #Transactional.
This is my DAO:
public class FooHibernateDaoImpl implements FooDao {
private SessionFactory sessionFactory;
public void testFoo(Foo foo) throws Throwable {
System.out.println(" --- ");
sessionFactory.openSession().save(foo);
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Explicitly opening the session using the openSession() method does not cause a problem however when I change to getCurrentSession() I am getting an exception.
I have two questions.
Is it good practice to call openSession() in every DAO method.
How can I make getCurrentSession() work so that it will not give me an exception like no active transaction present ?
Thanks.
To answer your questions:
No, its not. The #Transactional annotation that should be on your service class method calling testFoo() is opening the session for you. You should use getCurrentSession() in the DAO to get this session.
You can, but you shouldn't. That's the entire point of using the Hibernate SessionFactory with annotation based transaction management. As long as you are marking your service methods transactional, you shouldn't have a problem.
As a side note, why are you not Autowiring your SessionFactory? Don't use setters to set something that should be Autowired. Otherwise you may as well not use Spring.
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.
I am new to Spring programming and currently struggling with Spring 3.1's Java Based Configuraion" I have created following Configuration class
#Configuration
#ImportResource("classpath:/resources/jdbc.properties")
public class AppConfig {
#Autowired
Environment env;
private #Value("${jdbc.url}")
String url;
private #Value("${jdbc.username}")
String username;
private #Value("${jdbc.password}")
String password;
#Bean
public DataSource dataSource() {
System.out.println("Creating data Source.");
return new DriverManagerDataSource(url, username, password);
}
#Bean
public SessionFactory sessionFactory () throws Exception {
return new AnnotationSessionFactoryBuilder().setDataSource(dataSource()).setPackagesToScan("com.argusoft.loginmodule.domain").buildSessionFactory();
}
}
now when I try to run the project I get following error.
OUTPUT
SEVERE: Exception while loading the app :
java.lang.IllegalStateException: ContainerBase.addChild: start:
org.apache.catalina.LifecycleException:
java.lang.IllegalArgumentException: javax.servlet.ServletException:
java.lang.NoClassDefFoundError:
org/springframework/core/env/EnvironmentCapable
stuck into it, Cant solve it..... I am following Spring Source Blog.
please also suggest some good tutorial in which Spring's latest Java based configuration is explained by easy to understand examples...
Thanks in advance,
From the perspective of the exception:
java.lang.NoClassDefFoundError: org/springframework/core/env/EnvironmentCapable
This question is equals to the question: Spring class EnvironmentCapable
So the correct answer might be:
I think that need use version 3.1.0 - in package
org.springframework.core-3.1.0.M2.jar this class presents.
given by user810430 here: original answer.
you can puth configuration like this
inside application context:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>/WEB-INF/configuration.properties</value>
</list>
</property>
</bean>
<import resource="db-config.xml" />
and
db-config.xml is:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>${jdbc.driver.className}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" autowire="byName">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="packagesToScan" value="com.huawei.sa.album" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!-- uncomment this for first time run-->
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven />
</beans>