Configuration of JTDS for use with HikariCP + Spring + MS SQL Server - spring

I kept googling for configuration of JTDS (1.3.1) for use with HikariCP (2.4.3), Spring (4.1.2), and MS SQL Server (2008), but unable to find a complete and working example.
Here is what I have:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="springHikariCP" />
<property name="connectionTestQuery" value="SELECT 1" />
<property name="dataSourceClassName" value="${jdbc.dataSourceClassName}" />
<property name="maximumPoolSize" value="${jdbc.maximumPoolSize}" />
<property name="minimumIdle" value="${jdbc.minimumIdle}" />
<property name="idleTimeout" value="${jdbc.idleTimeout}" />
....
<property name="dataSourceProperties">
<props>
....
</props>
</property>
</bean>
Can anyone out there share the JTDS configs used in a production environment?
Regards.
UPDATE
I found this SO post:
HikariCP hanging on getConnection
It seems that JTDS has a problem working with HikariCP. Actually, I have this problem too. Here is my complete config for JTDS:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="springHikariCP" />
<property name="connectionTestQuery" value="${jdbc.connectionTestQuery}" />
<property name="dataSourceClassName" value="${jdbc.dataSourceClassName}" />
<property name="maximumPoolSize" value="${jdbc.maximumPoolSize}" />
<property name="minimumIdle" value="${jdbc.minimumIdle}" />
<property name="idleTimeout" value="${jdbc.idleTimeout}" />
<property name="connectionTimeout" value="${jdbc.connectionTimeout}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="dataSourceProperties">
<props>
<prop key="user">${jdbc.username}</prop>
<prop key="password">${jdbc.password}</prop>
<prop key="cacheMetaData">${jtds.cacheMetaData}</prop>
</props>
</property>
</bean>
This is exactly the reason I posted my question, and I hope to see a complete example. However, at HikariCP's page, JTDS is listed as supported. I am confused.

The following works:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close" depends-on="flyway">
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"/>
<property name="connectionTestQuery" value="SELECT GETDATE()"/>
<property name="maximumPoolSize" value="32"/>
<property name="jdbcUrl" value="${dbUrl}"/>
<property name="username" value="${dbUsername}"/>
<property name="password" value="${dbPassword}"/>
</bean>
Notice the connectionTestQuery property which is required so Hikari will not assume the driver is JDBC4 compliant (jTDS is 3.0 compliant).

Based on #roded I implemented it on this way and it worked for me.
#Bean
public JdbcTemplate jdbcTemplate() {
HikariConfig c = new HikariConfig();
c.setDriverClassName("net.sourceforge.jtds.jdbc.Driver");
c.setConnectionTestQuery("SELECT GETDATE()");
c.setMaximumPoolSize(32);
c.setJdbcUrl("jdbc:jtds:sqlserver://serverIp:1433/DBName;");
c.getDataSourceProperties().put("user", "user");
c.getDataSourceProperties().put("password", "password");
c.getDataSourceProperties().put("cacheMetaData", true);
HikariDataSource hds = new HikariDataSource(c);
JdbcTemplate jdbcTemplate = new JdbcTemplate(hds);
return jdbcTemplate;
}

Just adding a Validation Query (ConnectionTestQuery) to my config didn't work for me.
I ended up having to Wrap my JtdsDataSource in a HikariDataSource to get it to work.
In a #Configuration class
public DataSource getDataSource()
{
//initial JtdsDataSource to control the DB connection
JtdsDataSource ds = new JtdsDataSource();
ds.setDomain(this.domain);
ds.setServerName(this.server);
ds.setDatabaseName(this.database);
ds.setUser(this.user);
ds.setPassword(this.password);
//settings for integrated authentication to work.
ds.setSsl(SSL_REQUEST); //static import from net.sourceforge.jtds.ssl.Ssl
ds.setUseNTLMV2(true);
//WRAP JTDS in a Hikari Datsource
HikariConfig hc = new HikariConfig();
hc.setDataSource(ds);
hc.setConnectionTestQuery("SELECT 1");
HikariDataSource hds = new HikariDataSource(hc);
return hds;
}

Both of these approaches worked for me. I am able to use db connection properly.
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="tmmConnPool"/>
<property name="connectionTestQuery" value="SELECT 1"/>
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver"/>
<property name="maximumPoolSize" value="10"/>
<property name="jdbcUrl" value="jdbc:jtds:sqlserver://127.0.0.1:1433/users;domain=workgroup"/>
<property name="username" value="sa"/>
<property name="password" value="admin"/>
</bean>
<!-- OR -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="tmmConnPool"/>
<property name="connectionTestQuery" value="SELECT 1"/>
<property name="dataSourceClassName" value="net.sourceforge.jtds.jdbcx.JtdsDataSource"/>
<property name="maximumPoolSize" value="10"/>
<property name="dataSourceProperties">
<props>
<prop key="user">sa</prop>
<prop key="password">admin</prop>
<prop key="serverName">127.0.0.1</prop>
<prop key="portNumber">1433</prop>
<prop key="databaseName">users</prop>
<!-- For SQLServer value is 1 -->
<prop key="serverType">1</prop>
<prop key="domain">workgroup</prop>
</props>
</property>
</bean>
<!-- Reference of above databSource, both options given above works -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg ref="hikariConfig"/>
</bean>
Apart from this, i was able to get connection using java implementation as well
public Connection getConnectionFromPool() {
final HikariConfig hikariCfg = new HikariConfig();
hikariCfg.setPoolName("tmmConnectionPool");
hikariCfg.setDataSourceClassName("net.sourceforge.jtds.jdbcx.JtdsDataSource");
hikariCfg.setConnectionTestQuery("SELECT 1");
hikariCfg.setMaximumPoolSize(10);
hikariCfg.getDataSourceProperties().put("user", "sa);
hikariCfg.getDataSourceProperties().put("password", "admin");
hikariCfg.getDataSourceProperties().put("serverName", "127.0.0.1");
hikariCfg.getDataSourceProperties().put("portNumber", "1433");
hikariCfg.getDataSourceProperties().put("databaseName", "users");
hikariCfg.getDataSourceProperties().put("serverType", "1");
hikariCfg.getDataSourceProperties().put("domain", "workgroup");
final HikariDataSource hikariDs = new HikariDataSource(hikariCfg);
Connection conn = null;
try {
conn = hikariDs.getConnection();
} catch (SQLException excp) {
LOGGER.error("Exception occurred while getting connection from dataSource", excp);
} finally {
if (hikariDs !=null) {
hikariDs.close();
}
}
return conn;
}

Related

Multiple datasource configuration issue

In my project I am using two oracle datasources for one of the datasource Im using LocalSessionFactoryBean and for another LocalContainerEntityManagerFactoryBean
I am mapping the datasources accordingly but when Im trying to get sessionFactory for LocalSessionFactoryBean the datasource details are that of the other. Dono what I am doing wrong.
<tx:annotation-driven transaction-manager="xxxTransactionManager" />
<bean id="xxxEntityManagerFactoryBean"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceXmlLocation" value="classpath:persistence.xml" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<bean class="org.modelmapper.ModelMapper" id="modelMapper"/>
<bean id="xxxEntityManager"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="xxxEntityManagerFactoryBean" />
</bean>
<bean id="xxxTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="xxxEntityManagerFactoryBean" />
<property name="nestedTransactionAllowed" value="true" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
in another xml file that is imported i have
<bean id="sessionFactoryNew"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource1" />
<property name="packagesToScan" value="com.citi.aml.npa.domain.api" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
</props>
</property>
</bean>
<bean id="xxxTransactionManagerNew"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactoryNew" />
<qualifier value="xxxtransaction"/>
</bean>
in app context.xml i have the datasources like
<beans profile="local">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db.oracle.driverClassName}" />
<property name="username" value="${db.oracle.username}" />
<property name="password" value="${db.oracle.password}" />
<property name="url" value="${db.oracle.url}" />
</bean>
<context:property-placeholder location="classpath*:/config/local/yyy.properties" ignore-unresolvable="true"/>
</beans>
<beans profile="local">
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db.oracle.driverClassName}" />
<property name="username" value="${db.oracle.username}" />
<property name="password" value="${db.oracle.password}" />
<property name="url" value="${db.oracle.url}" />
</bean>
<context:property-placeholder location="classpath*:/config/local/xxx_db.properties" ignore-unresolvable="true"/>
</beans>
in Dao impl calss i have
#Repository
public class OracledbTestRepository implements TestRepository {
#Autowired
#Qualifier(value = "sessionFactoryNew")
SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
#Override
public List<xxx> getTestData() {
Session session = sessionFactory.getCurrentSession();
System.out.println(sessionFactory);
List<xxx> xxxTestDatas = session.createCriteria(xxx.class).list();
return xxxTestDatas;
}
}
any help will be appreciated.
Your bean configuration looks a bit wonky to me. You have two different profiles with the same name. If these two datasources need to run at the same time, it would be simpler to consolidate your database properties into a single file, and place both datasource configurations within the same profile element.
So, for the consolidated database.properties, do something like:
db1.oracle.url=jdbc:oracle:thin:#server1...
db1.oracle.username=foo
...
db2.oracle.url=jdbc:oracle:thin:#server2...
db2.oracle.username=bar
And for the bean config, use something like:
<beans profile="local">
<context:property-placeholder location="classpath*:/config/local/database.properties" ignore-unresolvable="true"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db1.oracle.driverClassName}" />
<property name="username" value="${db1.oracle.username}" />
<property name="password" value="${db1.oracle.password}" />
<property name="url" value="${db1.oracle.url}" />
</bean>
<bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db2.oracle.driverClassName}" />
<property name="username" value="${db2.oracle.username}" />
<property name="password" value="${db2.oracle.password}" />
<property name="url" value="${db2.oracle.url}" />
</bean>
</beans>

Manage Hibernate and Activiti with Common TransactionManager

I want to use a common transaction manager (JpaTransactionManager) for hibernate and activiti, but i can not! And i have read all internet resources for that! Hear is a simple scenario (which does not even use hibernate!!):
Save variables in task
Save variable in task#execution
Complete task
Scenario implementation (in a spring bean method with #Transactional annotation):
#Component
public class TaskManager {
#Autowired TaskService taskService;
#Autowired RuntimeService runtimeService;
#Transactional
public void completeTask(CompleteTaskRequest request) {
Task task = taskService.createTaskQuery().taskId(request.getTaskId()).singleResult();
if (task == null) {
throw new ActivitiObjectNotFoundException("No task found");
}
taskService.setVariableLocal(task.getId(), "actionDisplayUrl", request.getActionDisplayUrl());
taskService.setVariableLocal(task.getId(), "actionSummaryUrl", request.getActionSummaryUrl());
runtimeService.setVariableLocal(task.getExecutionId(), "prevTaskId", task.getId());
taskService.complete(task.getId());
}
}
It's obvious: if taskService.complete throws error, the whole transaction should be rollbacked, so all saved variables should be rollbacked, and the below test case should be passed:
#Test
#Deployment(resources = "org.activiti.test/CompleteTaskTest.bpmn20.xml")
public void testCompleteTaskWithError() {
Map<String, Object> processVars = new HashMap<>();
processVars.put("error", true); // Causes throwing error in ScriptTaskListener
runtimeService.startProcessInstanceByKey("CompleteTaskTest", processVars);
Task task = taskService.createTaskQuery().taskName("Task 1").singleResult();
CompleteTaskRequest req = new CompleteTaskRequest();
req.setTaskId(task.getId());
req.setActionDisplayUrl("/actions/1234");
req.setActionSummaryUrl("/actions/1234/summary");
try {
taskManager.completeTask(req);
fail("An error expected!");
} catch(Exception e) {
}
// Check variables rollback
assertNull(taskService.getVariableLocal(task.getId(),"actionSummaryUrl"));
assertNull(taskService.getVariableLocal(task.getId(),"actionDisplayUrl"));
assertNull(runtimeService.getVariableLocal(task.getExecutionId(), "prevTaskId"));
}
But it fails, the variables are committed to DB (not rollbacked).
Spring context (Using org.springframework.orm.jpa.JpaTransactionManager as transaction manager):
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="idGenerator" ref="idGenerator"/>
<property name="databaseSchemaUpdate" value="true" />
<property name="jpaEntityManagerFactory" ref="entityManagerFactory" />
<property name="jpaHandleTransaction" value="true" />
<property name="jpaCloseEntityManager" value="true" />
<property name="beans" ref="processEngineBeans" />
<property name="jobExecutorActivate" value="false" />
<property name="asyncExecutorEnabled" value="true" />
<property name="asyncExecutorActivate" value="true" />
</bean>
<aop:config proxy-target-class="true" />
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
<bean id="processEngineBeans" class="java.util.HashMap">
<constructor-arg index="0" type="java.util.Map">
<map>
</map>
</constructor-arg>
</bean>
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
<bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
<bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService" />
<bean id="formService" factory-bean="processEngine" factory-method="getFormService" />
<bean id="idGenerator" class="org.activiti.engine.impl.persistence.StrongUuidGenerator" />
<bean id="activitiRule" class="org.activiti.engine.test.ActivitiRule">
<property name="processEngine" ref="processEngine" />
</bean>
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="packagesToScan" value="org.activiti.test" />
<property name="defaultDataSource" ref="dataSource" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect_resolvers">org.hibernate.engine.jdbc.dialect.internal.DialectResolverSet</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<!-- bean post-processor for JPA annotations -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" >
<property name="proxyTargetClass" value="true" />
</bean>
Versions:
Activiti version: 5.22.0
DB: h2 (Also tested with Oracle in production)
What is wrong with my configurations?
P.S.
The test project is uploaded here.
I have also asked this question in alfresco forum.
UPDATE::
By using org.springframework.jdbc.datasource.DataSourceTransactionManager instead of org.springframework.orm.jpa.JpaTransactionManager the test case passed. But now i can not persist JPA entities.
The problem is solved by resolving conflict between MyBatis (JDBC) and Hibernate (JPA):
jpaVendorAdapter property should be added to entityManagerFactory bean:
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
So entityManagerFactory bean should be like this:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect_resolvers">org.hibernate.engine.jdbc.dialect.internal.DialectResolverSet</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
For more details see answer of this question.

Spring session factory is always null for multiple datasources

I am trying to #Autowire multiple Hibernate SessionFactory inside my application through Spring 4 SessionFactory DI. Only one Datasource(epi) is getting injected properly but the other two Datasources SessionFactory values are always null.
Two of them are oracle database and the other one is DB2. I am not sure what I am doing wrong.
Here is my spring-Datasource.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="epiStageDS"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.ibm.db2.jcc.DB2Driver"/>
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
<bean id="epi"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
<bean id="eveDS"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="" />
<property name="username" value="" />
<property name="password" value="" />
</bean>
<!-- Session factory for EPI db -->
<bean id="episessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="epi" />
<property name="packagesToScan">
<list>
<value>edu.eve.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql:false}</prop>
</props>
</property>
</bean>
<!-- EVE DS SESSION FACTORY -->
<bean id="eveSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="eveDS" />
<property name="packagesToScan">
<list>
<value>edu.eve.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql:false}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql:false}</prop>
</props>
</property>
</bean>
<!-- Session factory for Stage DS db -->
<bean id="stageDsSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="epiStageDS" />
<property name="packagesToScan">
<list>
<value>edu.eve.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
<prop key="hibernate.show_sql">${hibernate.db2.show_sql:false}</prop>
<prop key="hibernate.format_sql">${hibernate.db2.format_sql:false}</prop>
</props>
</property>
</bean>
<bean id="epiTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="episessionFactory" />
</bean>
<bean id="eveTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="eveSessionFactory" />
</bean>
<bean id="stageDsTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="stageDsSessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
Here are the classes in which I am autowiring SessionFactory.
Below sessionFactory is getting injected perfectly.
#Transactional("epiTransactionManager")
public class EpiBaseService {
#Autowired
#Qualifier("episessionFactory")
private SessionFactory sessionFactory;
Autowired sessionFactory value are always null for below DS.
#Transactional("stageDsTransactionManager")
public class StageDsBaseService {
#Autowired
#Qualifier("stageDsSessionFactory")
private SessionFactory sessionFactory;
#Transactional("eveTransactionManager")
public class EveBaseService {
#Autowired
#Qualifier("eveSessionFactory")
private SessionFactory sessionFactory;
Please tell me what i am missing here.
I know what I was doing wrong. I was creating a new object of service class rather than #Autowiring inside the spring controller. I was doing this in order to make sure that my sessionfactory is not null but looks like that's not the correct way to do it. You have to use the Spring IOC container to inject the service class in your controller. Now all the sessionFactories are properly connected to specified datasources.

Configure an Atomikos UserTransactionManager for Hibernate in Spring Batch

What I need to do is a distributed transaction over three distinct Oracle databases. One of each must be accessed through JDBC, the two others through Hibernate. Here is my Atomikos configuration :
<bean id="mainDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName" value="${mainDataSource.jdbc.className}" />
<property name="uniqueResourceName" value="${mainDataSource.jdbc.uniqueName}" />
<property name="poolSize" value="${mainDataSource.jdbc.maxPoolSize}" />
<property name="testQuery" value="${mainDataSource.jdbc.testQuery}" />
<property name="xaProperties">
<props>
<prop key="URL">${mainDataSource.jdbc.url}</prop>
<prop key="user">${mainDataSource.jdbc.user}</prop>
<prop key="password">${mainDataSource.jdbc.password}</prop>
</props>
</property>
</bean>
<bean id="optionalDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName" value="${optionalDataSource.jdbc.className}" />
<property name="uniqueResourceName" value="${optionalDataSource.jdbc.uniqueName}" />
<property name="poolSize" value="${optionalDataSource.jdbc.maxPoolSize}" />
<property name="testQuery" value="${optionalDataSource.jdbc.testQuery}" />
<property name="xaProperties">
<props>
<prop key="URL">${optionalDataSource.jdbc.url}</prop>
<prop key="user">${optionalDataSource.jdbc.user}</prop>
<prop key="password">${optionalDataSource.jdbc.password}</prop>
</props>
</property>
</bean>
<bean id="eventDataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="xaDataSourceClassName" value="${eventDataSource.jdbc.className}" />
<property name="uniqueResourceName" value="${eventDataSource.jdbc.uniqueName}" />
<property name="poolSize" value="${eventDataSource.jdbc.maxPoolSize}" />
<property name="testQuery" value="${eventDataSource.jdbc.testQuery}" />
<property name="xaProperties">
<props>
<prop key="URL">${eventDataSource.jdbc.url}</prop>
<prop key="user">${eventDataSource.jdbc.user}</prop>
<prop key="password">${eventDataSource.jdbc.password}</prop>
</props>
</property>
</bean>
<bean id="atomikosTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp"
init-method="init" destroy-method="shutdownForce">
<constructor-arg>
<props>
<prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactory
</prop>
<prop key="com.atomikos.icatch.tm_unique_name">${transactionmanager.atomikos.tmId}</prop>
<prop key="com.atomikos.icatch.enable_logging">${transactionmanager.atomikos.enablelogging}</prop>
<prop key="com.atomikos.icatch.output_dir">${transactionmanager.atomikos.console}</prop>
<prop key="com.atomikos.icatch.log_base_dir">${transactionmanager.atomikos.tmLog}</prop>
<prop key="com.atomikos.icatch.log_base_name">${transactionmanager.atomikos.tmLogBaseName}</prop>
</props>
</constructor-arg>
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp"
depends-on="atomikosTransactionService">
<property name="transactionTimeout" value="300" />
</bean>
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" depends-on="atomikosTransactionService"
destroy-method="close">
<!-- when close is called, should we force transactions to terminate or
not? -->
<property name="forceShutdown" value="true" />
<property name="startupTransactionService" value="false" />
</bean>
<bean id="mainTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosTransactionManager" />
<property name="userTransaction" ref="atomikosUserTransaction" />
</bean>
<!-- Der mainTransactionManager ist der Default-TransactionManager von Spring. -->
<alias name="mainTransactionManager" alias="transactionManager" />
The Hibernate configuration is inspired by the solution found on this topic :
<!-- inject the Atomikos transaction manager into a Spring Hibernate adapter
for JTA Platform -->
<bean id="springJtaPlatformAdapter"
class="my.domain.spring.hibernate.jta.SpringJtaPlatformAdapter">
<!-- the mainTransactionManager is defined in ora_jtam_atomikos.xml imported -->
<property name="jtaTransactionManager" ref="mainTransactionManager" />
</bean>
<bean id="entityManagerFactoryEVL"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
depends-on="mainTransactionManager,springJtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:evl_persistence.xml" />
<property name="persistenceUnitName" value="evlPersistenceUnit" />
<property name="dataSource" ref="optionalDataSource" />
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaPropertyMap" ref="jpaPropertyMapEVL"></property>
</bean>
<util:map id="jpaPropertyMapEVL">
<entry key="hibernate.hbm2ddl.auto" value="validate" />
<entry key="hibernate.show_sql" value="false" />
<entry key="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<entry key="hibernate.transaction.jta.platform"
value="my.domain.spring.hibernate.jta.SpringJtaPlatformAdapter" />
</util:map>
<bean id="entityManagerFactoryVVL"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
depends-on="mainTransactionManager,springJtaPlatformAdapter">
<property name="persistenceXmlLocation" value="classpath:vvl_persistence.xml" />
<property name="persistenceUnitName" value="vvlPersistenceUnit" />
<property name="dataSource" ref="eventDataSource" />
<property name="loadTimeWeaver">
<bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</property>
<property name="jpaPropertyMap" ref="jpaPropertyMapVVL"></property>
</bean>
<util:map id="jpaPropertyMapVVL">
<entry key="hibernate.hbm2ddl.auto" value="validate" />
<entry key="hibernate.show_sql" value="false" />
<entry key="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<entry key="hibernate.transaction.jta.platform"
value="my.domain.spring.hibernate.jta.SpringJtaPlatformAdapter" />
</util:map>
And the small class named SpringJtaPlatformAdapter :
public class SpringJtaPlatformAdapter extends AbstractJtaPlatform {
private static final long serialVersionUID = -7030175748923257913L;
private static TransactionManager sTransactionManager;
private static UserTransaction sUserTransaction;
#Override
protected TransactionManager locateTransactionManager() {
Assert.notNull(sTransactionManager, "TransactionManager has not been setted");
return sTransactionManager;
}
#Override
protected UserTransaction locateUserTransaction() {
Assert.notNull(sUserTransaction, "UserTransaction has not been setted");
return sUserTransaction;
}
public void setJtaTransactionManager(JtaTransactionManager jtaTransactionManager) {
sTransactionManager = jtaTransactionManager.getTransactionManager();
sUserTransaction = jtaTransactionManager.getUserTransaction();
}
}
When I do run the batch, I could verified that :
the atomikosUserTransaction and atomikosTransactionManager of
Atomikos are constructed first
the mainTransactionManager is initialized right after
the setJtaTransactionManager method of my SpringJtaPlatformAdapter is called, both memory addresses for the sTransactionManager and sUserTransaction are consistent with the ones created before
the locateTransactionManager of the SpringJtaPlatformAdapter is called twice (one for each persistence unit)
my Hibernate code is then performed, my entities are correctly initialized
the database which is accessed through JDBC is updated
the databases which are accessed through Hibernate are NOT updated (as if a rollback took place)
During the run, only one warning appears in the logs :
WARN main SessionFactoryImpl:1530 - HHH000008: JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()
Maybe that can help, I personnaly don't get the warning message.
According to Maven, I'm using Spring ORM 3.2.0 with Hibernate 4.2.3 and Atomikos 3.8.0.
I am using Atomikos 4.0.0.M4 release with:
<entry key="hibernate.transaction.jta.platform"
value="com.atomikos.icatch.jta.hibernate4.AtomikosPlatform"/>
instead of:
<entry key="hibernate.transaction.manager_lookup_class"
value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
The point to note is that Hibernate 4.x moved away from TransactionManager to JtaPlatform which has necessitated the need for the change in configuration.
I am happy with the functionality provided by Atomikos and it has been running stably for me.
One colleague found why my hibernate databases were not updated. I had this in my persistence.xml :
<persistence-unit name="evlPersistenceUnit" transaction-type="RESOUCE_LOCAL">
For Atomikos, I should have placed :
<persistence-unit name="evlPersistenceUnit" transaction-type="JTA">
Now it's working just fine.

How to set up datasource with Spring for HikariCP?

Hi I'm trying to use HikariCP with Spring for connection pool. I'm using jdbcTempLate and JdbcdaoSupport.
This is my spring configuration file for datasource:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<property name="dataSourceClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="dataSource.url" value="jdbc:oracle:thin:#localhost:1521:XE"/>
<property name="dataSource.user" value="username"/>
<property name="dataSource.password" value="password"/>
</bean>
But unfortunately the following error message is generating:
Cannot resolve reference to bean 'dataSource' while setting bean property 'dataSource'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in ServletContext resource [/WEB-INF/dispatcher-servlet.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.zaxxer.hikari.HikariDataSource]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.zaxxer.hikari.HikariDataSource.<init>()
Can anyone please tell me how to solve this issue?
you need to write this structure on your bean configuration (this is your datasource):
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="springHikariCP" />
<property name="connectionTestQuery" value="SELECT 1" />
<property name="dataSourceClassName" value="${hibernate.dataSourceClassName}" />
<property name="maximumPoolSize" value="${hibernate.hikari.maximumPoolSize}" />
<property name="idleTimeout" value="${hibernate.hikari.idleTimeout}" />
<property name="dataSourceProperties">
<props>
<prop key="url">${dataSource.url}</prop>
<prop key="user">${dataSource.username}</prop>
<prop key="password">${dataSource.password}</prop>
</props>
</property>
</bean>
<!-- HikariCP configuration -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
This is my example and it is working. You just need to put your properties on hibernate.properties and set it before:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:hibernate.properties</value>
</list>
</property>
</bean>
Obs.: the versions are
log4j: 1.2.16
springframework: 3.1.4.RELEASE
HikariCP: 1.4.0
Properties file (hibernate.properties):
hibernate.dataSourceClassName=oracle.jdbc.pool.OracleDataSource
hibernate.hikari.maximumPoolSize=10
hibernate.hikari.idleTimeout=30000
dataSource.url=jdbc:oracle:thin:#localhost:1521:xe
dataSource.username=admin
dataSource.password=
my test java config (for MySql)
#Bean(destroyMethod = "close")
public DataSource dataSource(){
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setDriverClassName("com.mysql.jdbc.Driver");
hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/spring-test");
hikariConfig.setUsername("root");
hikariConfig.setPassword("admin");
hikariConfig.setMaximumPoolSize(5);
hikariConfig.setConnectionTestQuery("SELECT 1");
hikariConfig.setPoolName("springHikariCP");
hikariConfig.addDataSourceProperty("dataSource.cachePrepStmts", "true");
hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSize", "250");
hikariConfig.addDataSourceProperty("dataSource.prepStmtCacheSqlLimit", "2048");
hikariConfig.addDataSourceProperty("dataSource.useServerPrepStmts", "true");
HikariDataSource dataSource = new HikariDataSource(hikariConfig);
return dataSource;
}
You can create a datasource bean in servlet context as:
<beans:bean id="dataSource"
class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<beans:property name="dataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" />
<beans:property name="maximumPoolSize" value="5" />
<beans:property name="maxLifetime" value="30000" />
<beans:property name="idleTimeout" value="30000" />
<beans:property name="dataSourceProperties">
<beans:props>
<beans:prop key="url">jdbc:mysql://localhost:3306/exampledb</beans:prop>
<beans:prop key="user">root</beans:prop>
<beans:prop key="password"></beans:prop>
<beans:prop key="prepStmtCacheSize">250</beans:prop>
<beans:prop key="prepStmtCacheSqlLimit">2048</beans:prop>
<beans:prop key="cachePrepStmts">true</beans:prop>
<beans:prop key="useServerPrepStmts">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
Using XML configuration, your data source should look something like this:
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="dataSourceProperties" >
<props>
<prop key="dataSource.url">jdbc:oracle:thin:#localhost:1521:XE</prop>
<prop key="dataSource.user">username</prop>
<prop key="dataSource.password">password</prop>
</props>
</property>
<property name="dataSourceClassName"
value="oracle.jdbc.driver.OracleDriver" />
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg ref="hikariConfig" />
</bean>
Or you could skip the HikariConfig bean altogether and use an approach like the one mentioned here
I have recently migrated from C3P0 to HikariCP in a Spring and Hibernate based project and it was not as easy as I had imagined and here I am sharing my findings.
For Spring Boot see my answer here
I have the following setup
Spring 4.3.8+
Hiberante 4.3.8+
Gradle 2.x
PostgreSQL 9.5
Some of the below configs are similar to some of the answers above but, there are differences.
Gradle stuff
In order to pull in the right jars, I needed to pull in the following jars
//latest driver because *brettw* see https://github.com/pgjdbc/pgjdbc/pull/849
compile 'org.postgresql:postgresql:42.2.0'
compile('com.zaxxer:HikariCP:2.7.6') {
//they are pulled in separately elsewhere
exclude group: 'org.hibernate', module: 'hibernate-core'
}
// Recommended to use HikariCPConnectionProvider by Hibernate in 4.3.6+
compile('org.hibernate:hibernate-hikaricp:4.3.8.Final') {
//they are pulled in separately elsewhere, to avoid version conflicts
exclude group: 'org.hibernate', module: 'hibernate-core'
exclude group: 'com.zaxxer', module: 'HikariCP'
}
// Needed for HikariCP logging if you use log4j
compile('org.slf4j:slf4j-simple:1.7.25')
compile('org.slf4j:slf4j-log4j12:1.7.25') {
//log4j pulled in separately, exclude to avoid version conflict
exclude group: 'log4j', module: 'log4j'
}
Spring/Hibernate based configs
In order to get Spring & Hibernate to make use of Hikari Connection pool, you need to define the HikariDataSource and feed it into sessionFactory bean as shown below.
<!-- HikariCP Database bean -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
<!-- HikariConfig config that is fed to above dataSource -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="SpringHikariPool" />
<property name="dataSourceClassName" value="org.postgresql.ds.PGSimpleDataSource" />
<property name="maximumPoolSize" value="20" />
<property name="idleTimeout" value="30000" />
<property name="dataSourceProperties">
<props>
<prop key="serverName">localhost</prop>
<prop key="portNumber">5432</prop>
<prop key="databaseName">dbname</prop>
<prop key="user">dbuser</prop>
<prop key="password">dbpassword</prop>
</props>
</property>
</bean>
<bean class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" id="sessionFactory">
<!-- Your Hikari dataSource below -->
<property name="dataSource" ref="dataSource"/>
<!-- your other configs go here -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.provider_class">org.hibernate.hikaricp.internal.HikariCPConnectionProvider</prop>
<!-- Remaining props goes here -->
</props>
</property>
</bean>
Once the above are setup then, you need to add an entry to your log4j or logback and set the level to DEBUG to see Hikari Connection Pool start up.
Log4j1.2
<!-- Keep additivity=false to avoid duplicate lines -->
<logger additivity="false" name="com.zaxxer.hikari">
<level value="debug"/>
<!-- Your appenders goes here -->
</logger>
Logback
Via application.properties in Spring Boot
debug=true
logging.level.com.zaxxer.hikari.HikariConfig=DEBUG
Using logback.xml
<logger name="com.zaxxer.hikari" level="DEBUG" additivity="false">
<appender-ref ref="STDOUT" />
</logger>
With the above you should be all good to go! Obviously you need to customize the HikariCP pool configs in order to get the performance that it promises.
This last error is caused by the library SLF4J not being found. HikariCP has two dependencies: slf4j and javassist. BTW, HikariDataSource does have a default constructor and does not need HikariConfig, see this link. So that was never the problem.
I found it in http://www.baeldung.com/hikaricp and it works.
Your pom.xml
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>2.6.3</version>
</dependency>
Your data.xml
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="jdbcUrl" value="${jdbc.databaseurl}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"
/>
Your jdbc.properties
jdbc.driverClassName=org.postgresql.Driver
jdbc.dialect=org.hibernate.dialect.PostgreSQL94Dialect
jdbc.databaseurl=jdbc:postgresql://localhost:5432/dev_db
jdbc.username=dev
jdbc.password=dev
May this also can help using configuration file like java class way.
#Configuration
#PropertySource("classpath:application.properties")
public class DataSourceConfig {
#Autowired
JdbcConfigProperties jdbc;
#Bean(name = "hikariDataSource")
public DataSource hikariDataSource() {
HikariConfig config = new HikariConfig();
HikariDataSource dataSource;
config.setJdbcUrl(jdbc.getUrl());
config.setUsername(jdbc.getUser());
config.setPassword(jdbc.getPassword());
// optional: Property setting depends on database vendor
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
dataSource = new HikariDataSource(config);
return dataSource;
}
}
How to use it:
#Component
public class Car implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(AptSommering.class);
#Autowired
#Qualifier("hikariDataSource")
private DataSource hikariDataSource;
}
for DB2, please try below configuration.
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="poolName" value="springHikariCP" />
<property name="dataSourceClassName" value="com.ibm.db2.jcc.DB2SimpleDataSource"/>
<property name="maximumPoolSize" value="${db.maxTotal}" />
<property name="dataSourceProperties">
<props>
<prop key="driverType">4</prop>
<prop key="serverName">192.168.xxx.xxx</prop>
<prop key="databaseName">dbname</prop>
<prop key="portNumber">50000</prop>
<prop key="user">db2inst1</prop>
<prop key="password">password</prop>
</props>
</property>
<property name="jdbcUrl" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<constructor-arg ref="hikariConfig" />
</bean>

Resources