Spring + Hibernate migration - currentSession() method throwing exception - spring

I have migrated Spring from 3.1 to 4.1.3 and Hibernate 3.2 to 4.3.9
As part of migration I have modified below import and code
old import
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
new Import
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;
and code changes
In hibernate 3 I have following code
public Session getCurrentSession() {
Session session = getSession();
session.setFlushMode(FlushMode.MANUAL);
return session;
}
now I have modified according to new jars as below
public Session getCurrentSession() {
Session session = currentSession();
session.setFlushMode(FlushMode.MANUAL);
return session;
}
after the above changes I am getting below exception
Could not obtain transaction-synchronized Session for current thread
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1014)
at org.springframework.orm.hibernate4.support.HibernateDaoSupport.currentSession(HibernateDaoSupport.java:129)
I am not using annotations in my application
I am not able to resolve the issue. Please help me in knowing possible reasons for the exception

I guess you need to add transactionManager for your sesssionFactory:
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="mySessionFactory"/>
</property>
</bean>
where, mySessionFactory is your Session Factory Bean Id.
As you said, you are not using Annotations in your project. Then, you must use AOP to enable Transaction Management at Method Level.
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="select*" read-only="true" />
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* example.MyClass.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
</aop:config>
Add Transaction Support for your method like this.
Add following entry in your POM, if you are using MAVEN or gradle or you can simply download and add jar to your classpath.
<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.3.RELEASE</version>
</dependency>

Related

Spring boot AOP configuration in external Jar file

I am writing a new spring boot app that is using existing jar files that work fine in other non spring boot applications (they are using spring).
In our service layer, we are using spring transactions and spring AOP that have their configurations defined in an XML file. For example:
<!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'find' are read-only -->
<tx:method name="find*" read-only="true" propagation="REQUIRED"/>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" propagation="REQUIRED"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution
of an operation on any service -->
<aop:config>
<aop:advisor pointcut="com.company.app.common.aspect.SystemArchitecture.serviceTransaction()"
advice-ref="dbTransaction" order="1010" />
<aop:aspect ref="verifyDatasourceSwitch" order="1001">
<aop:around pointcut="com.company.app.common.aspect.SystemArchitecture.serviceOperation()"
method="verifyDatasource" />
</aop:aspect>
<aop:aspect ref="appDatasourceSwitch" order="12">
<aop:around pointcut="com.company.app.common.aspect.SystemArchitecture.controlDatasource()"
method="switchToControl" />
</aop:aspect>
<aop:aspect ref="controlMongoDatabaseSwitch" order="13">
<aop:around pointcut="com.company.app.common.aspect.SystemArchitecture.controlMongoDatabase()"
method="switchToControl" />
</aop:aspect>
</aop:config>
The aspects and pointcuts are defined like this:
#Aspect
public class SystemArchitecture
{
/**
* A join point in the service layer if the method is defined
* in a type in the com.company.app.service package or
* any sub-package under that
*/
#Pointcut("within(com.company.app.service..*)")
public void inServiceLayer() {}
#Pointcut("inServiceLayer() && this(com.company.app.service.Service)")
public void serviceRegularOperation() {}
/**
* A service operation is the execution of any method defined on a service
* interface. This definition assumes that interfaces are placed in the
* "service" package, and that implementations are in sub-packages.
*/
#Pointcut("serviceRegularOperation() || serviceBrandOperation() || serviceCustomerOperation() || serviceWithChangeLoggingOperation() || serviceNonStandardService()")
public void serviceOperation() {}
#Pointcut("serviceOperation() && !#annotation(com.company.app.service.advice.NoTransaction)")
public void serviceTransaction() {}
}
This is all working correctly in other apps that are using it.
In the spring boot app, I have a configuration class that includes the xml config containing the above.
#Configuration
#PropertySource("classpath:config/application.properties")
#ImportResource({ "classpath:aspect.xml",
"classpath:rabbit.xml",
"classpath:email.xml",
"classpath:approval.xml",
"classpath:event.xml",
"classpath:facades.xml",
"classpath:general.xml",
"classpath:velocity.xml",
"classpath:mongo.xml",
"classpath:services.xml",
"classpath:velocity-service.xml",
"classpath:velocity-facade.xml",
"classpath:sharedservices.xml",
"classpath:jobs.xml",
"classpath:cachesharedfacades.xml",
"classpath:sharedContext-security.xml",
"classpath:hibernate-common-session-factory.xml",
"classpath:hibernate-datasource.xml",
"classpath:hibernate-local-transaction-manager.xml",
"classpath:hibernate-mysql-session-factory.xml",
"classpath:hibernate-repositories.xml",
"classpath:mysql-repositories.xml",
"classpath:hibernate-template.xml",
"classpath:repository-mbeans.xml",
"classpath:spring-transaction.xml" })
public class ApplicationConfiguration
{
}
The main application is created as:
#SpringBootApplication
public class GraphqlApplication
{
public static void main( String[] args )
{
SpringApplication.run( GraphqlApplication.class, args );
}
}
When the application is started up, I see warnings such as:
Bean 'adminTypeService' of type [com.company.app.service.impl.AdminTypeServiceImpl]
is not eligible for getting processed by all BeanPostProcessors
(for example: not eligible for auto-proxying)
Which I assume is causing the proxying not to happen, which is probably what is stopping the AOP calls from working.
Am I missing something? I can see the beans defined in the services.xml are created, but when calling a service methods, they interface isn't proxied, so there are no transactions or other supporting functions called via AOP that need to happen.
Thanks in advance!

Hibernate EntityInterceptor (EmptyInterceptor): Filter out all #Transaction(readOnly=TRUE) Transactions

I defined and successfully plugged in a Hibernate DB Interceptor which catches all Transactions.
public class HibernateTransactionInterceptor extends EmptyInterceptor {
#Override
public void afterTransactionBegin(Transaction tx) {
System.out.println("Intercepted");
// ...
super.afterTransactionBegin(tx);
}
}
applicationContext.xml:
<bean id="transactionInterceptor" class="myapp.interceptor.HibernateTransactionInterceptor" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- Plug into SessionFactory the Interceptor bean define above -->
<property name="entityInterceptor" ref="transactionInterceptor" />
...
</bean>
Now, the Interceptor fires on all #Transaction service methods. But I need to only intercept #Transaction(readOnly=FALSE) methods (i.e., filter out all Read-Only methods). Is there a way to configure that?
I found the solution. There's an easy way to check for Read-Only/non-Read-Only Transactions with a Spring-level transaction listener. On the Spring level, rather than Hibernate, there's a method called TransactionSynchronizationManager.isCurrentTransactionReadOnly(). It can be called from the following implementation of TransactionSynchronization which uses a pointcut to intercept all #Before #Transactional Spring processing.
#Component
#Aspect
public class TransactionSynchronizationAspect implements TransactionSynchronization {
#Before("#annotation(org.springframework.transaction.annotation.Transactional)")
public void registerTransactionSynchronization() {
boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
if (!isReadOnly) {
// ... logic goes here...
}
// Continue
TransactionSynchronizationManager.registerSynchronization(this);
}
#Override
public void afterCompletion(int status) {
// No custom code here
}
}
As for the original Hibernate Transaction Listener in the Original Post, that strategy can still be used, but requires a tx:advice to restrict the Listener to specified (mapped) Service method names, like so:
<aop:config>
<aop:advisor id="managerTx" advice-ref="txAdvice"
pointcut="execution(* com.app.*.*.service.*.*(..))"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="customTransactionManager">
<tx:attributes>
<tx:method name="delete*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="update*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
<tx:method name="save*" propagation="REQUIRED" isolation="READ_COMMITTED"/>
</tx:attributes>
</tx:advice>
This XML file can be imported with #ImportResource. With this strategy, all Write operations would be intercepted with the Listener, while Reads would always go through automatically.

How to clean two databases after running JUnit test method using Flyway

I have a JUnit test method which makes call to two different services and both services are running with different data sources and of course in two transaction managers.
So i have configured Flyway to use H2 data base and implemented JUnit test method as below.
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
public class DataControllerTest extends BaseIntegrationTest {
#Test
public void testDataSave() throws Exception {
// test code to call controller which internally calls two services.
assertEquals(1, JdbcTestUtils.countRowsInTable(this.jdbcTemplate, "Database1Table1"));
assertEquals(1, JdbcTestUtils.countRowsInTable(this.anotherjdbcTemplate, "Database2Table1"));
}
}
So my question is this test method is creating some records in H2 database and i want to clear that data after running this test.
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource1" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
and other transaction manager to work on different data source are configured as below.
<bean id="txManager2"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="anotherDataSource" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
Since i gave this test class as Transactional it would clean database after each test method run.
But currently it is clearning only one database. but i want to clean another database which is part of anotherDatasource.
How do i need to proceed to do that..?
If possible and How to mention these two transaction managers in #Transactional annotation.

tx:annotation-driven not working

Hello friend i'm developing spring(4.0.3) and hibernate(4.3.6) based application.
I'm facing following error when I saved any object in session factory:
org.hibernate.HibernateException: save is not valid without active transaction
20:38:59,881 ERROR [STDERR] at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:348)
And following is the entry which I have used in my application-context.xml
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryAthena" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
On more thing I'd like to bring here if I used any value in transaction-manager attribute instead actual transactionManager for bean reference then its not throwing error.
So i think its not taking reference bean value.
Please help me!!
You should take a look in this link but follows an example using xml.
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryAthena" />
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<!-- the transactional advice (what happens; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with get are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name=""/>
</tx:attributes>
</tx:advice>
But nowadays I have been seeing the spring community using declarative transactions with annotations. Like the example below:
#Transactional(readOnly = true)
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
// do something
}
// these settings have precedence for this method
#Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public void updateFoo(Foo foo) {
// do something
}
}
Use #EnableTransactionManagement at the top of your class:
#Component
#EnableTransactionManagement
public class Abc{
}

How to use Dynamic Proxies with JSF when the method signature contains Object ... args

I'm having some trouble with Spring, JPA and Dynamic Proxy DAO classes which are initialized as Spring Beans. This particular project has been plaguing me on the persistence/transaction side for some time, and I'd like to get this nailed down once and for all.
First, here's a method from the DAO interface:
/**
* Perform a named query using numbered parameters and return the results as a list
* #param name
* #param params
* #return query results
*/
List getNQasList(String name, Object... params);
This bean is registered automatically with Spring using a postProcessBeanFactory method:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
this.beanFactory = beanFactory;
for (Class entityClass : this.getPersistedClassList()) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
ConstructorArgumentValues constructorVals = new ConstructorArgumentValues();
constructorVals.addIndexedArgumentValue(0, entityClass);
beanDefinition.setConstructorArgumentValues(constructorVals);
beanDefinition.setBeanClass(GenericDAOImpl.class);
beanDefinition.setAutowireCandidate(true);
beanDefinition.setLazyInit(true);
beanDefinition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
String simpleName = entityClass.getSimpleName();
String convertedName = "" + simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1) + "Dao";
registry.registerBeanDefinition(convertedName, beanDefinition);
}
}
The method getPersistedClassList() reads persistence.xml and finds all of the JPA classes. The above method registers each of these instances with Spring so they can be accessed easily by the variable "entityNameDao". Because this class is a transactional class, it gets initialized as a Dynamic Java Proxy, and that's where my problems begin. JSF doesn't perceive the object by its interfaces anymore, but looks directly at the proxy, which does in fact show the above method definition as:
List getNQasList(String name, Object[] params);
This makes it much more difficult to access from JSF than an Object... params signature method. Is there any way I can get JSF to recognize these objects by their interface, or convince Spring to somehow not make dynamic proxies of them? Alternatively, how does one go about doing the following in EL, it gives me errors about the curly braces if I try:
new Object[] {...}
My spring config relating to persistence, including the transaction advice is included below for good measure.
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="${JDBC_CONNECTION_STRING}?autoReconnect=true&useUnicode=true&connectionCollation=utf8_general_ci&characterSetResults=utf8"/>
<property name="username" value="${PARAM1}"/>
<property name="password" value="${PARAM2}"/>
<property name="validationQuery" value="select 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<context:annotation-config/>
<!-- Enable aspectj based transactions -->
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />
<!-- the transactional advice (i.e. what 'happens'; see the <aop:advisor/> bean below) -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- the transactional semantics... -->
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true"/>
<!-- other methods use the default transaction settings (see below) -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- ensure that the above transactional advice runs for any execution
of an operation defined by the GenericDAOImpl class -->
<aop:config>
<aop:pointcut id="DaoOps" expression="execution(* daos.GenericDAOImpl.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="DaoOps"/>
</aop:config>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" >
<property name="showSql" value="true"/>
</bean>
</property>
</bean>

Resources