ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Brandon Goodin <brandon.goo...@gmail.com>
Subject Re: Sybase CHAINED v. UNCHAINED solution
Date Sat, 01 Jan 2005 19:36:25 GMT
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)
<Scott.Severtson@qg.com> 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.
>

Mime
View raw message