`
ouyangshixiong
  • 浏览: 6634 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

mysql-connector-J各版本 SQL_CALC_FOUND_ROWS found_rows() bug探究

 
阅读更多

朋友们先回答两个问题:

select SQL_CALC_FOUND_ROWS * from product where 1=1  order by pid asc limit 0,15

select found_rows() as ct

在mysql5命令行里面执行这两句,ok不ok?

ok

 

Java代码:

    stmt = conn.createStatement();
    rs = stmt.executeQuery(sql);
    CachedRowSetImpl record = new CachedRowSetImpl();
    record.populate(rs);
    rs = stmt.executeQuery("select found_rows() as count");
    int totalRecord = 0;
    if(rs.next())
    {
     totalRecord = rs.getInt("count");
    }

我们在Java代码里面这样写ok不ok?

不一定,取决于用哪个版本的mysql-connector-J。下图是我针对目前流行的mysql-connector-J各版本的支持情况的测试:

 

图片

 

结论:目前大部分mysql-connector-J在上述编程方法情况下都有问题。难道必须要回退到3.0.10 版本?

我当然不甘心。

既然怀疑mysql-connector-J的代码有问题,那就把源码下载下来看看。

经过仔细检查,mysql-connector-J里面就没有对found_rows() 做处理。

到此陷入僵局,该从哪入手?

打开mysql 查询日志(mysql.ini配置[mysqld] log=XX.log)

111106 15:25:07     2 Connect ouyangshixiong@localhost on ouyangshixiong
      2 Query select SQL_CALC_FOUND_ROWS * from product where 1=1  order by pid asc limit 0,15
      2 Query SHOW CHARACTER SET
      2 Query SHOW FULL COLUMNS FROM `ouyangshixiong`.`product`
      2 Query SHOW FULL COLUMNS FROM `ouyangshixiong`.`product`
      2 Query SHOW FULL COLUMNS FROM `ouyangshixiong`.`product`
      2 Query SHOW FULL COLUMNS FROM `ouyangshixiong`.`product`
      2 Query SHOW FULL COLUMNS FROM `ouyangshixiong`.`product`
      2 Query SHOW FULL COLUMNS FROM `ouyangshixiong`.`product`
      2 Query SHOW FULL COLUMNS FROM `ouyangshixiong`.`product`
      2 Query SHOW FULL COLUMNS FROM `ouyangshixiong`.`product`
      2 Query select found_rows() as ct

哇塞,两次查询哪来的这么多query日志?

想一下,record.populate(rs);这条语句非常可疑了。我没能下载到CachedRowSetImpl源码,还好有些网站提供源代码浏览。(哪位朋友下到源码麻烦发给我一下13062981@qq.com ,或者告诉我官方下载方法,谢谢~)

读CachedRowSetImpl源码发现populate方法调用了initMetaData方法,它又调用了conn.getMetaData()。细心的朋友可能发现了,哪来的connection呢,我们的参数只传了ResultSet! 

获取的方法在这里:rs.getStatement().getConnection()。够bt,够隐蔽吧!

 

到此我们可以大胆猜测一下bug的来龙去脉:

    jdk程序员为了实现取Meta信息的功能,在CachedRowSetImpl默认发起了大量请求,没有通知外部调用者,甚至没有对found_rows() 必须要跟在select SQL_CALC_FOUND_ROWS 后面做兼容处理。他可能认为这应该由mysql程序员保证正确性。

mysql-connector-J的程序员没有仔细测试CachedRowSetImpl代码,且在新版本mysql里默认打开取Meta功能。

这里至少有2个问题:

1. 性能可能受影响,大量的SHOW FULL COLUMNS (我没有在生产环境下评估过)

2. SQL_CALC_FOUND_ROWS & found_rows()的失去原子性,产生正确性问题。

 

我继续来找解决方法:

http://bugs.mysql.com/bug.php?id=43571  看看这个bug反馈。是不是跟本文碰到的情况很相识?

mysql程序员给出解决方案:

http://dev.mysql.com/doc/refman/5.0/en/connector-j-reference-configuration-properties.html

 

 

图片

 

 

good!

我们修改连接配置:jdbc:mysql://localhost:3306/ouyangshixiong?user=ouyangshixiong&password=12345163&useUnicode=true&characterEncoding=UTF8&useDynamicCharsetInfo=false

设置useDynamicCharsetInfo参数为关闭。好了,在mysql5.1下我就可以自由使用 SQL_CALC_FOUND_ROWS found_rows() 了。

 

总结:开发环境调试日志要全开;对mysql要多研究,各种参数都要了解;多读点jdk源代码没坏处;碰到问题要耐心,认真。

0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics