Transaction Repeatable Read Isolation does not work properly in PostgreSQL - spring

I use Spring framework with DataSourceTransactionManager and I noticed that Repeatable Read Isolation does not work properly with Postgresql. According to Postgres documentation:
repeatable read transaction cannot modify or lock rows changed by
other transactions after the repeatable read transaction began.
Lets assume that we have 2 transactions: T1 and T2. Assume this scenario:
T1 begin -> T2 begin -> T2 update row -> T2 commit -> T1 update the same row -> T1 commit
Transaction T1 should be rolled back with the message
ERROR: could not serialize access due to concurrent update
but T1 is committed and overwrites T2 update.
I made simple example in Spring to demonstrate it:
Sql:
CREATE TABLE tab
(
id bigint NOT NULL,
name character varying(50),
CONSTRAINT tab_pkey PRIMARY KEY (id )
)
INSERT INTO tab(id, name) VALUES (1, 'name');
DataSource configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
id="property">
<property name="location" value="classpath:database.properties"></property>
</bean>
<bean id="service" class="com.kulig.db_test.ServiceImpl">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
</beans>
Service interface:
public interface Service {
public void dosth(String name);
public void dosth2(String name);
}
Implementation of service interface:
public class ServiceImpl extends JdbcTemplate implements Service {
public ServiceImpl(DataSource dataSource) {
super(dataSource);
}
String sqlQuery="update tab set name=? where id=?";
#Transactional(isolation=Isolation.REPEATABLE_READ)
public void dosth(String name) {
System.out.println("Before waiting, "+Thread.currentThread().getName());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Start, "+Thread.currentThread().getName());
update(sqlQuery, name,1);
System.out.println("Stop,"+Thread.currentThread().getName());
}
#Transactional(isolation=Isolation.REPEATABLE_READ)
public void dosth2(String name) {
System.out.println("Before waiting, "+Thread.currentThread().getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Start, "+Thread.currentThread().getName());
update(sqlQuery, name,1);
System.out.println("Stop, "+Thread.currentThread().getName());
}
}
Main:
public class MainApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("data-tx-jpa.xml");
final Service service = applicationContext.getBean(Service.class);
Runnable runnable1 = new Runnable() {
public void run() {
service.dosth("name1");
}
};
Runnable runnable2 = new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
service.dosth2("name2");
}
};
Thread thread1 = new Thread(runnable1, "thread1");
Thread thread2 = new Thread(runnable2, "thread2");
thread1.start();
thread2.start();
}
}
Logs:
main 2014-01-08 10:34:04,636 INFO [org.springframework.context.support.ClassPathXmlApplicationContext] - <Refreshing org.springframework.context.support.ClassPathXmlApplicationContext#786bb78a: startup date [Wed Jan 08 10:34:04 CET 2014]; root of context hierarchy>
main 2014-01-08 10:34:04,687 INFO [org.springframework.beans.factory.xml.XmlBeanDefinitionReader] - <Loading XML bean definitions from class path resource [data-tx-jpa.xml]>
main 2014-01-08 10:34:04,967 INFO [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer] - <Loading properties file from class path resource [database.properties]>
main 2014-01-08 10:34:04,998 INFO [org.springframework.beans.factory.support.DefaultListableBeanFactory] - <Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#4d8657b9: defining beans [dataSource,transactionManager,org.springframework.aop.config.internalAutoProxyCreator,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0,org.springframework.transaction.interceptor.TransactionInterceptor#0,org.springframework.transaction.config.internalTransactionAdvisor,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,property,service,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy>
main 2014-01-08 10:34:05,080 DEBUG [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] - <Adding transactional method 'dosth2' with attribute: PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ; ''>
thread1 2014-01-08 10:34:05,108 DEBUG [org.springframework.transaction.annotation.AnnotationTransactionAttributeSource] - <Adding transactional method 'dosth' with attribute: PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ; ''>
thread1 2014-01-08 10:34:05,116 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [com.kulig.db_test.ServiceImpl.dosth]: PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ; ''>
thread1 2014-01-08 10:34:05,180 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] for JDBC transaction>
thread1 2014-01-08 10:34:05,188 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Changing isolation level of JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to 4>
thread1 2014-01-08 10:34:05,204 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Switching JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to manual commit>
Before waiting, thread1
thread2 2014-01-08 10:34:06,106 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [com.kulig.db_test.ServiceImpl.dosth2]: PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ; ''>
thread2 2014-01-08 10:34:06,111 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] for JDBC transaction>
thread2 2014-01-08 10:34:06,111 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Changing isolation level of JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to 4>
thread2 2014-01-08 10:34:06,112 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Switching JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to manual commit>
Before waiting, thread2
Start, thread2
thread2 2014-01-08 10:34:11,115 DEBUG [com.kulig.db_test.ServiceImpl] - <Executing prepared SQL update>
thread2 2014-01-08 10:34:11,116 DEBUG [com.kulig.db_test.ServiceImpl] - <Executing prepared SQL statement [update tab set name=? where id=?]>
thread2 2014-01-08 10:34:11,125 DEBUG [com.kulig.db_test.ServiceImpl] - <SQL update affected 1 rows>
Stop, thread2
thread2 2014-01-08 10:34:11,127 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
thread2 2014-01-08 10:34:11,128 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver]>
thread2 2014-01-08 10:34:11,149 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Resetting isolation level of JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to 2>
thread2 2014-01-08 10:34:11,149 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] after transaction>
thread2 2014-01-08 10:34:11,149 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
Start, thread1
thread1 2014-01-08 10:34:15,205 DEBUG [com.kulig.db_test.ServiceImpl] - <Executing prepared SQL update>
thread1 2014-01-08 10:34:15,205 DEBUG [com.kulig.db_test.ServiceImpl] - <Executing prepared SQL statement [update tab set name=? where id=?]>
thread1 2014-01-08 10:34:15,207 DEBUG [com.kulig.db_test.ServiceImpl] - <SQL update affected 1 rows>
Stop,thread1
thread1 2014-01-08 10:34:15,207 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
thread1 2014-01-08 10:34:15,207 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver]>
thread1 2014-01-08 10:34:15,233 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Resetting isolation level of JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] to 2>
thread1 2014-01-08 10:34:15,234 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [jdbc:postgresql://localhost:5432/test, UserName=postgres, PostgreSQL Native Driver] after transaction>
thread1 2014-01-08 10:34:15,234 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
Where is bug? Do I do something wrong or Postgres transaction does not work?
EDIT
This scenerio works properly:
T1 begin -> **T1 select row** ->T2 begin -> T2 update row -> T2 commit -> T1 update the same row -> T1 commit

You are using illegal outside knowledge to say that one transaction begin before the other. The database has fulfilled its obligation as long as there exists a legal ordering of actions which would produce the same end results from the database as the actually produced results. It is not required that this legal ordering match the ordering you think you measured with your stop watch.

I used Wireshark to analyze communication of my java application and PostgreSQL. I noticed that begin of transaction take place before send first query. I thought that transaction begins before start of method with #Transactional annotation. So scenerio:
T1 begin -> T2 begin -> T2 update row -> T2 commit -> T1 update the same row -> T1 commit
is not correct.
Real scenerio which I tested is:
T2 begin -> `T2 update row` -> T2 commit -> T1 begin ->T1 update the same row -> T1 commit
To test first scenerio, some query (select version() for example) should be executed before waiting in transaction T1. This query is necessary to begin a transaction T1 before start of transaction T2. In this scenerio everything is working properly.

Related

Transaction rollback in SSM framework problem

software version :jdk 8 spring 4.0 mybatis-3.2.7.jar mybatis-spring-1.2.2.jar ojdbc6.jar oracle 11g
applicationContext.xml:
<context:property-placeholder location="classpath:jdbc.properties" />
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource"
id="dataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driverClassName}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="appTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="appTransactionManager" />
junit code:
#RunWith(SpringJUnit4ClassRunner.class)
#TransactionConfiguration(transactionManager = "appTransactionManager", defaultRollback = true)
#Transactional(rollbackFor = Exception.class)
#ContextConfiguration("classpath:applicationContext.xml")
public class GenerateJylshTest {
#Test
#Rollback(true)
public void generateJylshTest() {
String jyjgbh = "4201000000";
GenerateJylsh generator = new GenerateJylsh();
int i;
for(i = 0;i < 3;i++) {
String jylshString = generator.generateJylsh(jyjgbh);
System.out.println(jylshString);
}
int k = 1/0;
}
}
console result:
Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
JDBC Connection [oracle.jdbc.driver.T4CConnection#172b013] will be managed by Spring
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800027
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800028(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800028
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800028
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800029(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800029
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: SELECT * FROM BIZ_VEH_IS_TEMP_FLOWNUM t WHERE t.JCZ = ? AND t.JCXDM = ?
==> Parameters: 4201000000(String), 42010000001(String)
<== Columns: JCZ, JCXDM, LSH
<== Row: 4201000000, 42010000001, 01000019110800029
<== Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306] from current transaction
==> Preparing: UPDATE BIZ_VEH_IS_TEMP_FLOWNUM SET LSH = ? WHERE JCZ = ? AND JCXDM = ?
==> Parameters: 01000019110800030(String), 4201000000(String), 42010000001(String)
<== Updates: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
01000019110800030
Transaction synchronization rolling back SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession#c7ba306]
2019-11-08 16:31:09 [main] - [ INFO ] Rolled back transaction after test execution for test context [DefaultTestContext#f316aeb testClass = GenerateJylshTest, testInstance = test.GenerateJylshTest#6aa3a905, testMethod = generateJylshTest#GenerateJylshTest, testException = java.lang.RuntimeException, mergedContextConfiguration = [MergedContextConfiguration#a22cb6a testClass = GenerateJylshTest, locations = '{classpath:applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]
2019-11-08 16:31:09 [Thread-1] - [ INFO ] Closing org.springframework.context.support.GenericApplicationContext#4667ae56: startup date [Fri Nov 08 16:31:05 CST 2019]; root of context hierarchy
I used to think that this result code
Transaction synchronization rolling back SqlSession
Transaction synchronization closing SqlSession
means the transaction rollback is already done,but the fact is data still update to the oracle database.
So,I want to konw why.Thanks for any help.

Spring integration chain error block process

I'm trying to handle errors using the int:poller, I defined an error-channel on the poller when an error occurs the ErrorHandler invoked, but it still executed in a loop and
block the principal process that handle the next correct message.
Here's my config any ideas?
<int:outbound-channel-adapter ref="cvsMessageHandler" method="handleMessage" channel="cvsInputChannel"/>
<int:poller max-messages-per-poll="1" id="defaultPoller" default="true" fixed-rate="5000"
error-channel="cvsErrorChannel">
<int:transactional transaction-manager="transactionManager" />
</int:poller>
<bean id="cvsMessageHandler" class="com.cvs.ws.wrapper.MessageHandler">
</bean>
<int:channel id="cvsErrorChannel"/>
<bean id="cvsErrorMessageHandler" class="com.eplatform.transverse.cvs.ws.service.ErrorHandler">
<property name="eventService" ref="cvsEventService"/>
<property name="eventFactory" ref="cvsEventFactory"/>
</bean>
<int:chain input-channel="cvsErrorChannel">
<int:service-activator ref="cvsErrorMessageHandler" method="handleMessage"/>
</int:chain>
<stream:stderr-channel-adapter channel="errorChannel" append-newline="true"/>
<int:channel id="csdbInputChannel">
<int:queue message-store="messageStore"/>
</int:channel>
<bean id="csdbService" class="com.renault.eplatform.transverse.datapower.csdb.ws.service.CsdbService">
<property name="channel" ref="csdbInputChannel"/>
</bean>
<bean id="csdbWrapper" class="com.renault.eplatform.transverse.datapower.csdb.ws.wrapper.CsdbWrapper">
<property name="httpClient">
<bean class="com.fullsix.framework.net.http.HttpClientFactoryBean"/>
</property>
<property name="url" value="${www}"/>
<property name="enumCountry" ref="currentCountry"/>
<property name="datapowerLoggingService" ref="dxxx"/>
<property name="password" value="${dwwww}"/>
<property name="socketTimeout" value="20000"/>
<property name="timeout" value="20000"/>
</bean>
201803-08 15:34:55,546 ERROR [ErrorHandler.java:28] - Try to fix data
on tables DATAPOWER_CSDB_MESSAGE_GROUP and DATAPOWER_CSDB_MESSAGE
201803-08 15:34:55,547 DEBUG
[AbstractReplyProducingMessageHandler.java:107]
- handler 'ServiceActivator for [org.springframework.integration.handler.MethodInvokingMessageProcessor#4cc7014c]'
produced no reply for request Message:
[Payload=java.lang.NullPointerException][Headers={timestamp=1520519695543,
id=b71d066b-a8e5-4fa3-8b87-a8c1d9e57587}]
201803-08 15:34:55,547
DEBUG [AbstractMessageChannel.java:237] - postSend (sent=true) on
channel 'csdbErrorChannel', message:
[Payload=java.lang.NullPointerException][Headers={timestamp=1520519695543,
id=b71d066b-a8e5-4fa3-8b87-a8c1d9e57587}]
201803-08 15:35:00,515
DEBUG [AbstractPlatformTransactionManager.java:365] - Creating new
transaction with name
201803-08 15:35:00,516 DEBUG
[SessionImpl.java:265] - opened session at timestamp: 15205197005
201803-08 15:35:00,517 DEBUG [HibernateTransactionManager.java:493] -
Opened new Session [org.hibernate.impl.SessionImpl#7e350225] for
Hibernate transaction
201803-08 15:35:00,517 DEBUG
[HibernateTransactionManager.java:504] - Preparing JDBC Connection of
Hibernate Session [org.hibernate.impl.SessionImpl#7e350225]
201803-08
15:35:00,517 DEBUG [JDBCTransaction.java:78] - begin
201803-08
15:35:00,518 DEBUG [ConnectionManager.java:444] - opening JDBC
connection
201803-08 15:35:00,518 DEBUG [JDBCTransaction.java:83] -
current autocommit status: true
201803-08 15:35:00,519 DEBUG
[JDBCTransaction.java:86] - disabling autocommit
201803-08
15:35:00,519 DEBUG [HibernateTransactionManager.java:569] - Exposing
Hibernate transaction as JDBC transaction
[jdbc:oracle:thin:#//active-db-valid:1521/rsite, UserName=RSITE_ES,
Oracle JDBC driver]
201803-08 15:35:00,520 DEBUG
[JdbcTemplate.java:635] - Executing prepared SQL query
201803-08
15:35:00,520 DEBUG [JdbcTemplate.java:570] - Executing prepared SQL
statement [SELECT COUNT(MESSAGE_ID) from DATAPOWER_CSDB_MESSAGE_GROUP
where GROUP_KEY=? AND REGION=?]
201803-08 15:35:00,523 DEBUG
[JdbcTemplate.java:635] - Executing prepared SQL query
201803-08
15:35:00,523 DEBUG [JdbcTemplate.java:570] - Executing prepared SQL
statement [SELECT MESSAGE_ID, CREATED_DATE from
DATAPOWER_CSDB_MESSAGE_GROUP where GROUP_KEY=? and REGION=? order by
UPDATED_DATE]
201803-08 15:35:00,525 DEBUG [JdbcTemplate.java:635] -
Executing prepared SQL query
201803-08 15:35:00,526 DEBUG
[JdbcTemplate.java:570] - Executing prepared SQL statement [SELECT
MESSAGE_ID, CREATED_DATE, MESSAGE_BYTES from DATAPOWER_CSDB_MESSAGE
where MESSAGE_ID=? and REGION=?]
201803-08 15:35:00,528 DEBUG
[DefaultLobHandler.java:117] - Returning BLOB as bytes
201803-08
15:35:00,529 DEBUG [AbstractPlatformTransactionManager.java:843] -
Initiating transaction rollback
201803-08 15:35:00,529 DEBUG
[HibernateTransactionManager.java:672] - Rolling back Hibernate
transaction on Session [org.hibernate.impl.SessionImpl#7e350225]
201803-08 15:35:00,530 DEBUG [JDBCTransaction.java:182] - rollback
201803-08 15:35:00,531 DEBUG [JDBCTransaction.java:223] - re-enabling
autocommit
201803-08 15:35:00,531 DEBUG [JDBCTransaction.java:193] -
rolled back JDBC Connection
201803-08 15:35:00,531 DEBUG
[ConnectionManager.java:325] - transaction completed on session with
on_close connection release mode; be sure to close the session to
release JDBC resources!
201803-08 15:35:00,532 DEBUG
[HibernateTransactionManager.java:734] - Closing Hibernate Session
[org.hibernate.impl.SessionImpl#7e350225] after transaction
201803-08
15:35:00,532 DEBUG [SessionFactoryUtils.java:800] - Closing Hibernate
Session
201803-08 15:35:00,533 DEBUG [ConnectionManager.java:464] -
releasing JDBC connection [ (open PreparedStatements: 0, globally: 0)
(open ResultSets: 0, globally: 0)]
201803-08 15:35:00,533 DEBUG
[ConnectionManager.java:325] - transaction completed on session with
on_close connection release mode; be sure to close the session to
release JDBC resources!
201803-08 15:35:00,534 DEBUG
[AbstractMessageChannel.java:224] - preSend on channel
'csdbErrorChannel', message:
[Payload=java.lang.NullPointerException][Headers={timestamp=1520519700534,
id=fe974a6c-2351-4b95-ac6f-b98a0c02a7b3}]
201803-08 15:35:00,534
DEBUG [AbstractMessageHandler.java:67] -
org.springframework.integration.handler.MessageHandlerChain#0 received
message:
[Payload=java.lang.NullPointerException][Headers={timestamp=1520519700534,
id=fe974a6c-2351-4b95-ac6f-b98a0c02a7b3}]
201803-08 15:35:00,535
DEBUG [AbstractMessageHandler.java:67] - ServiceActivator for
[org.springframework.integration.handler.MethodInvokingMessageProcessor#4cc7014c]
received message:
[Payload=java.lang.NullPointerException][Headers={timestamp=1520519700534,
id=fe974a6c-2351-4b95-ac6f-b98a0c02a7b3}]
201803-08 15:35:00,535
INFO [ErrorHandler.java:25] - Error message handled
201803-08
15:35:00,536 ERROR [ErrorHandler.java:27] -
java.lang.NullPointerException
201803-08 15:35:00,536 ERROR
[ErrorHandler.java:28] - Try to fix data on tables
DATAPOWER_CSDB_MESSAGE_GROUP and DATAPOWER_CSDB_MESSAGE*
*

JdbcTemplate query close database connection

I use jpa with hibernate. I have following method:
#Transactional
public void myMethod(){
...
firstJDBCTemplateQuery();
secondJDBCTemplateQuery();
...
}
firstJDBCTemplateQuery works, but it closes connection to database. When second secondJDBCTempolateQuery is executed
java.sql.SQLException: Connection is closed exception
is thrown what causes
org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction ...
My configuration:
EDIT
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="packagesToScan" value="com.emisoft.ami.user.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.max_fetch_depth">3</prop>
<prop key="hibernate.jdbc.fetch_size">50</prop>
<prop key="hibernate.jdbc.batch_size">10</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<jpa:repositories base-package="com.emisoft.ami.user.repository"
entity-manager-factory-ref="emf" transaction-manager-ref="transactionManager" />
...
I don't know why 'firstJDBCTemplateQuery' close db connection. How to resolve this problem?
StackTrace:
org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is java.sql.SQLException: Connection is closed.
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:296)
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:320)
at org.springframework.jdbc.support.SQLErrorCodesFactory.getErrorCodes(SQLErrorCodesFactory.java:214)
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.setDataSource(SQLErrorCodeSQLExceptionTranslator.java:140)
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.<init>(SQLErrorCodeSQLExceptionTranslator.java:103)
at org.springframework.jdbc.support.JdbcAccessor.getExceptionTranslator(JdbcAccessor.java:99)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:639)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:668)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:676)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:731)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:747)
at org.springframework.jdbc.core.JdbcTemplate.queryForInt(JdbcTemplate.java:782)
at org.springframework.security.provisioning.JdbcUserDetailsManager.findGroupId(JdbcUserDetailsManager.java:373)
at org.springframework.security.provisioning.JdbcUserDetailsManager.addUserToGroup(JdbcUserDetailsManager.java:301)
//////////////////////////////////////////////////This is secondJDBCTemplateQuery///////////
at com.emisoft.ami.user.service.impl.UserServiceImpl.insert(UserServiceImpl.java:42)
///////////////////////////////////////////////////////////////////////////////////////////
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy46.insert(Unknown Source)
at com.kulig.test.service.PaymentServiceContext.main(PaymentServiceContext.java:28)
Caused by: java.sql.SQLException: Connection is closed.
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.checkOpen(PoolingDataSource.java:185)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.getMetaData(PoolingDataSource.java:244)
at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:285)
... 29 more
DEBUG: org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator - Unable to translate SQLException with Error code '0', will now try the fallback translator
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Initiating transaction rollback
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Rolling back JPA transaction on EntityManager [org.hibernate.ejb.EntityManagerImpl#76c741]
DEBUG: org.hibernate.engine.transaction.spi.AbstractTransactionImpl - rolling back
DEBUG: org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - re-enabling autocommit
DEBUG: org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - Could not toggle autocommit
java.sql.SQLException: Connection is closed.
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.checkOpen(PoolingDataSource.java:185)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.setAutoCommit(PoolingDataSource.java:327)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.releaseManagedConnection(JdbcTransaction.java:127)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doRollback(JdbcTransaction.java:170)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:209)
at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:106)
at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:539)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:846)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:823)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:493)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:264)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy46.insert(Unknown Source)
at com.kulig.test.service.PaymentServiceContext.main(PaymentServiceContext.java:28)
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [org.hibernate.ejb.EntityManagerImpl#76c741] after transaction
DEBUG: org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Releasing JDBC connection
DEBUG: org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Released JDBC connection
ERROR: org.springframework.transaction.interceptor.TransactionInterceptor - Application exception overridden by rollback exception
org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [select id from groups where group_name = ?]; SQL state [null]; error code [0]; Connection is closed.; nested exception is java.sql.SQLException: Connection is closed.
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:639)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:668)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:676)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:731)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:747)
at org.springframework.jdbc.core.JdbcTemplate.queryForInt(JdbcTemplate.java:782)
at org.springframework.security.provisioning.JdbcUserDetailsManager.findGroupId(JdbcUserDetailsManager.java:373)
at org.springframework.security.provisioning.JdbcUserDetailsManager.addUserToGroup(JdbcUserDetailsManager.java:301)
at com.emisoft.ami.user.service.impl.UserServiceImpl.insert(UserServiceImpl.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:96)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:260)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy46.insert(Unknown Source)
at com.kulig.test.service.PaymentServiceContext.main(PaymentServiceContext.java:28)
Caused by: java.sql.SQLException: Connection is closed.
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.checkOpen(PoolingDataSource.java:185)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:312)
at org.springframework.jdbc.core.JdbcTemplate$SimplePreparedStatementCreator.createPreparedStatement(JdbcTemplate.java:1446)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:583)
... 23 more
Exception in thread "main" org.springframework.transaction.TransactionSystemException: Could not roll back JPA transaction; nested exception is javax.persistence.PersistenceException: unexpected error when rollbacking
at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:543)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:846)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:823)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:493)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:264)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:94)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy46.insert(Unknown Source)
at com.kulig.test.service.PaymentServiceContext.main(PaymentServiceContext.java:28)
Caused by: javax.persistence.PersistenceException: unexpected error when rollbacking
at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:109)
at org.springframework.orm.jpa.JpaTransactionManager.doRollback(JpaTransactionManager.java:539)
... 9 more
Caused by: org.hibernate.TransactionException: rollback failed
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:215)
at org.hibernate.ejb.TransactionImpl.rollback(TransactionImpl.java:106)
... 10 more
Caused by: org.hibernate.TransactionException: unable to rollback against JDBC connection
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doRollback(JdbcTransaction.java:167)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:209)
... 11 more
Caused by: java.sql.SQLException: Connection is closed.
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.checkOpen(PoolingDataSource.java:185)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.rollback(PoolingDataSource.java:322)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doRollback(JdbcTransaction.java:163)
... 12 more
EDIT
I checked secondJDBCTemplateQuery in stacktrace.
EDIT
I use org.springframework.security.provisioning.JdbcUserDetailsManager
firstJDBCTemplateQuery is createUser(UserDetails user)
secondJDBCTemplateQuery is addUserToGroup(String username, String groupName)
public void createUser(final UserDetails user) {
validateUserDetails(user);
getJdbcTemplate().update(createUserSql, new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
ps.setString(1, user.getUsername());
ps.setString(2, user.getPassword());
ps.setBoolean(3, user.isEnabled());
}
});
if (getEnableAuthorities()) {
insertUserAuthorities(user);
}
}
public void addUserToGroup(final String username, final String groupName) {
logger.debug("Adding user '" + username + "' to group '" + groupName + "'");
Assert.hasText(username);
Assert.hasText(groupName);
final int id = findGroupId(groupName);
getJdbcTemplate().update(insertGroupMemberSql, new PreparedStatementSetter() {
public void setValues(PreparedStatement ps) throws SQLException {
ps.setInt(1, id);
ps.setString(2, username);
}
});
userCache.removeUserFromCache(username);
}
EDIT DEBUG RESULT:
Beigin transaction on startup myMethod():
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Creating new transaction with name [com.emisoft.ami.user.service.impl.UserServiceImpl.insert]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Opened new EntityManager [org.hibernate.ejb.EntityManagerImpl#b18ac9] for JPA transaction
DEBUG: org.hibernate.engine.transaction.spi.AbstractTransactionImpl - begin
DEBUG: org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Obtaining JDBC connection
DEBUG: org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Obtained JDBC connection
DEBUG: org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - initial autocommit status: true
DEBUG: org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - disabling autocommit
DEBUG: org.springframework.orm.jpa.JpaTransactionManager - Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#940dc4]
//////////////////////////////////
firstJDBCTemplateMethod:
//////////////////////////////////
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL update
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL statement [insert into users (username, password, enabled) values (?,?,?)]
DEBUG: org.springframework.jdbc.core.JdbcTemplate - SQL update affected 1 rows
/////////////////////////////////////////
secondJDBCTemplateMethod:
////////////////////////////////////
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL query
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL statement [select id from groups where group_name = ?]
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
INFO : org.springframework.jdbc.support.SQLErrorCodesFactory - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
DEBUG: org.springframework.jdbc.support.SQLErrorCodesFactory - Looking up default SQLErrorCodes for DataSource [org.apache.commons.dbcp.BasicDataSource#150f6f]
WARN : org.springframework.jdbc.support.SQLErrorCodesFactory - Error while extracting database product name - falling back to empty error codes
org.springframework.jdbc.support.MetaDataAccessException: Error while extracting DatabaseMetaData; nested exception is java.sql.SQLException: Connection is closed. ///This is the beginning of stacktrace which is located above.
EDIT
PaymentServiceContext :
public class PaymentServiceContext {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"com/kulig/test/service/PaymentServiceTest-context.xml");
UserService userService = context.getBean(UserService.class);
///CREATE POJO OBJECTS credentials and p
...
userService.insert(credentials, p);
}
}
Actually, I have had that same issue recently...
After debugging trough the Hibernate code, I noticed Hibernate 4 calls HibernateJpaDialect.releaseConnection at some point. Comments before suggest that it's only to release the connection, but not to close it since it's the connection used by the transactional context. However, that releaseConnection method does in fact call JdbcUtils.closeConnection(con). The HibernateJpaDialect class responsible is actually part of the spring framework, not hibernate.
In the end, this issue is reported by Spring as a bug (SPR-10395) and should be fixed in release 3.2.3 or above. So in the end, you can use Hibernate 4.2 but you'll have to upgrade spring (orm) in that case:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.3</version>
</dependency>
I think that there is a bug in hibernate. I changed
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.2.5.Final</version>
</dependency>
to
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.1.12.Final</version>
</dependency>
and it works.
Comparison of 2 different version of HibernateJpaDialect from spring-orm artifact.
Thanks to #Kevin Chabot for pointing this out:
HibernateJpaDialect (spring-orm ver 3.1.4)
public void releaseConnection(Connection con) {
JdbcUtils.closeConnection(con);
}
HibernateJpaDialect (spring-orm ver 3.2.8)
public void releaseConnection(Connection con) {
if (sessionConnectionMethod != null) {
// Need to explicitly call close() with Hibernate 3.x in order to allow
// for eager release of the underlying physical Connection if necessary.
// However, do not do this on Hibernate 4.2+ since it would return the
// physical Connection to the pool right away, making it unusable for
// further operations within the current transaction!
JdbcUtils.closeConnection(con);
}
}
Switching to spring-orm 3.2.3+ solves this problem. Be careful to include spring-orm in your pom.xml explicitly. The common mistake is when pom.xml contains only spring-data and fetches spring-orm thru transitive dependency from spring-data - and than it may be in wrong version.
First of all make sure that you are using the same DataSource for JPA as for your JdbcTemplate. Next wire the DataSource to the JpaTransactionManager.
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emf" />
<property name="dataSource" ref="dataSource" />
</bean>
This will make the transaction managed by the same transaction manager (you should only have one transaction manage

Spring MVC DataSourceTransactionManager Tomcat Transactions

I'm doing some test with Spring Transaction, this is my configuration:
DAO
#Repository
public class ClienteDaoJdbc implements ClienteDao {
private static final String SQL_INSERT = "INSERT INTO clientes (CodigoCliente,Nombres) "
+ "VALUES (:codigo_cliente,:nombres)";
#Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
public void insertBatch(List<Cliente> clientes) {
Map<String, Object>[] batchValues = new HashMap[clientes.size()];
for (int i = 0; i < batchValues.length; i++) {
Map<String, Object> parametros = new HashMap<String, Object>();
parametros.put("codigo_cliente", clientes.get(i).getCodigoCliente());
parametros.put("nombres", clientes.get(i).getNombres());
batchValues[i] = parametros;
}
this.jdbcTemplate.batchUpdate(SQL_INSERT, batchValues);
}
}
Service
#Service
#Transactional(readOnly=true)
public class ClienteServiceImpl implements ClienteService {
#Autowired
private ClienteDao clienteDao;
#Transactional(readOnly=false,propagation=Propagation.REQUIRES_NEW)
public void register(List<Cliente> clientes) {
this.clienteDao.insertBatch(clientes);
}
}
Spring configuration
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value=""/>
<property name="defaultAutoCommit" value="false"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<constructor-arg ref="dataSource"/>
</bean>
<context:component-scan base-package="com.varas"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<context:annotation-config/>
<tx:annotation-driven/>
When I use this code in a standalone application transaction works perfect, for this purpose I use some code to test this app and I get:
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection#1a10a9a1]]]
DEBUG: org.springframework.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [ProxyConnection[PooledConnection[com.mysql.jdbc.JDBC4Connection#1a10a9a1]]] after transaction
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
Exception in thread "main" org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO clientes (CodigoCliente,Nombres) VALUES (?,?)]; Duplicate entry '0000000007' for key 'PRIMARY'; nested exception is java.sql.BatchUpdateException: Duplicate entry '0000000007' for key 'PRIMARY'
The rollbacking process works, but when I use the same code in a Spring MVC Project spring transaction apparently is not working and the rollback process never happen
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing SQL batch update [INSERT INTO clientes (CodigoCliente,Nombres) VALUES (?,?)]
DEBUG: org.springframework.jdbc.core.JdbcTemplate - Executing prepared SQL statement [INSERT INTO clientes (CodigoCliente,Nombres) VALUES (?,?)]
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
DEBUG: org.springframework.jdbc.support.JdbcUtils - JDBC driver supports batch updates
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
INFO : org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [org/springframework/jdbc/support/sql-error-codes.xml]
INFO : org.springframework.jdbc.support.SQLErrorCodesFactory - SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase]
DEBUG: org.springframework.jdbc.support.SQLErrorCodesFactory - Looking up default SQLErrorCodes for DataSource [org.apache.tomcat.jdbc.pool.DataSource#3291ea21{ConnectionPool[defaultAutoCommit=false; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=100; minIdle=10; initialSize=10; maxWait=30000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=********; url=jdbc:mysql://localhost:3306/test; username=root; validationQuery=null; validatorClassName=null; validationInterval=30000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; }]
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource
DEBUG: org.springframework.jdbc.datasource.DataSourceUtils - Returning JDBC Connection to DataSource
DEBUG: org.springframework.jdbc.support.SQLErrorCodesFactory - Database product name cached for DataSource [org.apache.tomcat.jdbc.pool.DataSource#3291ea21]: name is 'MySQL'
DEBUG: org.springframework.jdbc.support.SQLErrorCodesFactory - SQL error codes for 'MySQL' found
DEBUG: org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator - Translating SQLException with SQL state '23000', error code '1062', message [Duplicate entry '0000000007' for key 'PRIMARY']; SQL was [INSERT INTO clientes (CodigoCliente,Nombres) VALUES (?,?)] for task [PreparedStatementCallback]
jul 23, 2013 9:15:57 AM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: El Servlet.service() para el servlet [appServlet] en el contexto con ruta [/comercial] lanz? la excepci?n [Request processing failed; nested exception is org.springframework.dao.DuplicateKeyException: PreparedStatementCallback; SQL [INSERT INTO clientes (CodigoCliente,Nombres) VALUES (?,?)]; Duplicate entry '0000000007' for key 'PRIMARY'; nested exception is java.sql.BatchUpdateException: Duplicate entry '0000000007' for key 'PRIMARY'] con causa ra?z
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '0000000007' for key 'PRIMARY'
I dont know Why Spring Transaction is not working in this case, in a We App environment?
Thanks in advance for your response.

Spring JMS Oracle AQ Too many transactions

I have created a basic Spring applicatin to read from Oracle AQ. I am experiencing following issues. Kindly help me on this
1)- Messages placed on the queue (by PL/SQL code) prior to starting of my spring application are not dequeued by it.
2)- A message that is successfull read from the queue should be removed from the queue. This is not happening. All messages remain in Queue Table.
3)- Once a message is read, the process goes in block/waiting state, as shown by the log below, if any message is place on queue during that period, that message is ignored. It is taking 30 - 40 secs to commit the transaction
2012-02-08 13:26:37,700 DEBUG [org.springframework.data.jdbc.jms.listener.oracle.AdtMessageListenerContainer] - <Received message of type [class oracle.jms.AQjmsAdtMessage] from consumer [oracle.jms.AQjmsConsumer#1989b5] of transactional session [oracle.jms.AQjmsSession#189c036]>
2012-02-08 13:26:37,700 DEBUG [org.springframework.data.jdbc.support.oracle.BeanPropertyStructMapper] - <Mapping column 'id' to property 'id' of type class java.math.BigDecimal>
2012-02-08 13:26:37,700 DEBUG [org.springframework.data.jdbc.support.oracle.BeanPropertyStructMapper] - <Mapping column 'type_cd' to property 'type_cd' of type class java.lang.String>
2012-02-08 13:26:37,700 INFO [com.test.oracle.aq.ProductDelegate] - <Product [id=6, type_cd=Test Product Code]>
2012-02-08 13:26:37,715 DEBUG [org.springframework.jdbc.core.JdbcTemplate] - <Executing SQL update [INSERT INTO Product(id, type_cd) values(6, 'Test Product Code')]>
2012-02-08 13:26:37,731 DEBUG [org.springframework.jdbc.core.JdbcTemplate] - <SQL update affected 1 rows>
2012-02-08 13:26:57,295 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
2012-02-08 13:26:57,295 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [oracle.jdbc.driver.T4CConnection#1860038]>
2012-02-08 13:26:57,295 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [oracle.jdbc.driver.T4CConnection#1860038] after transaction>
2012-02-08 13:26:57,295 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
4)- Why it is making soo many tansactions? While waiting on queue
2012-02-08 13:22:58,937 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [org.springframework.data.jdbc.jms.listener.oracle.AdtMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT>
2012-02-08 13:22:59,000 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [oracle.jdbc.driver.T4CConnection#9b688e] for JDBC transaction>
2012-02-08 13:22:59,000 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Switching JDBC Connection [oracle.jdbc.driver.T4CConnection#9b688e] to manual commit>
2012-02-08 13:23:00,045 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
2012-02-08 13:23:00,045 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [oracle.jdbc.driver.T4CConnection#9b688e]>
2012-02-08 13:23:00,061 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [oracle.jdbc.driver.T4CConnection#9b688e] after transaction>
2012-02-08 13:23:00,061 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
2012-02-08 13:23:00,061 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [org.springframework.data.jdbc.jms.listener.oracle.AdtMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT>
2012-02-08 13:23:00,093 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [oracle.jdbc.driver.T4CConnection#eca36e] for JDBC transaction>
2012-02-08 13:23:00,093 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Switching JDBC Connection [oracle.jdbc.driver.T4CConnection#eca36e] to manual commit>
2012-02-08 13:23:01,154 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
2012-02-08 13:23:01,154 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [oracle.jdbc.driver.T4CConnection#eca36e]>
2012-02-08 13:23:01,155 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [oracle.jdbc.driver.T4CConnection#eca36e] after transaction>
2012-02-08 13:23:01,155 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
2012-02-08 13:23:01,155 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [org.springframework.data.jdbc.jms.listener.oracle.AdtMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT>
2012-02-08 13:23:01,202 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [oracle.jdbc.driver.T4CConnection#19b4748] for JDBC transaction>
2012-02-08 13:23:01,202 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Switching JDBC Connection [oracle.jdbc.driver.T4CConnection#19b4748] to manual commit>
2012-02-08 13:23:02,263 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Initiating transaction commit>
2012-02-08 13:23:02,263 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Committing JDBC transaction on Connection [oracle.jdbc.driver.T4CConnection#19b4748]>
2012-02-08 13:23:02,278 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Releasing JDBC Connection [oracle.jdbc.driver.T4CConnection#19b4748] after transaction>
2012-02-08 13:23:02,278 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
2012-02-08 13:23:02,278 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Creating new transaction with name [org.springframework.data.jdbc.jms.listener.oracle.AdtMessageListenerContainer#0]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT>
2012-02-08 13:23:02,311 DEBUG [org.springframework.jdbc.datasource.DataSourceTransactionManager] - <Acquired Connection [oracle.jdbc.driver.T4CConnection#1a41cc7] for JDBC transaction>
Below are my spring config
<bean id="dataSource" class="oracle.jdbc.pool.OracleConnectionPoolDataSource">
<property name="URL" value="jdbc:oracle:thin:#//localhost:1521/XE" />
<property name="user" value="migration" />
<property name="password" value="password" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
lazy-init="true">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="messageDelegate" class="com.test.oracle.aq.ProductDelegate" />
<jms:listener-container connection-factory="connectionFactory"
transaction-manager="transactionManager"
message-converter="messageConverter"
container-class="org.springframework.data.jdbc.jms.listener.oracle.AdtMessageListenerContainer" destination-type="topic">
<jms:listener destination="MIGRATION.PRODUCT_QUEUE" ref="messageDelegate" method="handleMessage" />
</jms:listener-container>
<bean id="messageConverter"
class="org.springframework.data.jdbc.jms.support.converter.oracle.MappingAdtMessageConverter">
<constructor-arg>
<bean class="org.springframework.data.jdbc.jms.support.oracle.StructDatumMapper">
<constructor-arg index="0" value="MIGRATION.PRODUCT_T"/>
<constructor-arg index="1" value="com.test.oracle.aq.Product"/>
</bean>
</constructor-arg>
</bean>
<orcl:aq-jms-connection-factory id="connectionFactory" data-source="dataSource"/>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="sessionTransacted" value="true"/>
</bean>

Resources