Return-Path: Mailing-List: contact ibatis-user-java-help@incubator.apache.org; run by ezmlm Delivered-To: mailing list ibatis-user-java@incubator.apache.org Received: (qmail 99295 invoked by uid 99); 1 Jan 2005 19:36:30 -0000 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests=RCVD_BY_IP,SPF_HELO_PASS,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (hermes.apache.org: domain of brandon.goodin@gmail.com designates 64.233.170.193 as permitted sender) Received: from rproxy.gmail.com (HELO rproxy.gmail.com) (64.233.170.193) by apache.org (qpsmtpd/0.28) with ESMTP; Sat, 01 Jan 2005 11:36:27 -0800 Received: by rproxy.gmail.com with SMTP id c16so245246rne for ; Sat, 01 Jan 2005 11:36:25 -0800 (PST) DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=beta; d=gmail.com; h=received:message-id:date:from:reply-to:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:references; b=hLmVcoO4PGUm4VhASpKQ631SLMG/LEZJQnddsCmJy4Xid12FA1Glwf1q82bhPbg1rxKsyFy5oijm1o47ODl98knLb22IMaWwYOr5pqlORlgS8VT+v7mCmSvXbnZ8AdKN8oCydLnjtjrFiGp8pmIEmLZBk28aJNLcYr817Br9rOs= Received: by 10.38.73.77 with SMTP id v77mr398708rna; Sat, 01 Jan 2005 11:36:25 -0800 (PST) Received: by 10.38.74.57 with HTTP; Sat, 1 Jan 2005 11:36:25 -0800 (PST) Message-ID: <2fe5ef5b0501011136616a6865@mail.gmail.com> Date: Sat, 1 Jan 2005 12:36:25 -0700 From: Brandon Goodin Reply-To: Brandon Goodin To: ibatis-user-java@incubator.apache.org Subject: Re: Sybase CHAINED v. UNCHAINED solution In-Reply-To: Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit References: X-Virus-Checked: Checked I'll start a thread on this on the developers list and see what we can get setup. Brandon On Tue, 28 Dec 2004 14:58:17 -0600, Severtson, Scott (Associate) wrote: > All, > Many months ago, moonpool posted a question regarding Sybase's lack of > support for DDL (including temporary tables) when inside a transaction > within iBATIS (http://sourceforge.net/forum/message.php?msg_id=2507161). > I solved this problem for a client transitioning to iBATIS, and posted a > whitepaper about the solution, pasted below. I have finally received > written permission from the client to open source the code. > > So, where should I post the code? Anyone want to host it? > > For the time being, anyone in desperate need can email me at > scott.severtson@qg.com. > > --Scott Severtson > > Note: > As described in the white paper below, we must detect if iBATIS is using > implicit or explicit transactions; three different detection methods are > included for reference, supporting the DaoManager, the SqlMapClient, and > one that supports both Dao/SqlMaps, but only without a JIT compilier > (included because it requires no changes to *your code* to test, just > changing the transaction manager; the other solutions require wrapping a > proxy around the DaoManager/SqlMapClient). None of these solutions are > optimal; however, they work without changing any iBATIS code, which was > critical for the client. The active detector implementation can be > changed by editing > com.qg.open.sybase.ibatis.TransactionTypeDetector.Factory's code to hold > an instance of another detector, and usage details are included in the > javadocs. A much better solution would be to expose implicit/explicit > transaction state at the DaoManager/SqlMapClient level. > > Unchained and Chained Transaction Modes > ----------------------------------------- > Sybase supports two transaction modes: Chained and Unchained. > * Unchained mode is specified by JDBC's Connection.setAutoCommit(true): > insert/update/delete statements are automatically committed on execute. > Sybase extends standard AutoCommit with multi-statement transaction > support if BEGIN TRANSACTION is explicitly called. This mode is the > default. > * Chained mode is specified by JDBC's Connection.setAutoCommit(false), > and conforms to the SQL 92 behavior of implicit transactions: a > transaction automatically begins with the first statement, and no work > is committed until COMMIT TRANSACTION is explicitly called. > > Unchained and Chained modes are (mostly) mutually exclusive. Unless a > stored procedure is written with care to support both modes, it will > generally only work in one mode. > > JDBC's transactional support requires Connection.setAutoCommit(false) to > be set, which forces Sybase into Chained mode. However, nearly all > existing stored procedures are written exclusively for Unchained mode. > > Temporary Tables and Transactions > ----------------------------------------- > Sybase by default does not allow CREATE/DROP TABLE statements within > transactions, including creating tables on the temporary database. While > this can be enabled, Sybase strongly recommends against it: "doing so > can slow performance to a halt". See http://tinyurl.com/5clrf for > further information. > > iBATIS expects Connection.setAutoCommit(false) mode: all calls exist in > an implicit, automatic transaction, and must be committed/rolled back. > However, two modes are supported, implicit and explicit transactions: > > // ***Implicit transaction*** > // A Transaction object is automatically retrieved prior to calling > getUser > User user = userDao.getUser("fflintstone"); > // Transaction.commit() is automatically called after calling getUser > > // ***Explicit transaction*** > // A Transaction object is explicitly requested > daoManager.startTransaction(); > userDao.updateUser(user); > someOtherDao.updateSomethingElse(user); > // Transaction.commit() is explicitly called > daoManager.commitTransaction(); > > Many existing procedures make use of temporary tables; these procedures > cannot be run inside a transaction. Therefore, we must prevent iBATIS's > implicit transaction support from actually beginning/committing/rolling > back transactions. > > Solutions > ======= > ConnectionProxy/StatementProxy/ProxyUtil > ----------------------------------------- > JDBC's Connection.setAutoCommit(false) behavior can be simulated in > Unchained mode. > 1. Call BEGIN TRANSACTION prior to executing any SQL on a connection. > 2. Call COMMIT/ROLLBACK TRANSACTION in place of > Connection.commit/rollback() > However, these manual calls would force knowledge of Sybase's > limitations into the data access code, and would not work with iBATIS's > transaction support. > The Proxy pattern from Design Patterns by Gamma et. al. (page 207) > allows us to wrap the real Connection object with our own > implementation, which makes the desired BEGIN/COMMIT/ROLLBACK calls on > our behalf. The proxy's setAutoCommit method enables/disables this > behavior > > TransactionTypeDetector > ------------------------ > Detecting implicit and explicit transactions is necessary, as implicit > transactions must not actually call BEGIN TRANSACTION. The detector > examines the stack trace to determine if startTransaction() was > explicitly called, or if iBATIS is making the call on the user's behalf. > > SybaseTransaction/SybaseTransactionConfig > ------------------------------------------- > iBATIS defines Transaction and TransactionConfig interfaces, allowing > third-party developers to build in their own transactional support. > > public interface Transaction { > public Connection getConnection() throws ...; > public void commit() throws ...; > public void rollback() throws ...; > public void close() throws ...; > } > public interface TransactionConfig { > public Transaction newTransaction() throws ...; > // ...Other methods... > } > Transaction initializes connections and manages transactions, and > TransactionConfig builds Transaction objects. The SybaseTransaction > implementation automatically wraps a Sybase connection in a > ConnectionProxy, and SybaseTransactionConfig builds SybaseTransaction > instances. Additionally, SybaseTransactionConfig uses > TransactionTypeDetector to specify the setAutoCommit behavior of the > ConnectionProxy. > > Comments > ======== > This solution adequately solves the Unchained and Chained Modes problem; > any code that uses the ConnectionProxy can use setAutoCommit as JDBC > specifies, while the underlying Sybase Connection remains in > setAutoCommit(true)/Unchained mode. Stored procedures written for > Unchained mode can be can be called from JDBC seamlessly as part of a > transaction. > > This solution does not completely solve the Temporary Tables and > Transactions problem. Stored procedures that use temporary tables must > not be called in the ConnectionProxy's setAutoCommit(false) mode, such > as inside an explicit iBATIS transaction. This limitation is entirely > within the RDBMS, and as such, cannot be resolved by Java code. > > Finally, the implementation could have been simplified had > ConnectionProxy's transactional support code been placed inside > SybaseTransaction. However, the Connection.close() method is not handled > through the Transaction interface; cleanup requires us to listen for > this call. Additionally, the ConnectionProxy implementation has no > dependency on iBATIS, and can be used with other persistence frameworks > or straight JDBC calls. >