MySQL AutoCommit带来的问题(2)

因为测试时采用的是一个连接这种极端条件,因此该现象非常容易复现,且是100%的复现,但是在测试条件下,并非100%复现,而是在重启之后会好一段时间,一段时间以后就会重新出现这个情况。

如果将读取类的代码稍加修改:

public class GetClient { private void query() throws SQLException { System.out.println("start"); MysqlClient instance = MysqlClient.getInstance(); Connection conn = instance.getConnection(); conn.setAutoCommit(true); String sql = "select uname from test1"; PreparedStatement statement = conn.prepareStatement(sql); ResultSet rs = statement.executeQuery(); while (rs.next()) { System.out.println(rs.getString("uname")); } statement.close(); rs.close(); conn.close(); } private void nothing() throws SQLException { MysqlClient instance = MysqlClient.getInstance(); Connection conn = instance.getConnection(); conn.setAutoCommit(false); conn.close(); } public static void main(String[] args) throws SQLException, InterruptedException, ClassNotFoundException { DBconfigEntity entity = new DBconfigEntity(); entity.setDbName("test"); entity.setDbPasswd("123456"); entity.setDbUser("root"); entity.setIp("127.0.0.1"); entity.setPort(3306); MysqlClient.init(entity); GetClient client = new GetClient(); client.nothing(); while (true) { client.query(); Thread.sleep(5000); } } }

注意我在query方法中加入这一句:conn.setAutoCommit(true);

此时这个问题不再出现。

源码分析 jdbc驱动源码分析

Connection是Java提供的一个标准接口:java.sql.Connection,其具体实现是:com.mysql.jdbc.ConnectionImpl。

分析jdbc驱动代码可知,jdbc默认的AutoCommit状态是TRUE:

这实际上和MySQL的默认值是一样的。

tomcat-jdbc源码分析

tomcat-jdbc的close方法由拦截器实现,具体的逻辑代码:

if (compare(CLOSE_VAL,method)) { if (connection==null) return null; //noop for already closed. PooledConnection poolc = this.connection; this.connection = null; pool.returnConnection(poolc); return null; }

实际上此处只是将连接还给了连接池,没有对连接进行任何处理。

tomcat-jdbc维护了两个Queue:busy和idle,用于存放空闲和已借出连接,连接还给连接池的过程简单的说就是将该连接从busy队列中移除,并放在idle队列中的过程。

boneCP源码分析

根据实际使用的经验看,boneCP连接池在使用的过程中并没有出现这个问题,分析boneCP的Connection具体实现,发现在close方法的具体实现中,有这样的一段代码逻辑:

if (!getAutoCommit()) { setAutoCommit(true); }

这段逻辑会判断该连接的AutoCommit属性是否为FALSE,如果是,就自动将其置为TRUE。

因此,在这个连接被交还回连接池时,AutoCommit属性总是TRUE。

结论

任何查询接口都应该在获取连接以后进行AutoCommit的设置,将其设置为true。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/f3797cc155f0f40373515121d2d9ff4a.html