Transaction Management using Hibernate with weblogic - spring

Our application is deployed on weblogic
we use Hibernate and spring
The session factory is created through a user defined class which creates SessionFactories by reading the hibernate.cfg.xml file
So these are the steps :
Our custom class is defined in spring application context and we inject the format of theCFG xml file in this class constructor :
<bean id="myCustomFactoryCreator"
class="com.xyz.CustomFactoryCreator"
singleton="true">
<constructor-arg>
<bean class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" >
<property name="staticField">
<value>com.xyz.MyConstants.HIBERNATE_CFG_XML</value>
</property>
</bean>
</constructor-arg>
</bean>
In MyConstants.java:
public static final String HIBERNATE_CFG_XML = ".hibernate.cfg.xml";
So this way in the constructor - the code will iterate over all such files ending with ".hibernate.cfg.xml"
I will have different files for different clients :
"Client1.hibernate.cfg.xml" and "Client2.hibernate.cfg.xml" and so on ......
The code will iterate over all such files and create SessionFactories and then embed them into Springs HibernateTemplate and then store them in a map against the client name as key value pair :
i.e. Client1 , HibernateTemplate1
Client2 , HibernateTemplate2 and so on
I hope you get the picture
This bean "myCustomFactoryCreator" is then injected into my Dao:
<bean id="myCustomDao"
class="com.xyz.MyCustomDao"
lazy-init="true">
<property name="criteriaConverter" ref="criteriaConverter" />
<property name="myFactory" ref="myCustomFactoryCreator" />
</bean>
An example of my Hibernate.cfg.xml is as : ( I have multiple such files where schema name changes for each client )
<hibernate-configuration>
<session-factory>
<property name="connection.datasource">MYDS</property>
<property name="show_sql">true</property>
<property name="default_schema">CLIENT1SCHEMA</property>
</session-factory>
In my Dao - based on the client login - I get the appropriate HibernateTemplate and fire selects against the database
Here we are using "DetachedCriteria" - sample code as follows :
List<T> inObjList=HibernateTemplate.findByCriteria(DetachedCriteria, 0, 100);
So this is all fine and this works well
This was when we were using Hibernate prior to 4.x
Thanks for your patience till now - will now get to the problem
With Hibernate 4.x - I cannot any longer use Springs Hibernate Template
Even if there is a way to use it - for reasons beyond my control I will not be allowed to use it - so I must go the SessionFactory route
So following the same logic as above - I stored in a map clientName and SessionFactory as against storing HibernateTemplate
The difference was that now I could no longer use - HibernateTemplate.findByCriteria()
So what I did was got the SessionFactory from the map and then tried to get a session:
Session session=testSessionFactory.getCurrentSession();
This failed with the error at above line with the exception :
org.hibernate.HibernateException: No CurrentSessionContext configured!
So did a bit of googling and looking at solutions in stackoverflow - I added the following line in my CFG files - I am not 100% sure if it is correct but used it assuming that mine being a managed environment where I am using weblogic managed datasource it would be JTA:
<property name="hibernate.current_session_context_class">jta</property>
This got me by the first exception - but then I hit the second exception :
org.hibernate.HibernateException: createCriteria is not valid without active transaction
at the following line of code :
Criteria subSelectCriteria =session.createCriteria(getType());
I come from the humble jdbc world - so I thought no big deal - I will simply add some transaction ala jdbc in the code - so I added this :
Transaction tx = null;
session.beginTransaction();
Criteria subSelectCriteria =session.createCriteria(getType());
tx.commit();
It failed at the above commit with the error :
Caused by: org.hibernate.TransactionException: unable to commit against JDBC connection
at org.hibernate.engine.tx.internal.jdbc.JdbcTransaction.doCommit(JdbcTransaction.java:116)
at org.hibernate.engine.tx.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:180)
Caused by: java.sql.SQLException: Cannot call Connection.commit in distributed transaction.
Transaction Manager will commit the resource manager when the distributed tx is committed.
at weblogic.jdbc.wrapper.JTSConnection.commit(JTSConnection.java:663)
So then in my Hibernate CFG file I added the following line and removed the transaction management in my Java code in my Dao :
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
This gave the error :
org.hibernate.HibernateException: No TransactionManagerLookup specified
So please advise what I should do - and thanks for bearing with me on a long post
NOTE - I did find a solution where I can define each SessionFactory as a bean in spring and inject each of these into a
org.springframework.orm.hibernate4.HibernateTransactionManager
However that would mean for each SessionFactory I would need to manually define a bean and inject the HibernateTransactinManager
Thank you !

Related

Programatically set v$session program property

I found some answers on the problem but none that i could make work in my case. My problem is that I load a datasource from my JBoss configuration with spring:
<xa-datasource jndi-name="java:jboss/jdbc/oracleDatasource" pool-name="jdbc/oracleDatasource" enabled="true">
<xa-datasource-property name="URL">
jdbc:oracle:thin:#URL:1522:SID
</xa-datasource-property>
<xa-datasource-property name="connectionProperties">
v$session.program=MyAPP
</xa-datasource-property>
<driver>oracle-jdbc</driver>
The spring loading is made as follows:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:jboss/jdbc/oracleDatasource"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
As you can see, I have set the v$session.program property in JBoss, it works well.
The problem is that i have several applications (war) that can be deployed on the same JBoss server, using this configuration. What I want to do in this case is to have each of my application to have its own name written in the v$session.program property.
So basically, i would like to be able to load the same datasource on each app but to have each of them using its own name to log the program property in oracle DB. Is it possible or do I have to have one datasource for each application hosted?
The only thing you need it to intercept each call of getConnection from connection pool.
You must obtain a real Oracle connection - not a proxy - and call the setClientInfo on 12c or setEndToEndMetrics in older versions to set the action / client / module identification.
An example see here.
Also note that the use of dbms_application_info for this same purpose works as well, but this produces a one server roundtrip too much. The setClientInfo doesn't produce server call, but stores this information for the next statement execution (which is the preformance saving approach).
Also note that to use this feature, your driver must match perfectly with your database - the strange exeptions you can see while setting teh client info are in most cases caused by the incompatibility of teh JDBC driver and the RDBMS.
If putting this information into v$session.module or v$session.client_info is an option, you can do using Java code.
All you need to do is call dbms_application_info.set_module() or dbms_application_info.set_client_info() after your Java code obtained the connection from the datasource.
Something like this:
Connection conn = ... // get connection from the DataSource
CallableStatement cstmt = conn.prepareCall("{call dbms_application_info.set_client_info(?)}");
cstmt.setString(1, "Some interesting information");
cstmt.execute();

Spring session with JDBC integration

I am new in Spring Session and want to use embedded database to store session information. I follow all the steps in
http://docs.spring.io/spring-session/docs/current/reference/html5/guides/httpsession-jdbc.html using spring-session-jdbc of version 1.2.0.but using Spring-web of 3.2.4 only
The following error is shown repeatly:
Caused by: org.postgresql.util.PSQLException: ERROR: relation "spring_session" does not exist 'Position: 13
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:365)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:824)
at org.springframework.jdbc.core.JdbcTemplate$2.doInPreparedStatement(JdbcTemplate.java:818)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:589)
... 21 more'
This issue already haunted me for days. Please help.
Here is the xml configuration
<bean class="org.springframework.session.jdbc.config.annotation.web.http.JdbcHttpSessi‌​onConfiguration"/>
<jdbc:embedded-database id="dataSource02" type="H2">
<jdbc:script location="classpath:org/springframework/session/jdbc/schema-h2.sql"/>
</jdbc:embedded-database>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource02"/>
</bean>
Your problem stems from the fact that you use multiple data sources, since the provided stacktrace includes PostgreSQL JDBC driver classes while you are configuring a secondary, embedded data source to storing sessions.
Spring Session configuration picks up your primary data source (PostgreSQL) and expects to find session tables there.
I'd suggest you to use your primary data source to store session data, but if you insist on having secondary/embedded data source for that purpose you need to override JdbcOperationsSessionRepository bean provided by JdbcHttpSessionConfiguration#sessionRepository with your own instance which is created using your secondary data source and its appropriate tra saction manager. Note that bean must be named sessionRepository in order to override one from JdbcHttpSessionConfiguration.

how to handle name not found exception in application-context.xml?

I am creating a spring project using Oracle and jboss server.
I have one bean in my application-context.xml.
<!-- Datasource for TaskManager -->
<jee:jndi-lookup id="tmTestDataSource"
jndi-name="test_datasource" expectedtype="javax.sql.DataSource"/>
<bean id="tmTestJdbcTemplate" name="TmTestJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="tmTestDataSource" />
</bean>
If the 'test_datasource' JNDI (one datasource.xml file in jboss deployment folder, which contains db credentials like url, uid, password) inside the file found deployment is successfull, but if the file is not there then the deployment is failing.
I want to handle this exception so that deployment should not fail.
how I can do this. Can anybody provide me any solution.
Thanks.
Instead of using dataSource args constructor, you can set it using setter method.
This way your bean will be created but its datasource will be null. So you will get NPE if you try to use it, but at least bean creation tree will not be stalled.

How to switch the datasource dynamically at runtime using AbstractRoutingDataSource?

Requirement:
I have the requirement like to switch the datasource at runtime after receiving the request.
I had read the blog about routing the datasource at runtime in spring3 using the class AbstractRoutingDataSource. Using that we can get the manually defined datasource key's at runtime.
Here in my project, datasources had configured in jetty-env.xml file. Now, i want to retrieve the Database name from DB in some tables like app_config.Using that DB name, i want to switch the database at runtime and also i want to pass the parameters to jetty-env.xml file.
Even I have a problem trying to set datasources from DB. You may like my solution (with annotations instead of xml). Spring 3.1.3 + Hibernate Configuration with annotations and with (Dynamic) AbstractRoutingDataSource
Taking a look at the "EDIT", you can set there any number of static datasources you want) or use them in xml.
Create a new subclass of DriverManagerDataSource, and autowire it a DAO to access table app_config.
Then for example override getUrl() method, and construct the url using a code dbNameParameter that allows to retrieve the database name from app config:
<bean id="parentDataSource"
class="org.springframework.jdbc.datasource.custom.MyDriverManagerDataSource"
abstract="true">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="username" value="sa"/>
</bean>
<bean id="goldDataSource" parent="parentDataSource">
<property name="dbNameParameter" value="gold"/>
</bean>
jetty-env.xml is not meant for that use and is better not used on this use case. It's better to put in jetty-env.xml only the datasource for where table app_config is.
You should store the tenant identifier in a ThreadLocal, supply data source list, configure an AbstractRoutingDataSource to select the data source at run time based on the tenant identifier.

Loading Liferay Properties from Spring IoC container (to get jdbc connection parameters)

I'm developing some portlets for Liferay Portal 5.2.3 with bundled tomcat 6.0.18 using Spring IoC container.
I need to map the User_ table used in Liferay database to an entity with Hibernate, so I need to use two different dataSources to separate the liferay db from the db used by portlets.
My jdbc.properties has to hold all connection parameters for both databases: no problem for the one used by portlets, but I am having issues determining which database uses liferay to hold its data.
My conclusion is that i should have something like this:
liferayConnection.url=jdbc:hsqldb:${liferay.home}/data/hsql/lportal
in order to get the database url dynamically loaded, according to Liferay properties found in portal-ext.properties. (Or, better, load the whole portal-ext.properties and read database properties from there).
The problem is that the placeholder is not resolved:
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'liferayDataSource' defined in class path resource [WEB-INF/applicationContext.xml]: Could not resolve placeholder 'liferay.home'
To dodge this problem I tried to load explicitly portal-ext.properties with a Spring bean:
<bean id="liferayPropertiesConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="../../portal-ext.properties"/>
but no luck: liferay.home is not resolved but there aren't other errors.
How can I resolve the placeholder defined by Liferay? Thanks
You can use PropsUtil class (from Liferay) to get values of portal-ext.properties.
String value = PropsUtil.get("key");
For loading properties files from an applicationContext.xml file I usually use the PropertiesFactoryBean specifying the location property with a the name of the file located in the classpath, like this:
<bean name="myHibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location">
<value>classpath:hibernate.properties</value>
</property>
</bean>
Make sure the properties files are in a folder/package that is in the classpath.
You can call PropsUtil using SpringEL. for example:
#{T(com.liferay.portal.kernel.util.PropsUtil).get('liferay.home')}
I haven't tried exactly this. but you could load the liferay properties that you need with the following:
<util:properties id="liferayProps">
<prop key="liferay.home">#{T(com.liferay.portal.kernel.util.PropsUtil).get('liferay.home')}</prop>
</util:properties>

Resources