相信使用MySQL的同学都配置过它的JDBC驱动,多数人会直接从哪里贴一段URL过来,然后稍作修改就上去了,对应的连接池配置也是一样的,很少有人会去细想这每一个参数都是什么含义。今天我们就来聊两个比较常见的配置是否要开启autoReconnect和是否缓存PreparedStatement。 笔者看到过很多MySQL的URL里都是这样写的,复制过来改改IP、端口和库名就能用了: 从字面上看挺好的,在连接断开后还会自动重连,加之MySQL有8小时自动断开连接的特性,在断开后连接会重连,多好的功能呀。但是如果你去阅读一下MySQL Connect/J开发手册的相关章节,就会看到官方是这么说明的:
简单来说,不推荐开启这个特性,因为有副作用,在没有正确处理SQLException时容易造成会话状态和数据一致性的问题。 一般的应用都会使用数据库连接池,那我们的连接池是否正确地处理了抛出的SQLException呢?抱着这个疑问,我们来看看阿里的Druid连接池是怎么处理的。 首先,通过设置合理的健康检查及连接存活时间能解决大部分问题;其次,它有针对特定异常的处理逻辑,在MySqlExceptionSorter中会对特定返回码、异常类(比如com.mysql.jdbc.Communication**ception和com.mysql.jdbc.exceptions.jdbc4.Communication**ception)以及错误消息进行处理,如果是致命错误就把连接抛弃。也就是说,如果用了Druid,不管是否设置了autoReconnect,都能保证后续请求的正确处理。JBoss的连接池实现也有类似的特性。 一般在设置连接池时,都会有类似下面的设置: 很多文章上都说PSCache对使用游标的数据库有巨大的性能提升,但MySQL不建议开启,因为它不支持游标。所以很多人在用MySQL时,都会将poolPreparedStatements设置为false,就连Druid的文档上也是这么写的。 但事实真的是这样么,MySQL使用PSCache真的对性能没有提升么? 先来看看关于游标的问题,其实大部分文章的表述不太准确,现在的MySQL在存储过程里是支持游标的,但其他地方的确不支持,具体详见官方手册(MySQL supports cursors inside stored programs.)。但这并不是我们要讨论的关键。 3.1.0版本后的JDBC驱动里有一个参数是useServerPrepStmts,如果服务器支持的话,会开启服务端PreparedStatement,默认是false。官方手册中有如下说明:
也就是说在MySQL 4.1.0版本后,3.1.0以上的驱动会检测到支持服务端PreparedStatement,并且启用该特性。根据MySQLTUTORIAL上的说明,整个过程分为PREPARE、EXECUTE和DEALLOCATE PREPARE三步。MySQL JDBC驱动的Contributor Jess Balint在StackOverflow上做了一个详细的说明,《High-Performance Java Persistence》的作者也专门撰写文章分析了两者的区别。 上述代码在使用客户端PreparedStatement时,MySQL日志里看到的是: 如果用的是服务端PreparedStatement,看到的则是(实际每次执行只会传占位符的值,语句是不传的): 在整个使用过程中,Prepare只会做一次,在这时服务端会对语句进行解析,后续收到具体值时会优化执行计划。如果同一条语句每次都新建PreparedStatement,那么每次都会多一回网络交互和语句解析,这显然是可以优化的。 综上所述,现在在使用MySQL时(如果版本比较新的话),出于性能考虑,应该在数据库连接池上开启针对PreparedStatement的缓存。如果没有使用连接池,或者所用的连接池不支持PSCache,也可以在JDBC连接上设置cachePrepStmts=true。 事实上,MySQL的JDBC驱动还有不少针对性能的优化,比如设置useConfigs=maxPerformance(请酌情使用),相当于同时做了如下设置: 各位同学,是时候检视一下自己的系统是如何连接MySQL的了。 时代在发展,有些以前适用的配置也许就不再合适了。 |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|