tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Chris Cheshire <yahoono...@gmail.com>
Subject Re: tomcat 8.5.23 dbcp not honoring autocommit = false?
Date Thu, 26 Oct 2017 19:54:22 GMT
On Thu, Oct 26, 2017 at 3:00 PM, Christopher Schultz
<chris@christopherschultz.net> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA256
>
> Chris,
>
> On 10/16/17 9:43 AM, Chris Cheshire wrote:
>> On Fri, Oct 13, 2017 at 5:00 PM, Christopher Schultz
>> <chris@christopherschultz.net> wrote:
>>> -----BEGIN PGP SIGNED MESSAGE-----
>>
>>> When you say you have "autocommit disabled in mysql config" what
>>> do you mean?
>>>
>>
>> /etc/my.cnf : [mysqld] autocommit=0
>>
>> This turns off autocommit off as a default for all connections.
>
> It only affects connections from MySQL's "mysql" command-line client.
> It does not affect e.g. Java-based clients.
>

It's in the [mysqld] section of my.cnf so it is supposed to be at a
server level.

I do have stuff in the [mysql] section that affects the command line client
behaviour only.

>> I need this at a minimum for the mysql client, but in the absence
>> of any other configuration it should be the default for a
>> connection from any client.
>
> The JDBC spec says that all connections are auto-commit unless
> otherwise specified. So if you are creating your own connections or
> using e.g. a connection-pool then you'll have to make sure that you
> configure them to be NOT auto-commit. This is not a setting that you
> can control from the server.
>
> More below.
>

I was doing that anyway in both the pool configuration and when
the connection is grabbed from the pool. I've since changed the code to not
touch the autocommit setting and leave that up to the datasource
(resource config in context.xml)


>>> On 10/13/17 10:17 AM, Chris Cheshire wrote:
>>>> </snip>
>>>>
>>>> As a further test I just took out my explicit rollback in my
>>>> DAOFactory close() method, and swapped back to commons dbcp.
>>>> Added an update that wasn't explicitly committed, and it
>>>> correctly did not get committed when the connection was closed.
>>>> Swapped back to tomcat dbcp and repeated, it got committed
>>>> without an explicit commit statement.
>>>>
>>>> I'm really puzzled as to why *I* have to explicitly rollback
>>>> on close if autocommit is not enabled, instead of tomcat dbcp
>>>> handling that when commons dbcp appears to do it.
>>>
>>> No connection pool can read your mind. If you begin a transaction
>>> (or never start one), you must either commit or rollback. Merely
>>> calling close() does not explicitly cause either of those to be
>>> called.
>>>
>>
>> And that's just it. If I don't explicitly commit, then why are
>> changes being committed when the connection is closed and returned
>> back to the pool?
>>
>>>> If I do
>>>>
>>>> daoFactory = new MySQLDAOFactoryImpl(getDataSource());
>>>>
>>>> // update #1 daoFactory.commit()
>>>>
>>>> // update #2 daoFactory.close();
>>>>
>>>> then update #2 is being committed.
>>>
>>> I'm curious why you are doing "update #2" without either COMMIT
>>> or ROLLBACK. That seems like ... a mistake.
>>>
>>
>> Correct. This is an example to illustrate a mistake I found in my
>> code. I found a servlet that actually wasn't explicitly committing
>> when it should have been, yet everything it was doing was being
>> committed to the database.
>>
>>> - From the Connection.close() javadoc:
>>>
>>> " It is strongly recommended that an application explicitly
>>> commits or rolls back an active transaction prior to calling the
>>> close method. If the close method is called and there is an
>>> active transaction, the results are implementation-defined. "
>>>
>>
>> If a commit is not being explicitly issued, then the commit
>> behaviour should honor that of the connection, yes?
>
> Yes, but it's more complicated than that. Any change to the
> connection's settings (which happen ALL THE TIME when the connection
> is being returned to a connection pool) will cause an implicit COMMIT.
> That's why it's super important for you to either COMMIT or ROLLBACK
> yourself.
>
> Note that "autocommit = false" doesn't mean "autorollback=true".
> Best-case scenario for you there is that the transaction gets
> committed *later* when another piece of your code grabs a connection
> from the pool, does its work (successfully) and issues a COMMIT.
>
> It's just NOT the pool's job nor the driver's job to clean-up after
> any messes created by your code.


Agreed, however since it was acting differently than the commons
pool I mistakenly attributed the behaviour to tomcat jdbc instead.


>
>>> There *is* an implicit COMMIT executed if the autocommit flag is
>>> flipped for any reason, either true->false or false->true.
>>>
>>> If you have autocommit=false in your <Resource> configuration
>>> (which you do), then calling setAutoCommit(false) shouldn't do
>>> anything.
>>>
>>>> If I put in this in the close() method of my DAO Factory
>>>>
>>>> if (!this.dbConn.getAutoCommit()) { this.dbConn.rollback(); }
>>>>
>>>> before the close() call, then update #2 is correctly not
>>>> getting committed.
>>>
>>> This is probably the wrong approach: your close() method doesn't
>>> know whether it's better to call commit() or rollback(), so it
>>> should do neither.
>>
>> I realise this too, however I have to have it in otherwise if an
>> exception is thrown, then work is being committed regardless of the
>> fact that I have autocommit turned OFF in 3 levels, all  the way
>> back to the mysqld configuration.
>
> The mysqld configuration is not relevant, here. Are you able to run
> your code through a debugger to see when the COMMIT is happening?
>
>> This behaviour does not happen with commons dbcp, only tomcat dbcp.
>> There is a difference in default behaviour between the two pools
>> when a transaction is not explicitly committed or rolled back when
>> a connection is closed and returned to the pool.
>
> Can you create a SSCCE test-case which demonstrates this problem where
> it behaves one way with tomcat-pool versus commons-dbcp? Something
> simple like "java RunTest" where it prints out "expected behavior" or
> "unexpected behavior" would be great. Remember that JavaDB (aka Derby)
> is built-into JVMs before 9.0 so you don't need any complicated
> database setup.


I don't have time to make an SSCCE for a while, but since Keiichi pointed out
the tomcat jdbc pool is doing nothing in the absence of any instruction to do
otherwise, I figured out that it was a subsequent explicit commit when
the connection
was reused. This was giving me the impression that a commit was happening
when the connection was being returned.


>
>> I use a try-with-resources/finally to open and close my database
>> connections, thus short of a JVM crash, any exceptions thrown will
>> always close the connections and return them to the pool.
>
> Good. Will those exceptions cause a ROLLBACK to occur? If not, your
> code is broken.
>

No, I am using the rollbackOnReturn parameter now to handle that. I explicity
commit, but any unchecked exceptions that are thrown will trigger a rollback
via this. Previously the commons pool appeared to be doing that for me and I
didn't think anything of it.

I could change this to have every single servlet action
catch a Throwable, issue a rollback and then rethrow the Throwable, but
it is easier right now to make use of the configuration available in tomcat jdbc
to issue a rollback on return.

I understand this is not the correct approach and if I find the time,
I will fix it.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message