-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 
Author Message
 Post subject: transaction trouble mixing Hibernate and plain JDBC
PostPosted: Wed Dec 07, 2005 5:14 pm 
Newbie

Joined: Wed Dec 07, 2005 4:43 pm
Posts: 1
I have used Hibernate successfully in past projects, but now I am trying to integrate Hiberante with a legacy system that uses JDBC. The intent is to gradually replace the plain JDBC code with Hibernate persistence, but the two will have to coexist for some period of time.

To that end, I want the Hibernate and JDBC code to share the same transaction, with errors in one forcing a rollback in the other. I am using Spring to manage all the code, but am having a problem where I create an object in Hibernate, but when I try to reference that same object for another insert operation in the plain JDBC code, I get an constraint violation because the newly created has not yet been committed to the database.

Here is my Spring configuration:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

    <!--====================-->
    <!-- Hibernate Settings -->
    <!--====================-->

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="org.postgresql.Driver"/>
        <property name="url" value="jdbc:postgresql://localhost:5432/test1"/>
        <property name="username" value="*****"/>
        <property name="password" value="*****"/>
    </bean>

    <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mappingResources">
            <list>
                <value>com/edusoft/model/Test.hbm.xml</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
                <prop key="hibernate.query.substitutions">true 1, false 0</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.use_sql_comments">true</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!--==============-->
    <!-- DAO Mappings -->
    <!--==============-->

    <bean name="testDAO" class="com.edusoft.model.dao.TestDAOHibernateImpl">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!--========================-->
    <!-- Service Layer Mappings -->
    <!--========================-->

    <bean name="testServiceTarget" class="com.edusoft.service.TestServiceImpl">
        <property name="testDAO" ref="testDAO"/>
    </bean>

    <bean id="testService"
          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager"><ref bean="transactionManager"/></property>
        <property name="target"><ref bean="testServiceTarget"/></property>
        <property name="transactionAttributes">
            <props>
                <prop key="getTest">PROPAGATION_SUPPORTS,readOnly</prop>
                <prop key="getAllTests">PROPAGATION_SUPPORTS,readOnly</prop>
                <prop key="insertTest">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

    <!-- This is the plain JDBC service -->
    <bean name="questionServiceTarget" class="com.edusoft.service.QuestionServiceImpl">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="questionService"
          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager"><ref bean="transactionManager"/></property>
        <property name="target"><ref bean="questionServiceTarget"/></property>
        <property name="transactionAttributes">
            <props>
                <prop key="addQuestion">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>

</beans>

I should also note that I am explicitly starting a transaction with a Servlet filter at the beginning of the request to enforce the transactional scope to be over the entire request, and committing or rolling back at the end of the request. Thus, the session will not flush until the whole request is done. The doFilter() method looks something like this:

Code:
// start a transaction, using Spring transaction manager
PlatformTransactionManager txManager = (PlatformTransactionManager) this.context.getBean("transactionManager");
DefaultTransactionDefinition txDefinition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus tx = txManager.getTransaction(txDefinition);
try {
    // now actually do something
    filterChain.doFilter(request,response);
} finally {
    // commit transaction and close everything down
    if (tx.isRollbackOnly()) {
        txManager.rollback(tx);
    } else {
        txManager.commit(tx);
    }
}

I have a Spring controller object that does something like this:

Code:
Test test = (Test) command;
TestService service = getTestService();
Test result = service.insertTest(test);
// result contains the new object ID
QuestionService questionService = getQuestionService();
Question question = new Question("This is a sample question","This is the sample answer");
questionService.addQuestion(result,question);

When I get to the following code in QuestionService (the plain JDBC one)..

Code:
String text = question.getText();
String answer = question.getAnswer();
String testID = test.getId();

JdbcTemplate jt = new JdbcTemplate(getDataSource());
String newID = (String) jt.queryForObject("select nextval ('object_id_seq')",String.class);
String query = "insert into question(id,text,answer,test_id) values ('" + newID + "','" + text + "','" + answer + "','" + testID + "')";
jt.execute(query);

I get the following (totally understandable) exception:

Code:
org.springframework.dao.DataIntegrityViolationException: StatementCallback; SQL [insert into question(id,text,answer,test_id) values ('133','This is a sample question','This is the sample answer','132')]; ERROR: insert or update on table "question" violates foreign key constraint "fk_question_test_id"

My questions is: is it possible to do what I want to do? Namely, to share a transaction across Hibernate and JDBC code such that an object created in one is visibile to the other? I thought that with the above Spring configuration I would be sharing the same connection and transaction, but now I am not so sure. I have pured over the Spring and Hibernate docs, but have not anything that sheds any light. Any help is appreciated.

thanks.
--Deryl

Hibernate version: 3.0.5

Name and version of the database you are using: PostgreSQL 8.1


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 1 post ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.