前言
今天又去水了一波,结果有个问题居然忘记了,myBatis中的#和$有什么区别?
实验
1、使用# mybatis Mapper.xml配置如下:
<select id="selectByFuzzy" resultMap="BaseResultMap">
select * from test_case where case_name like #{testCaseName} or busi_code like #{testCaseName} or case_name_zh like #{testCaseName}
</select>
查询语句以及结果如下:
==> Preparing: select * from test_case where case_name like ? or busi_code like ? or case_name_zh like ?
==> Parameters: do_queryUsableBalance(String), do_queryUsableBalance(String), do_queryUsableBalance(String)
<== Columns: id, case_name, user_id, request, expected_response, ignore_fields, create_date, last_update_date, busi_code, result_response, result, result_type, url, ext3, ext2, ext1, case_name_zh, test_result_file_name
<== Row: 1, do_queryUsableBalance, 1001, <<BLOB>>, <<BLOB>>, errorMsg, 2023-03-01 15:01:17, 2021-12-08 17:33:45, 7064, <<BLOB>>, <<BLOB>>, 0, null, null, null, null, 查询可用余额, 49456.html
<== Total: 1
可以看出#{}占位符最终被替换为了jdbc中常用的?占位符。
2、使用$ mybatis Mapper.xml配置如下:
<select id="selectByFuzzy" resultMap="BaseResultMap">
select * from test_case where case_name like ${testCaseName} or busi_code like ${testCaseName} or case_name_zh like ${testCaseName}
</select>
执行结果如下:
==> Preparing: select * from test_case where case_name like do_queryUsableBalance or busi_code like do_queryUsableBalance or case_name_zh like do_queryUsableBalance
==> Parameters:
其实最终的运行结果是报错了。但是光看这句sql其实就可以发现这是一个错误的语句。
原理
使用#号从sql语句中我们可以发现这种操作类似于原生jdbc的prepareStatement方式,jdbc写法如下:
String sql = "insert into ZD.Group_cust_mapper(cust_id, acct_id) values(?, ?)";
stmtPreparedMysql = connMysql.prepareStatement(sql);
stmtPreparedMysql.setString(1, custId);
stmtPreparedMysql.setString(2, acctId);
stmtPreparedMysql.executeUpdate();
stmtPreparedMysql.close();
使用$符原理就是使用Statement的方式操作sql,需要将sql提前拼接好。jdbc写法如下:
@Test
public void test2(){
Connection conn = null;
Statement stmt = null;
try{
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/test?serverTimezone=Asia/Shanghai",
"root",
"123456");
stmt = conn.createStatement();
List<String> whitelistAll = new LinkedList<String>();
String sql="select * from test_case where case_name like 'do_queryUsableBalance' or busi_code like 'do_queryUsableBalance' or case_name_zh like 'do_queryUsableBalance'";
//int deleted=stmt.executeUpdate(sql);
ResultSet result = stmt.executeQuery(sql);
result.setFetchSize(1); // 游标一个一个读
int sum = 0;
while(result.next()) {
sum ++;
}
System.out.println(sum);
} catch (Exception e) {
System.out.print(e.getMessage());
e.printStackTrace();
} finally {
try {
stmt.close();
conn.close();
} catch (SQLException e) {
System.out.print("Can't close stmt/conn because of " + e.getMessage());
}
}
}
Statement
- 每次通过Statement执行SQL语句时,都要将SQL语句发送给数据库服务器进行编译,因此执行速度比较慢。
- Statement不能防止SQL注入攻击。
PreparedStatement:
- 在创建PreparedStatement时,就已经预编译了SQL语句,可以多次执行,因此执行速度快。
- PreparedStatement会在执行时将输入参数进行参数化处理,可以防止SQL注入攻击。
什么情况下必须要使用$占位符
比如目标sql是这样的:select name, age, school from student where score > 60 order by age desc;
那么如果使用mybatis时,mapper.xml就需要这样配置:
<select id="selectStudent" resultMap="BaseResultMap">
select name, age, school from student where score > #{score} order by ${age} desc;
</select>