- 预编译:数据库服务器在收到SQL语句后,会先去预编译缓存中查找该语句预编译的结果,如果找不到,则对SQL语句进行编译并将编译结果存入预编译缓存。
- 客户端开启预编译,需要在建立连接时配置
useServerPrepStmts=true&cachePrepStmts=true
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test?useServerPrepStmts=true&cachePrepStmts=true"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
-
预编译的优点:在需要大量重复执行且只是参数不同的SQL语句,可以先将参数设置成占位符再交给数据库服务器进行预编译,这样后续的SQL语句不需要进行编译直接利用对应的编译结果进行参数设置再执行即可。
-
PreparedStatement:支持预编译和参数设置。在预编译/编译后再进行参数设置和执行。
-
Statement:不支持预编译和参数设置,直接发送SQL语句给数据库服务器进行编译和执行。
-
#{xxx}:当statementType等于默认的PREPARED时,Mybatis会将SQL语句中的#{xxx}换成占位符,再交给数据库服务器进行预编译/编译、参数设置和执行。当statementType等于STATEMENT时,会因占位符不能被识别而报错,因为Statement会直接进入编译和执行步骤,缺少参数设置方法。
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select id, name, dept_id
from employee
where id = #{id,jdbcType=BIGINT}
</select>
输出(statementType等于默认的PREPARED。要进行预编译的SQL语句里面的#{id}处用占位符 ? 替代)
2022-04-06 02:22:00,144 [main] DEBUG [com.wsh.mapper.EmployeeMapper.selectByPrimaryKey] - ==> Preparing: select id, name, dept_id from employee where id = ?
2022-04-06 02:22:00,173 [main] DEBUG [com.wsh.mapper.EmployeeMapper.selectByPrimaryKey] - ==> Parameters: 1(Long)
2022-04-06 02:22:00,195 [main] DEBUG [com.wsh.mapper.EmployeeMapper.selectByPrimaryKey] - <== Total: 1
- ${xxx}:当statementType等于默认的PREPARED时,Mybatis首先将参数放入SQL语句,再交给数据库服务器进行预编译/编译、参数设置和执行,此处参数设置步骤没有任务。当statementType等于STATEMENT时,Mybatis首先将参数放入SQL语句,再交给数据库服务器进行编译和执行。 ${xxx}一般用于传输关于表或字段信息的值。
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
select id, name, dept_id
from employee
where id = ${id,jdbcType=BIGINT}
</select>
输出(发送给数据库服务器进行预编译的SQL语句里面的${id}直接替换为对应参数值,但由于statementType等于默认的PREPARED,仍然有参数设置的步骤)
2022-04-06 02:25:00,149 [main] DEBUG [com.wsh.mapper.EmployeeMapper.selectByPrimaryKey] - ==> Preparing: select id, name, dept_id from employee where id = 1
2022-04-06 02:25:00,175 [main] DEBUG [com.wsh.mapper.EmployeeMapper.selectByPrimaryKey] - ==> Parameters:
2022-04-06 02:25:00,199 [main] DEBUG [com.wsh.mapper.EmployeeMapper.selectByPrimaryKey] - <== Total: 1
#{xxx}的优点:
防止SQL注入。在编译前用占位符替换#{xxx},得到的编译结果的语法逻辑是确定好的,SQL语句中的占位符只是充当参数的作用。