最近开发时使用c3p0连接池,数据库用的mysql的InnoDB,但是发现事务提交出错之后不能回滚。查了多方原因,查看mysql的log时发现rollback命令也执行了,但是在事务执行开始的时候并没有去SET autocommit=0的操作。更换了数据库连接池,并且把setAutocommit=false,这个时候发现问题不在。那就之能是c3p0的问题了。
但是c3p0并没有setAutocommit=false这个属性配置。
此时需要配置一个ConnectionCustomizer
public class YourConnectionCustomizer extends AbstractConnectionCustomizer{
public void onCheckOut( Connection c, String parentDataSourceIdentityToken ) throws Exception
{
super.onCheckOut(c, parentDataSourceIdentityToken);
System.out.println("手动关闭自动提交");
c.setAutoCommit(false);
}
}
并且修改c3p0配置文件
<property name="connectionCustomizerClassName" value="cn.vodone.base.database.c3p0.IsolationLevelConnectionCustomizer"/>
这个时候会发现,在事务执行之前有SET autocommit=0了
事务回滚成功。
关于connectionCustomizerClassName
:
connectionCustomizerClassName
default : null
用来定制Connection的管理,比如在Connection acquire 的时候设定Connection的隔离级别,或者在
Connection丢弃的时候进行资源关闭,就可以通过继承一个AbstractConnectionCustomizer来实现相关
方法,配置的时候使用全类名。有点类似监听器的作用。
关于接口描述:
/**
* <p>Implementations of this interface should
* be immutable, and should offer public,
* no argument constructors.</p>
*
* <p>The methods are handed raw, physical
* database Connections, not c3p0-generated
* proxies.</p>
*
* <p>Although c3p0 will ensure this with
* respect to state controlled by
* standard JDBC methods, any modifications
* of vendor-specific state shold be made
* consistently so that all Connections
* in the pool are interchangable.</p>
*/
public interface ConnectionCustomizer
{
/**
* <p>Called immediately after a
* Connection is acquired from the
* underlying database for
* incorporation into the pool.</p>
*
* <p>This method is only called once
* per Connection. If standard JDBC
* Connection properties are modified
* [holdability, transactionIsolation,
* readOnly], those modifications
* will override defaults throughout
* the Connection's tenure in the
* pool.</p>
*/
public void onAcquire( Connection c, String parentDataSourceIdentityToken )
throws Exception;
/**
* Called immediately before a
* Connection is destroyed after
* being removed from the pool.
*/
public void onDestroy( Connection c, String parentDataSourceIdentityToken )
throws Exception;
/**
* Called immediately before a
* Connection is made available to
* a client upon checkout.
*/
public void onCheckOut( Connection c, String parentDataSourceIdentityToken )
throws Exception;
/**
* Called immediately after a
* Connection is checked in,
* prior to reincorporation
* into the pool.
*/
public void onCheckIn( Connection c, String parentDataSourceIdentityToken )
throws Exception;
}
由此可见,在从连接池中拿connection的时候,会触发onCeckout方法,所以需要手动setAutoCommit(false);