ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Young, Alistair" <alistair.yo...@logica.com>
Subject RE: iBATIS caching / transaction isolation question
Date Mon, 12 Jan 2009 16:36:20 GMT
Many thanks for the reply, Clinton - but sadly this doesn't seem to fix the problem.  My understanding
was that readonly need only be set to "false" if a thread is likely to change the contents
of the returned object - this is not the case in my example application (indeed, the returned
object is a String).

I've appended my code and iBATIS configuration files below - I'd appreciate it if you could
tell me if I'm doing anything obviously wrong.  My understanding was that a SqlMapClient object
could safely be used from multiple threads (and that it would handle the caching appropriately).

Thanks,


Alistair.

IBatisTest.java:
------------------------------------------------------------
package test;

public class IBatisTest implements Runnable {

    private SqlMapClient sql;
    
    public IBatisTest() throws Exception {
        // create the SQL map
        Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
        this.sql = SqlMapClientBuilder.buildSqlMapClient(reader);
    }
    
    public void runTest() throws Exception {
        
        this.sql.startTransaction();

        String value = (String)this.sql.queryForObject("db.getValue");
        System.out.println("Value is " + value); // "1"
        
        this.sql.update("db.updateValue", "2");

        value = (String)this.sql.queryForObject("db.getValue");
        System.out.println("Value is " + value);  // "2"
        
        // start the other thread
        new Thread(this).start();
        
        // wait for a bit
        Thread.sleep(2000);

        // roll back the transaction        
        this.sql.endTransaction();
        
        value = (String)this.sql.queryForObject("db.getValue");
        System.out.println("Value is " + value); // "2" (expecting "1")
    }
    
    // second thread
    public void run() {
        try {
            String value = (String)this.sql.queryForObject("db.getValue");
            System.out.println("    Value is " + value); // "2" (expecting "1")
        } catch (Exception x) {
            throw new RuntimeException(x);
        }
    }

    public static void main(String[] args) throws Exception {
        new IBatisTest().runTest();
    }

}
------------------------------------------------------------

SqlMapConfig.xml:
------------------------------------------------------------
<?xml version="1.0" encoding="windows-1252" ?>

<!DOCTYPE sqlMapConfig
    PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
    "sql-map-config-2.dtd">
    
<sqlMapConfig>

    <settings
        useStatementNamespaces="true"
        lazyLoadingEnabled="true"
        enhancementEnabled="true"
        statementCachingEnabled="false" />

    <transactionManager type="JDBC">
    
        <dataSource type="SIMPLE">
            <property name="JDBC.Driver" value="oracle.jdbc.OracleDriver"/>
            <property name="JDBC.ConnectionURL" value="..."/>
            <property name="JDBC.Username" value="..."/>
            <property name="JDBC.Password" value="..."/>
        </dataSource>
        
    </transactionManager>
    
    <!-- at least one SQL Map is required for this to be a
         valid configuration file -->
    <sqlMap resource="SqlMap.xml"/>
    
</sqlMapConfig>
------------------------------------------------------------
 
and SqlMap.xml:
------------------------------------------------------------
<?xml version="1.0" encoding="windows-1252" ?>

<!DOCTYPE sqlMap
    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
    "sql-map-2.dtd">
    
<sqlMap namespace="db">

    <cacheModel id="cache" type="FIFO" readOnly="false" serialize="true">
        <flushOnExecute statement="db.updateValue"/>
        <property name="size" value="10"/>
    </cacheModel>

    <insert id="updateValue" parameterClass="String">
        update VALUES set VALUE=#value# where ID=1
    </insert>
    
    <select id="getValue" resultClass="String" cacheModel="cache">
        select VALUE from VALUES where ID=1
    </select>
        
</sqlMap>
------------------------------------------------------------

-----Original Message-----
From: Clinton Begin [mailto:clinton.begin@gmail.com] 
Sent: 12 January 2009 15:23
To: user-java@ibatis.apache.org
Subject: Re: iBATIS caching / transaction isolation question

The uncommitted data would be seen by thread B as you expect, *if* the cache is configured
as read-only.

To stop this problem, set the cache to read/write and serializable.
Sorry for the confusing configuration here.

Clinton

On 1/12/09, Young, Alistair <alistair.young@logica.com> wrote:
> Apologies for following up my own post...
>
> I carried out a simple test and found that transaction isolation is 
> not maintained.  Also, the cache is not flushed in the event of a 
> transaction being rolled back.
>
> The sequence of events was:
>
> Thread A: start transaction
> Thread A: select value ("1" is returned) Thread A: update value to "2"
> Thread A: select value ("2" is returned)
>
>         Thread B: select value ("2" is returned - not "1")
>
> Thread A: rollback transaction
> Thread A: select value ("2" is returned - not "1")
>
> Is this the expected behaviour?
>
> If not, what might I be doing wrong?  If so, how do people deal with 
> this behaviour?
>
> Thanks for any advice,
>
>
> Alistair.
>
> ________________________________
>
> From: Young, Alistair
> Sent: 12 January 2009 10:54
> To: user-java@ibatis.apache.org
> Subject: iBATIS caching / transaction isolation question
>
>
> Hello all,
>
> I wonder if somebody could clarify for me how iBATIS caching works 
> with regards to transaction isolation.
>
> Suppose I have a cache set up with is used when a "selectAllItems"
> statement is invoked, and flushed when an "updateItem" statement is 
> invoked.
>
> Suppose then that thread A starts a transaction, invokes updateItem 
> and then selectAllItems.  Then, before thread A completes the 
> transaction, thread B invokes selectAllItems.
>
> Is transaction isolation maintained, or does thread B end up seeing 
> the
> (uncommitted) data that thread A has updated?
>
> I should add that I haven't actually tried this yet - but I'd like to 
> know what the expected behaviour is before getting stuck in.
>
> In our particular use case, we're making use of a custom 
> TransactionConfig (which is essentially the same as "EXTERNAL" but 
> handles connection creation slightly differently).  And we're not 
> making any explicit calls to the iBATIS transaction methods.
>
> Many thanks!
>
>
> Alistair.
>
>
>
>
> Please help Logica to respect the environment by not printing this 
> email  / Merci d'aider Logica à préserver l'environnement en évitant 
> d'imprimer ce mail /  Bitte drucken Sie diese Nachricht nicht aus und 
> helfen Sie so Logica dabei die Umwelt zu schuetzen  /  Por favor ajude 
> a Logica a respeitar o ambiente não imprimindo este correio electrónico.
>
>
>
> This e-mail and any attachment is for authorised use by the intended
> recipient(s) only. It may contain proprietary material, confidential 
> information and/or be subject to legal privilege. It should not be 
> copied, disclosed to, retained or used by, any other party. If you are 
> not an intended recipient then please promptly delete this e-mail and 
> any attachment and all copies and inform the sender. Thank you.
>
>

--
Sent from my mobile device


Please help Logica to respect the environment by not printing this email  /  Merci d'aider
Logica à préserver l'environnement en évitant d'imprimer ce mail /  Bitte drucken Sie diese
Nachricht nicht aus und helfen Sie so Logica dabei die Umwelt zu schuetzen  /  Por favor ajude
a Logica a respeitar o ambiente não imprimindo este correio electrónico.



This e-mail and any attachment is for authorised use by the intended recipient(s) only. It
may contain proprietary material, confidential information and/or be subject to legal privilege.
It should not be copied, disclosed to, retained or used by, any other party. If you are not
an intended recipient then please promptly delete this e-mail and any attachment and all copies
and inform the sender. Thank you.



Mime
View raw message