日期:2014-05-16  浏览次数:20785 次

MySQL PrepareStatement基本的两种模式&客户端空间占用的源码分析

关于预编译(PrepareStatement),对于所有的JDBC驱动程序来讲,有一个共同的功能,就是“防止SQL注入”,类似Oracle还有一种“软解析”的概念,它非常适合应用于OLTP类型的系统中。

在JDBC常见的操作框架中,例如ibatis、jdbcTemplate这些框架对JDBC操作时,默认会走预编译(jdbcTemplate如果没有传递参数,则会走createStatement),这貌似没有什么问题。不过在一个应用中发现了大量的预编译对象导致频繁GC,于是进行了源码上的一些跟踪,写下这篇文章,这里分别从提到的几个参数,以及源码中如何应用这几个参数来说明。

看看有那些参数:

MySQL JDBC是通过其Driver的connenct方法获取到连接,然后可以将连接参数设置在JDBC URL或者Properties中,它会根据这些参数来创建一个Connection,简单说来就是将这些参数解析为K-V结构,交给Connection的对象来解析,Connection会将它们解析为自己所能识别的许多属性中,这个属性的类型为:ConnectionProperty,当然有许多子类来实现不同的类型,例如:BooleanConnectionProperty、IntegerConnectionProperty是处理不同参数类型的。

这些参数会保存在Connection对象中(在源码中,早期的版本,源码的类名就叫:com.mysql.jdbc.Connection,新版本的叫做:com.mysql.jdbc.ConnectionImpl,抽象了接口与实现类,这里统一称Connection的对象);具体是保存在这个Connection的父类中,这里将几个与本题相关的几个参截取出来,如下所示:

private BooleanConnectionProperty cachePreparedStatements = new BooleanConnectionProperty(
            "cachePrepStmts", //$NON-NLS-1$
            false,
            Messages.getString("ConnectionProperties.cachePrepStmts"), //$NON-NLS-1$
            "3.0.10", PERFORMANCE_CATEGORY, Integer.MIN_VALUE); //$NON-NLS-1$
private IntegerConnectionProperty preparedStatementCacheSize = new IntegerConnectionProperty(
            "prepStmtCacheSize", 25, 0, Integer.MAX_VALUE, //$NON-NLS-1$
            Messages.getString("ConnectionProperties.prepStmtCacheSize"), //$NON-NLS-1$
            "3.0.10", PERFORMANCE_CATEGORY, 10); //$NON-NLS-1$
private IntegerConnectionProperty preparedStatementCacheSqlLimit = new IntegerConnectionProperty(
            "prepStmtCacheSqlLimit", //$NON-NLS-1$
            256,
            1,
            Integer.MAX_VALUE,
            Messages.getString("ConnectionProperties.prepStmtCacheSqlLimit"), //$NON-NLS-1$
            "3.0.10", PERFORMANCE_CATEGORY, 11); //$NON-NLS-1$
private BooleanConnectionProperty detectServerPreparedStmts = new BooleanConnectionProperty(
            "useServerPrepStmts", //$NON-NLS-1$
            false,
            Messages.getString("ConnectionProperties.useServerPrepStmts"), //$NON-NLS-1$
            "3.1.0", MISC_CATEGORY, Integer.MIN_VALUE); //$NON-NLS-1$


找到这个通常要看看获取它的方法名,显然实际执行的时候,一般用方法来获取,而且这里的类型是private,也就是子类不可见,直接访问如果不通过变通手段访问不到;也许我们搞Java的第一眼看到的就是就是属性名的get方法嘛,有些时候MySQL这个该死的就是不按照常规思路走,例如它对属性:“detectServerPreparedStmts”的获取方法是:“getUseServerPreparedStmts()”,如下图: