3 什么叫预编译
预编译也就预处理,叫什么都行。它就是把SQL语句的模板生成一个函数,模板中的“?”就是函数的参数。当给“?”赋值之后,再执行SQL语句时,就是用参数来调用函数。
例如:SELECT * FROM tab_student WHERE s_number=?,这是一条SQL模板语句,当使用这个SQL模板获取PreparedStatement对象时,已经把这条SQL模板发送给了SQL服务器,这时SQL服务器会根据SQL模板生成一个函数一样的东西:详情讲看
functioin myfun(?) { … } |
当使用PreparedStatement为“?”设置了值后(pstmt.setString(1,”S_1001”),再去调用executeQuery()方法时,就是在使用参数调用函数一样:myfun(“S_1001”)。
4 预编译的好处
在没有使用预编译时,SQL服务器在执行每条SQL语句时都需要去查询SQL的语法是否正确,解析SQL语句,再去编译执行。其中执行的时间远远比不上查询语法、解析,以及编译要用的时间。
虽然在使用PreparedStatement时也需要做查询语法、解析,以及编译的工作,但是如果使用PreparedStatement执行多次的话,那么查询、解析,以及编译只会做一次。这就是它的好处。
所以,建议大家在今后的开发中,无论什么情况,都去需要PreparedStatement,而不是使用Statement。
5 MySQL默认预编译是关闭的(了解即可)
MySQL的驱动默认情况下是不会预编译SQL的,这需要我们把useServerPrepStmts参数设置为true,这样MySQL驱动就打开了预编译功能。可以在url中设置这个参数:
url=jdbc:mysql:///mydb1?useServerPrepStmts=true |
注意,当使用同一个PreparedStatement对象执行多次时,只需要编译一次。
String sql = “select * from tab_student where s_number=?”; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, “S_1001”); ResultSet rs = pstmt.executeQuery(); rs.close(); pstmt.clearParameters(); pstmt.setString(1, “S_1002”); rs = pstmt.executeQuery(); |
上面代码是多次使用同一个PreparedStatement对象执行操作,所以数据库只编译一次SQL模板,然后调用多次。看看下面代码是编译几次呢?
String sql = “select * from tab_student where s_number=?”; PreparedStatement pstmt1 = con.prepareStatement(sql); PreparedStatement pstmt2 = con.prepareStatement(sql); …… |
虽然使用的是相同的sql,但是返回的是两个不同的PreparedStatement对象,所以数据库还是要编译两次的。如果你希望Connection的prepareStatement()方法在sql相同时,返回相同的对象,即返回同一个PreparedStatement,那么就需要缓存PreparedStatement对象。
设置cachePrepStmts为true,表示缓存PreapredStatement。这时,就算多次获取PreparedStatement对象,但只要SQL模板相同,那么返回的就是相同的PreparedStatement对象,也就是不会再次编译SQL语句了。
String sql = “select * from tab_student where s_number=?”; PreparedStatement pstmt = con.prepareStatement(sql); pstmt.setString(1, “S_1001”); ResultSet rs = pstmt.executeQuery(); rs.close(); pstmt.close(); pstmt = con.prepareStatement(sql); pstmt.setString(1, “S_1002”); rs = pstmt.executeQuery(); |
使用prepStmtCacheSize变量来设置缓存PreparedStatement的上限。
例如prepStmtCacheSqlLimit变量来设置SQL模板的长度上限。
url=jdbc:mysql:///mydb1?useServerPrepStmts=true&cachePrepStmts=true&prepStmtCacheSize=50&prepStmtCacheSqlLimit=300 |
<!--EndFragment-->
<!--EndFragment-->