深入理解statement

0 概述

Statement 是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。

1 JDBC 使用流程

如下图所示,JDBC和相应的数据进行连接是由相应的驱动进行建立连接,连接可以创建不同Statement,然后由Statement接口向数据库发送要执行的SQL语句。
这里写图片描述

2 几种Statement对比

这里写图片描述

  • Statement, 用于执行静态的sql语句或者说拼装好的sql语句
  • PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句。
  • CallableStatement 对象用于执行对数据库已存在的存储过程的调用。
    PreparedStatement接口相比于Statement,有以下几个重要的特点:
    提高安全,防SQL注入:Statement这种直接拼接sql的方式,容易发生sql注入,因此你就应该始终以PreparedStatement代替Statement(mybatis框架默认的就是PreparedStatement)。
    预编译技术提高性能:PreparedStatement 创建后,向Server端发送执行带有占位符的SQL语句,把SQL语句在Server端的执行计划和执行逻辑缓存起来,通过参数来调用,减少Sql编译等过程,这里值得强调是在实际使用中mysql不一定开启了预编译技术,具体见后面分析,这个和具体的mysql版本也有一定的关系
    参数转义、编码简洁:Statement 所有的参数需要我们自己拼接好,这样就比较恶心而且有的参数比较难拼接。

看下面程序,首先开启mysql(本文使用的mysql Server版本5.7.13)的SQL执行过程日志,具体开启可以参考:MySQL开启general_log跟踪数据执行过程

import java.sql.*;

/**
 * Created by hsc on 16/8/27.
 */
public class JdbcTest {
    private static final String DRIVER = "com.mysql.jdbc.Driver";
    private static String userName = "mysql"; //连接数据库用户名
    private static String password = "test";//连接数据库的密码
    private static String connectionUrl = "jdbc:mysql://127.0.0.1:3306/test";


    public static void usePreparedStatement(String sql) throws Exception {

        Class.forName(JdbcTest.DRIVER);
        //数据库的连接
        Connection connection = DriverManager.getConnection(connectionUrl, userName, password);
        //预编译的Statement 向数据库发送sql语句,数据库那边进行编译,数据那边将编译结果存放在缓存
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        long start = System.currentTimeMillis();
        preparedStatement.setObject(1, 10);
        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet == null) {
            return;
        }
        while (resultSet.next()) {
            System.out.println(resultSet.getString(1));
        }
        preparedStatement.close();
        resultSet.close();
        connection.close();

    }



    public static void main(String args[]) throws Exception {
        //问号表示占位符
        String sql = "select * from Users limit ?";
        usePreparedStatement(sql);
    }
}

运行程序,观察执行日志(发现没有预编译):
2017-11-29T14:10:47.695703Z   35 Query  SET NAMES latin1
2017-11-29T14:10:47.696114Z   35 Query  SET character_set_results = NULL
2017-11-29T14:10:47.696784Z   35 Query  SET autocommit=1
2017-11-29T14:10:47.831764Z   35 Query  select * from Users limit 10
2017-11-29T14:10:47.836862Z   35 Quit   

当我们把connectUrl 换成 “jdbc:mysql://127.0.0.1:3306/test?useServerPrepStmts=true&cachePrepStmts=true”;参数说明:useServerPrepStmts 表示是否在sever端使用预编译,cachePrepStmts表示是否在Server端缓存预编译的SQL。更多可以参考官网:JDBC URL 语法

运行程序,观察执行日志(发现有预编译Prepare):
2017-11-29T14:14:34.665887Z   36 Query  SET NAMES latin1
2017-11-29T14:14:34.666278Z   36 Query  SET character_set_results = NULL
2017-11-29T14:14:34.666956Z   36 Query  SET autocommit=1
2017-11-29T14:14:34.696959Z   36 Prepare    select * from Users limit ?
2017-11-29T14:14:34.698873Z   36 Execute    select * from Users limit 10
2017-11-29T14:14:34.704005Z   36 Quit   

3 总结

应该始终以PreparedStatement代替Statement,要开启预编译功能还需要在连接的URL带上特定参数。

参考文献
http://lj6684.iteye.com/blog/1520681
https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-configuration-properties.html
http://cs-css.iteye.com/blog/1847772

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值