You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-java@ibatis.apache.org by Albert L Sapp <as...@uiuc.edu> on 2007/01/22 19:42:22 UTC

Re: Proper transaction code pattern

We are logging and displaying error reports to the user.  Perhaps that 
is the wrong approach to take, but I just inherited this as the standard 
for coding.  None of the try/catch blocks have a finally clause in 
them.  Instead, they just do a endTransaction in the try part of the 
block and also a endTransaction in each of the catches.  This seems to 
me to be overkill as I would think a finally clause with a 
endTransaction should be sufficient whether a exception is being caught 
and thrown or the transaction was completed successfully with a commit.

Please forgive my terminology if it is wrong.  Even after more than a 
year coding Java, I still am not sure what everything is called.  I 
simply want to make my code as efficient and correct as possible.  My 
thanks to the list for indulging what is probably a simple question.

Thanks,

Al
Clinton Begin wrote:
> If you call startTransaction() you must guarantee that endTransaction
> is called.  The only way to do that is inside a finally block.  You
> really should not need a catch block unless you're logging the
> exception or something.
>
> Cheers,
> Clinton
>
> On 1/22/07, Albert L Sapp <as...@uiuc.edu> wrote:
>> Clinton,
>>
>> You mentioned one case where I am unclear what I should be doing.  I
>> thought I read the documentation correctly, but still have the
>> question.  We use try/catch extensively in our application.  All the
>> try/catch are coded with a endTransaction prior to the actual throw of
>> the exception and the results of the endTransaction ignored.  Is this
>> really needed?  Can't we just have a endTransaction in a finally
>> clause?  Am I missing something here?  Probably, but I thought I 
>> would ask.
>>
>> Sorry, if it is covered in the docs and missed or didn't understand it.
>>
>> Al
>>
>> Clinton Begin wrote:
>> > Hi everyone,
>> >
>> > Reading through the original thread, there is more than one person
>> > confused by sessions and transactions, so here's some clarification.
>> >
>> > There are four levels of control you can have over iBATIS
>> > transactions.  They are:
>> >
>> > #1 First is single statement, automatic transaction.  In this case,
>> > you execute one statement that gets committed (or rolled back)
>> > automatically by iBATIS.  This behaves like JDBC "auto-commit", but it
>> > definitely doesn't use it.  iBATIS always explicitly calls
>> > commit/rollback.  An example of this single statement approach is:
>> >
>> > sqlMapper.insert("insertPerson",somePerson);
>> >
>> > You don't need a try/finally block or anything.  It's all self
>> > contained.  This is one transaction.
>> >
>> > #2 The second is multi-statement manual transaction mode.  In this
>> > case you have multiple statements you want to succeed or fail as a
>> > group.  If one statement fails, they all get rolled back.  This is the
>> > most common case for update statements, but can also improve the
>> > performance and consistency of multiple queries in some cases.  The
>> > example is:
>> >
>> > try {
>> >  sqlMapper.startTransaction();
>> >  sqlMapper.insert("insertPerson",somePerson);
>> >  sqlMapper.update("updatePerson",someOtherPerson);
>> >  sqlMapper.delete("deletePerson",anotherPerson);
>> >  sqlMapper.commitTransaction();
>> > } finally {
>> >  sqlMapper.endTransaction();
>> > }
>> >
>> > There's no explicit call to rollback().  iBATIS knows if you've called
>> > commit() indicating a successful transaction, otherwise it calls
>> > rollback.  This allows you to use try/finally semantics instead of
>> > try/catch (which can get messy).  You must ensure that this is always
>> > in a try/finally block as above, otherwise you risk connection leaks.
>> >
>> > #3 The third approach is to manage sessions manually.  In the last two
>> > cases sessions were managed automatically.  Sometimes you need to do
>> > this for greater control of the broader iBATIS usage scope, but you
>> > might also use it to pass your own connection to iBATIS (openSession()
>> > can take a connection as a parameter).  Here's an example:
>> >
>> > SqlMapSession session = sqlMap.openSession()
>> > try {
>> >   session.startTransaction()
>> >   session.insert("insertPerson",somePerson);
>> >   session.update("updatePerson",someOtherPerson);
>> >   session.delete("deletePerson",anotherPerson);
>> >   session.commitTransaction();
>> > } finally {
>> >   try {
>> >     session.endTransaction();
>> >   } finally {
>> >     session.close();
>> >   }
>> >   // Generally your session scope would be in a wider context and
>> > therefore the
>> >   // ugly nested finally block above would not be there.  Realize that
>> > sessions
>> >   // MUST be closed if explicitly opened (via openSession()).
>> > }
>> >
>> > As you can see, there's definitely more work and more code involved
>> > with managing sessions manually...it's therefore pretty rare.  If you
>> > do, you'll usually hide it in some abstract class or perhaps even in a
>> > separate layer of the application.  As the comment above says, doing
>> > so will also avoid the need for a nested try/finally block (in C#
>> > using blocks make this a lot cleaner too!).
>> >
>> > #4 Finally, there's 3rd Party session/transaction management.  This is
>> > the case if you're using Spring DAO, iBATIS DAO, or some other higher
>> > level persistence framework that has an iBATIS "plug-in".  I won't
>> > bother with an example, as you're better off looking them up.  The one
>> > we generally recommend is Spring DAO.
>> >
>> > I hope that helps.  This is all documented both in the JavaDocs and
>> > the user guide (this is almost a cut and paste from the javadoc).  Let
>> > us know if and how we can make it more clear.
>> >
>> > Cheers,
>> > Clinton
>> >
>> > On 1/22/07, Clinton Begin <cl...@gammagarage.com> wrote:
>> >> Cornel,
>> >>
>> >> Richard is right.  You're unfortunately mistaken.  The following 
>> is an
>> >> excerpt from the documentation you responded with:
>> >>
>> >> 'If a connection is in auto-commit mode, then all its SQL statements
>> >> will be executed and committed as individual transactions. Otherwise,
>> >> its SQL statements are grouped into transactions that are terminated
>> >> by a call to either the method commit or the method rollback."
>> >>
>> >> iBATIS always commits or rolls back transactions explicitly with
>> >> commit() and rollback().
>> >>
>> >> Clinton
>> >>
>> >> On 1/22/07, Cornel Antohi <ca...@kepler-rominfo.com> wrote:
>> >> >
>> >> >
>> >> > Hi Richard,
>> >> >
>> >> > I do not agree with you:
>> >> >
>> >> 
>> http://java.sun.com/j2se/1.3/docs/api/java/sql/Connection.html#setAutoCommit(boolean) 
>>
>> >>
>> >> >
>> >> > Thank you,
>> >> > Cornel
>> >> >
>> >> > ----- Original Message -----
>> >> > From: Yee, Richard K CTR DMDC
>> >> > To: 'user-java@ibatis.apache.org'
>> >> >
>> >> > Sent: Monday, January 22, 2007 6:42 PM
>> >> > Subject: RE: Autocommit not properly handled in Ibatis.
>> >> >
>> >> >
>> >> > Antohi,
>> >> > It looks to me that the code does exactly what Clinton says. If
>> >> autocommit
>> >> > is on, iBATIS turns it off and thus does not use autocommit to 
>> commit
>> >> > changes to the DB.
>> >> >
>> >> > -Richard
>> >> >
>> >> >
>> >> >
>> >> > -----Original Message-----
>> >> > From: Cornel Antohi [mailto:cantohi@kepler-rominfo.com]
>> >> > Sent: Monday, January 22, 2007 2:37 AM
>> >> > To: user-java@ibatis.apache.org
>> >> > Subject: Re: Autocommit not properly handled in Ibatis.
>> >> >
>> >> >
>> >> > Hi Clinton,
>> >> >
>> >> > 1) What do you mean by "iBATIS never uses AutoCommit"? Here is what
>> >> I found
>> >> > in:
>> >> >
>> >> > com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransaction
>> >> > --> private void init() throws SQLException, TransactionException
>> >> > // AutoCommit
>> >> > if (connection.getAutoCommit()) {
>> >> >     connection.setAutoCommit(false);
>> >> > }
>> >> >
>> >> >
>> >> > Thank you,
>> >> > Cornel
>> >> >
>> >> > ----- Original Message -----
>> >> > From: "Clinton Begin" <cl...@gmail.com>
>> >> > To: <us...@ibatis.apache.org>
>> >> > Sent: Friday, January 19, 2007 8:52 AM
>> >> > Subject: Re: Autocommit not properly handled in Ibatis.
>> >> >
>> >> > A few things:
>> >> >
>> >> > 1) iBATIS never uses AutoCommit.
>> >> >
>> >> > 2) setCommitRequired has nothing to do with AutoCommit.  iBATIS 
>> uses
>> >> > deferred commits to avoid unecessary commits when no non-queries 
>> have
>> >> > been issued.  And setCommitRequired is actually parameterized 
>> and can
>> >> > be set with <transactionManager ... commitRequired="true">
>> >> >
>> >> > 3) You'll need to post your code so we can see what it's doing.  
>> Are
>> >> > you calling startTransaction()?  Are you using 
>> setUserConnection?  Or
>> >> > openSession(conn)?
>> >> >
>> >> > I'm sure with the right information we can resolve this for you
>> >> easily.
>> >> >
>> >> > Clinton
>> >> >
>> >> > On 1/18/07, Yuvraj Shinde <Yu...@sos.sungard.com> wrote:
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> > > Hi all,
>> >> > >
>> >> > >
>> >> > >
>> >> > >    I want to know how to handle auto commit in ibatis.if I am
>> >> saving two
>> >> > > records and if I get an exception while saving second record the
>> >> first
>> >> > > record saved should be rolled back.
>> >> > >
>> >> > >   But ibatis is saving the first record. How I should handle this
>> >> even
>> >> > > though the auto commit property is explicitly set to false.
>> >> > >
>> >> > >
>> >> > >
>> >> > >    Even though AutoCommit value is set to false. Rollback of
>> >> Transaction
>> >> > is
>> >> > > not working.
>> >> > >
>> >> > >    I found one Issue in GeneralStatement.java.
>> >> > >
>> >> > >    On line 52  request.getSession().setCommitRequired(true);
>> >> > >
>> >> > >
>> >> > >
>> >> > >    Here Auto commit is hard coded it should be parameterized so
>> >> that it
>> >> > will
>> >> > > take value from "Auto commit" property of  SqlMapConfig.xml.
>> >> > >
>> >> > >    Please correct me if I am wrong.please send me a solution.
>> >> > >
>> >> > >
>> >> > >
>> >> > > Regards
>> >> > >
>> >> > > Yuvrajs
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> > > Yuvraj Shinde * Senior Software Engineer -  Zainet*  SunGard *
>> >> Offshore
>> >> > > Services *
>> >> > >  Pride Portal,CTS No 103A/5A/1A/1B Bhamburda,Senapati Bapat Road,
>> >> > > shivajinagar,Pune 411016
>> >> > >  Tel Direct +91 20 66248045 * Main +91 20 66248000 * Fax +91 20
>> >> 25606222
>> >> > >  yuvraj.shinde@sos.sungard.com * www.sungard.com
>> >> > >
>> >> > >
>> >> > >
>> >> > >
>> >> > > Success is never ending and failure is never final.
>> >> > >
>> >> > >
>> >>
>> >
>>
>>
>


Re: Proper transaction code pattern

Posted by Clinton Begin <cl...@gammagarage.com>.
It sounds like you've done a good job recognizing the problem.  You're
right that it would be better to put it in the try/finally block,
especially if the code is catching a specific exception (like
SQLException).  Think about what happens if an unexpected
RuntimeException is thrown...

You're on the right track.

Cheers,  ;-)
Clinton

On 1/22/07, Albert L Sapp <as...@uiuc.edu> wrote:
> We are logging and displaying error reports to the user.  Perhaps that
> is the wrong approach to take, but I just inherited this as the standard
> for coding.  None of the try/catch blocks have a finally clause in
> them.  Instead, they just do a endTransaction in the try part of the
> block and also a endTransaction in each of the catches.  This seems to
> me to be overkill as I would think a finally clause with a
> endTransaction should be sufficient whether a exception is being caught
> and thrown or the transaction was completed successfully with a commit.
>
> Please forgive my terminology if it is wrong.  Even after more than a
> year coding Java, I still am not sure what everything is called.  I
> simply want to make my code as efficient and correct as possible.  My
> thanks to the list for indulging what is probably a simple question.
>
> Thanks,
>
> Al
> Clinton Begin wrote:
> > If you call startTransaction() you must guarantee that endTransaction
> > is called.  The only way to do that is inside a finally block.  You
> > really should not need a catch block unless you're logging the
> > exception or something.
> >
> > Cheers,
> > Clinton
> >
> > On 1/22/07, Albert L Sapp <as...@uiuc.edu> wrote:
> >> Clinton,
> >>
> >> You mentioned one case where I am unclear what I should be doing.  I
> >> thought I read the documentation correctly, but still have the
> >> question.  We use try/catch extensively in our application.  All the
> >> try/catch are coded with a endTransaction prior to the actual throw of
> >> the exception and the results of the endTransaction ignored.  Is this
> >> really needed?  Can't we just have a endTransaction in a finally
> >> clause?  Am I missing something here?  Probably, but I thought I
> >> would ask.
> >>
> >> Sorry, if it is covered in the docs and missed or didn't understand it.
> >>
> >> Al
> >>
> >> Clinton Begin wrote:
> >> > Hi everyone,
> >> >
> >> > Reading through the original thread, there is more than one person
> >> > confused by sessions and transactions, so here's some clarification.
> >> >
> >> > There are four levels of control you can have over iBATIS
> >> > transactions.  They are:
> >> >
> >> > #1 First is single statement, automatic transaction.  In this case,
> >> > you execute one statement that gets committed (or rolled back)
> >> > automatically by iBATIS.  This behaves like JDBC "auto-commit", but it
> >> > definitely doesn't use it.  iBATIS always explicitly calls
> >> > commit/rollback.  An example of this single statement approach is:
> >> >
> >> > sqlMapper.insert("insertPerson",somePerson);
> >> >
> >> > You don't need a try/finally block or anything.  It's all self
> >> > contained.  This is one transaction.
> >> >
> >> > #2 The second is multi-statement manual transaction mode.  In this
> >> > case you have multiple statements you want to succeed or fail as a
> >> > group.  If one statement fails, they all get rolled back.  This is the
> >> > most common case for update statements, but can also improve the
> >> > performance and consistency of multiple queries in some cases.  The
> >> > example is:
> >> >
> >> > try {
> >> >  sqlMapper.startTransaction();
> >> >  sqlMapper.insert("insertPerson",somePerson);
> >> >  sqlMapper.update("updatePerson",someOtherPerson);
> >> >  sqlMapper.delete("deletePerson",anotherPerson);
> >> >  sqlMapper.commitTransaction();
> >> > } finally {
> >> >  sqlMapper.endTransaction();
> >> > }
> >> >
> >> > There's no explicit call to rollback().  iBATIS knows if you've called
> >> > commit() indicating a successful transaction, otherwise it calls
> >> > rollback.  This allows you to use try/finally semantics instead of
> >> > try/catch (which can get messy).  You must ensure that this is always
> >> > in a try/finally block as above, otherwise you risk connection leaks.
> >> >
> >> > #3 The third approach is to manage sessions manually.  In the last two
> >> > cases sessions were managed automatically.  Sometimes you need to do
> >> > this for greater control of the broader iBATIS usage scope, but you
> >> > might also use it to pass your own connection to iBATIS (openSession()
> >> > can take a connection as a parameter).  Here's an example:
> >> >
> >> > SqlMapSession session = sqlMap.openSession()
> >> > try {
> >> >   session.startTransaction()
> >> >   session.insert("insertPerson",somePerson);
> >> >   session.update("updatePerson",someOtherPerson);
> >> >   session.delete("deletePerson",anotherPerson);
> >> >   session.commitTransaction();
> >> > } finally {
> >> >   try {
> >> >     session.endTransaction();
> >> >   } finally {
> >> >     session.close();
> >> >   }
> >> >   // Generally your session scope would be in a wider context and
> >> > therefore the
> >> >   // ugly nested finally block above would not be there.  Realize that
> >> > sessions
> >> >   // MUST be closed if explicitly opened (via openSession()).
> >> > }
> >> >
> >> > As you can see, there's definitely more work and more code involved
> >> > with managing sessions manually...it's therefore pretty rare.  If you
> >> > do, you'll usually hide it in some abstract class or perhaps even in a
> >> > separate layer of the application.  As the comment above says, doing
> >> > so will also avoid the need for a nested try/finally block (in C#
> >> > using blocks make this a lot cleaner too!).
> >> >
> >> > #4 Finally, there's 3rd Party session/transaction management.  This is
> >> > the case if you're using Spring DAO, iBATIS DAO, or some other higher
> >> > level persistence framework that has an iBATIS "plug-in".  I won't
> >> > bother with an example, as you're better off looking them up.  The one
> >> > we generally recommend is Spring DAO.
> >> >
> >> > I hope that helps.  This is all documented both in the JavaDocs and
> >> > the user guide (this is almost a cut and paste from the javadoc).  Let
> >> > us know if and how we can make it more clear.
> >> >
> >> > Cheers,
> >> > Clinton
> >> >
> >> > On 1/22/07, Clinton Begin <cl...@gammagarage.com> wrote:
> >> >> Cornel,
> >> >>
> >> >> Richard is right.  You're unfortunately mistaken.  The following
> >> is an
> >> >> excerpt from the documentation you responded with:
> >> >>
> >> >> 'If a connection is in auto-commit mode, then all its SQL statements
> >> >> will be executed and committed as individual transactions. Otherwise,
> >> >> its SQL statements are grouped into transactions that are terminated
> >> >> by a call to either the method commit or the method rollback."
> >> >>
> >> >> iBATIS always commits or rolls back transactions explicitly with
> >> >> commit() and rollback().
> >> >>
> >> >> Clinton
> >> >>
> >> >> On 1/22/07, Cornel Antohi <ca...@kepler-rominfo.com> wrote:
> >> >> >
> >> >> >
> >> >> > Hi Richard,
> >> >> >
> >> >> > I do not agree with you:
> >> >> >
> >> >>
> >> http://java.sun.com/j2se/1.3/docs/api/java/sql/Connection.html#setAutoCommit(boolean)
> >>
> >> >>
> >> >> >
> >> >> > Thank you,
> >> >> > Cornel
> >> >> >
> >> >> > ----- Original Message -----
> >> >> > From: Yee, Richard K CTR DMDC
> >> >> > To: 'user-java@ibatis.apache.org'
> >> >> >
> >> >> > Sent: Monday, January 22, 2007 6:42 PM
> >> >> > Subject: RE: Autocommit not properly handled in Ibatis.
> >> >> >
> >> >> >
> >> >> > Antohi,
> >> >> > It looks to me that the code does exactly what Clinton says. If
> >> >> autocommit
> >> >> > is on, iBATIS turns it off and thus does not use autocommit to
> >> commit
> >> >> > changes to the DB.
> >> >> >
> >> >> > -Richard
> >> >> >
> >> >> >
> >> >> >
> >> >> > -----Original Message-----
> >> >> > From: Cornel Antohi [mailto:cantohi@kepler-rominfo.com]
> >> >> > Sent: Monday, January 22, 2007 2:37 AM
> >> >> > To: user-java@ibatis.apache.org
> >> >> > Subject: Re: Autocommit not properly handled in Ibatis.
> >> >> >
> >> >> >
> >> >> > Hi Clinton,
> >> >> >
> >> >> > 1) What do you mean by "iBATIS never uses AutoCommit"? Here is what
> >> >> I found
> >> >> > in:
> >> >> >
> >> >> > com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransaction
> >> >> > --> private void init() throws SQLException, TransactionException
> >> >> > // AutoCommit
> >> >> > if (connection.getAutoCommit()) {
> >> >> >     connection.setAutoCommit(false);
> >> >> > }
> >> >> >
> >> >> >
> >> >> > Thank you,
> >> >> > Cornel
> >> >> >
> >> >> > ----- Original Message -----
> >> >> > From: "Clinton Begin" <cl...@gmail.com>
> >> >> > To: <us...@ibatis.apache.org>
> >> >> > Sent: Friday, January 19, 2007 8:52 AM
> >> >> > Subject: Re: Autocommit not properly handled in Ibatis.
> >> >> >
> >> >> > A few things:
> >> >> >
> >> >> > 1) iBATIS never uses AutoCommit.
> >> >> >
> >> >> > 2) setCommitRequired has nothing to do with AutoCommit.  iBATIS
> >> uses
> >> >> > deferred commits to avoid unecessary commits when no non-queries
> >> have
> >> >> > been issued.  And setCommitRequired is actually parameterized
> >> and can
> >> >> > be set with <transactionManager ... commitRequired="true">
> >> >> >
> >> >> > 3) You'll need to post your code so we can see what it's doing.
> >> Are
> >> >> > you calling startTransaction()?  Are you using
> >> setUserConnection?  Or
> >> >> > openSession(conn)?
> >> >> >
> >> >> > I'm sure with the right information we can resolve this for you
> >> >> easily.
> >> >> >
> >> >> > Clinton
> >> >> >
> >> >> > On 1/18/07, Yuvraj Shinde <Yu...@sos.sungard.com> wrote:
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > > Hi all,
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >    I want to know how to handle auto commit in ibatis.if I am
> >> >> saving two
> >> >> > > records and if I get an exception while saving second record the
> >> >> first
> >> >> > > record saved should be rolled back.
> >> >> > >
> >> >> > >   But ibatis is saving the first record. How I should handle this
> >> >> even
> >> >> > > though the auto commit property is explicitly set to false.
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >    Even though AutoCommit value is set to false. Rollback of
> >> >> Transaction
> >> >> > is
> >> >> > > not working.
> >> >> > >
> >> >> > >    I found one Issue in GeneralStatement.java.
> >> >> > >
> >> >> > >    On line 52  request.getSession().setCommitRequired(true);
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >    Here Auto commit is hard coded it should be parameterized so
> >> >> that it
> >> >> > will
> >> >> > > take value from "Auto commit" property of  SqlMapConfig.xml.
> >> >> > >
> >> >> > >    Please correct me if I am wrong.please send me a solution.
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > > Regards
> >> >> > >
> >> >> > > Yuvrajs
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > > Yuvraj Shinde * Senior Software Engineer -  Zainet*  SunGard *
> >> >> Offshore
> >> >> > > Services *
> >> >> > >  Pride Portal,CTS No 103A/5A/1A/1B Bhamburda,Senapati Bapat Road,
> >> >> > > shivajinagar,Pune 411016
> >> >> > >  Tel Direct +91 20 66248045 * Main +91 20 66248000 * Fax +91 20
> >> >> 25606222
> >> >> > >  yuvraj.shinde@sos.sungard.com * www.sungard.com
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > >
> >> >> > > Success is never ending and failure is never final.
> >> >> > >
> >> >> > >
> >> >>
> >> >
> >>
> >>
> >
>
>