ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Clinton Begin <clinton.be...@gmail.com>
Subject Re: iBATIS caching / transaction isolation question
Date Tue, 20 Jan 2009 05:24:43 GMT
That's a fair assumption.  FWIW:  iBATIS 3 will have a transactional cache.
It might not catch every case, but it will catch most, and can be unit
tested to ensure that it behaves as intended.

Clinton

On Mon, Jan 19, 2009 at 2:22 AM, Young, Alistair
<alistair.young@logica.com>wrote:

> Me again... :)
>
> I was having a think about this over the weekend and realized that the
> behaviour I'm after would be very difficult to implement (and possibly very
> inefficient), so perhaps iBATIS does NOT behave in this way.
>
> It struck me that, if iBATIS were maintaining multiple caches AND paying
> attention to transaction boundaries the cache flushing logic would become
> very complex.  For example, if thread A executed an 'update', iBATIS would
> have to flush the corresponding cache for that thread only.  If the
> transaction were later rolled back, iBATIS would have to flush that cache
> again.  However, if the transaction were committed, it would have to flush
> all OTHER caches...
>
> So, I've come to the conclusion that the only way to use caching safely is
> to ensure that no cached SELECT statements are executed within transactions
> that may ultimately be rolled back.
>
> I'd appreciate some input from anybody making use of iBATIS caching - is
> this a rule you've had to adhere to?
>
> Cheers,
>
>
> Alistair.
>
> -----Original Message-----
> From: Young, Alistair
> Sent: 15 January 2009 10:31
> To: 'user-java@ibatis.apache.org'
> Subject: RE: iBATIS caching / transaction isolation question
>
> Sorry to rake this up again...  I hope you don't mind if I ask a couple of
> questions about the expected behaviour of iBATIS in this area.
>
> 1. Should different threads, sharing an SqlMapClient object, be seeing the
> SAME cache or DIFFERENT caches?  I would expect the latter (though the
> behaviour I'm seeing suggests the former).
>
> 2. If a transaction is rolled back, should the cache be flushed?  I would
> expect yes but, again, my tests suggest no.
>
> Fundamentally, I'd just like to know whether I'm mis-using iBATIS, or
> whether I'm going to need to manage the caching myself (custom
> CacheController?) if I want things to behave as above.
>
> Cheers,
>
>
> Alistair.
>
> -----Original Message-----
> From: Young, Alistair [mailto:alistair.young@logica.com]
> Sent: 12 January 2009 16:36
> To: user-java@ibatis.apache.org
> Subject: RE: iBATIS caching / transaction isolation question
>
> 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.
>
>
>
>
> 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