mybatis 07: sql标签中 "#{}" 和 "${}" 的作用和比较
"#{}"占位符
作用
- 传参大部分使用"#{}",在数据库底层使用的是:PreparedStatement预编译处理对象
- 数据库底层被解析为"?",用来传值,是安全的数据库访问,可以防止sql注入
- 通过在SqlMapConfig.xml添加日志输出配置,在后文测试输出的结果中可以验证
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 设置日志输出-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
写法
- "#{}"里参数的写法,要参考parameterType的类型
- 如果parameterType的类型是简单类型(8种基本类型(封装) + String类型),则"#{}"里变量名称任意
<!--
//根据用户主键查取用户信息
User getById();
-->
<select id="getById" resultType="user" parameterType="int">
select
id, username, birthday, sex, address
from
users
where
id=#{asYouLike}
</select>
- 如果parameterType的类型是实体类的类型,则"#{}"里只能是类中成员变量的名称,而且区分大小写
//User实体类中的属性
public class User {
private Integer id;
private String userName;
private Date birthday;
private String sex;
private String address;
}
<!--
//向用户表中增加用户信息
int insert(User user);
-->
<insert id="insert" parameterType="user">
insert into
users(username, birthday, sex, address)
values(#{userName}, #{birthday}, #{sex}, #{address})
</insert>
"${}"占位符
用于字符串的拼接和字符串的替换
字符串拼接
作用
- 一般用于模糊查询,建议少用,因为存在sql注入风险
写法
- "${}"中参数名称的写法,分两种情况,与"#{}"的两种情况相同,可参考之
- 注意:对于parameterType的类型是简单类型时,"${}"里变量名称随便写,但是分版本
- 如果是3.5.1及以下版本,只能写"value"
模糊查询示例
- 未优化前,存在sql注入风险
<!--
//根据用户名模糊查询用户信息
List<User> getByName(String name);
-->
<select id="getByName" parameterType="string" resultType="user">
select
id, username, birthday, sex, address
from
users
where username like '%${name}%'
</select>
- 优化后,使用"#{}"接受传参,底层是preparedStatement预编译对象,可以防止sql注入
<!--
//优化后的模糊查询
List<User> getByNameBetter(String name);
-->
<select id="getByNameBetter" parameterType="string" resultType="user">
select
id, username, birthday, sex, address
from
users
where username like concat('%', #{name}, '%')
</select>
字符串替换("${}"的主要作用)
需求:在users表中,根据地址或者用户名模糊查询用户信息
sql语句:
select * from users where username like '%模糊查询条件%'
select * from users where address like '%模糊查询条件%'
存在的问题:两条sql语句的结构在本质上是相同的,写两条语句十分冗余,可以采用替换列名的方式进行优化
UsersMapper.java接口
package com.example.mapper;
import com.example.pojo.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 数据访问层的接口,定义对数据库完成的CRUD的操作
*/
public interface UsersMapper {
//根据用户名或者地址模糊查询
List<User> getByNameOrAddress(
@Param("colName")
String colName,
@Param("userName")
String userName
);
}
- 接口分析:当接口中的方法的参数有多个时,用注解标识参数,sql标签可通过注解中声明的参数名获取参数
UsersMapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UsersMapper">
<!--
//根据用户名或者地址模糊查询
List<User> getByNameOrAddress(
@Param("colName")
String colName,
@Param("userName")
String userName);
-->
<select id="getByNameOrAddress" resultType="user">
select
id, username, birthday, sex, address
from
users
where
${colName} like concat('%', #{userName}, '%')
</select>
</mapper>
- sql标签分析
- 当标签对应的接口中的方法有多个参数时,标签中的入参类型,即:parameterType,取消不写,通过方法中注解的参数名称获取参数
- 用于替换时只可以使用"${}",应该放在like前。"#{}"用来传值,应该放在like后用来占位传值
测试代码
package com.example.mapper;
import com.example.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class TestUsersMapper {
//时间刷
SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
//SqlSession对象
SqlSession sqlSession;
//mybatis动态代理对象
UsersMapper usersMapper;
//获取SqlSession
@Before
public void getSqlSession() throws IOException {
//读取核心配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//创建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//获取SqlSession
sqlSession = factory.openSession();
//获取mybatis动态代理对象
usersMapper = sqlSession.getMapper(UsersMapper.class);
}
//归还SqlSession
@After
public void closeSession(){
sqlSession.close();
}
@Test
public void testGetByNameOrAddress(){
List<User> users = usersMapper.getByNameOrAddress("username", "小");
//List<User> users = usersMapper.getByNameOrAddress("address", "市");
users.forEach(System.out::println);
}
}
测试输出
根据用户名模糊查询
Checking to see if class com.example.mapper.TestUsersMapper matches criteria [is assignable to Object]
Checking to see if class com.example.mapper.UsersMapper matches criteria [is assignable to Object]
Opening JDBC Connection
Created connection 1293462056.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
==> Preparing: select id, username, birthday, sex, address from users where username like concat('%', ?, '%')
==> Parameters: 小(String)
<== Columns: id, username, birthday, sex, address
<== Row: 2, 小王, 2001-07-12, 1, 芜湖市
<== Row: 3, 小张, 1999-02-22, 1, 长沙
<== Row: 29, 小昕, 2001-03-14, 女, 忻州
<== Total: 3
Users{id=2, userName='小王', birthday=Thu Jul 12 00:00:00 CST 2001, sex='1', address='芜湖市'}
Users{id=3, userName='小张', birthday=Mon Feb 22 00:00:00 CST 1999, sex='1', address='长沙'}
Users{id=29, userName='小昕', birthday=Wed Mar 14 00:00:00 CST 2001, sex='女', address='忻州'}
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
Returned connection 1293462056 to pool.
Process finished with exit code 0
根据地址模糊查询
Checking to see if class com.example.mapper.TestUsersMapper matches criteria [is assignable to Object]
Checking to see if class com.example.mapper.UsersMapper matches criteria [is assignable to Object]
Opening JDBC Connection
Created connection 1293462056.
Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
==> Preparing: select id, username, birthday, sex, address from users where address like concat('%', ?, '%')
==> Parameters: 市(String)
<== Columns: id, username, birthday, sex, address
<== Row: 2, 小王, 2001-07-12, 1, 芜湖市
<== Row: 7, 学委, 2001-05-13, 2, 平顶山市
<== Total: 2
Users{id=2, userName='小王', birthday=Thu Jul 12 00:00:00 CST 2001, sex='1', address='芜湖市'}
Users{id=7, userName='学委', birthday=Sun May 13 00:00:00 CST 2001, sex='2', address='平顶山市'}
Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@4d18aa28]
Returned connection 1293462056 to pool.
Process finished with exit code 0
测试结果分析
- sql标签在底层分别被解析为
==> Preparing: select id, username, birthday, sex, address from users where username like concat('%', ?, '%')
==> Parameters: 小(String)
==> Preparing: select id, username, birthday, sex, address from users where address like concat('%', ?, '%')
==> Parameters: 市(String)
- 由上可知
- 标签中的${colName}分别被替换成了传入的"username"和"address",起到了替换作用
- "#{}"被解析成"?",#{userName}分别拿到值:小(String)和市(String),起到占位传值作用
mybatis 07: sql标签中 "#{}" 和 "${}" 的作用和比较的更多相关文章
- 9.mybatis动态SQL标签的用法
mybatis动态SQL标签的用法 动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么 ...
- Mybatis笔记 - SQL标签方法
Mpper.xml映射文件中定义了操作数据库的sql,并且提供了各种标签方法实现动态拼接sql.每个sql是一个statement,映射文件是mybatis的核心. 一.内容标签 1.NamePlac ...
- MyBatis 动态 SQL 语句中出现 '<' 的问题
问题描述 映射接口方法如下: /** * 根据姓名和年龄查询用户信息 * @param name 姓名 * @param user 获取年龄 * @return */ public List<U ...
- mybatis动态SQL标签的用法
动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格 ...
- sql语句中having的作用是?
HAVING对由sum或其它集合函数运算结果的输出进行限制.比如,我们可能只希望看到Store_Information数据表中销售总额超过1500美圆的商店的信息,这时我们就需要使用HAVING从句. ...
- Mybatis+MySql 一个标签中执行多条sql语句 这个坑 ,我心中有一句MMP
解决办法 转自网友: 亲测 解决了问题@ MySql默认是不支持这种骚操作的,但是并不代表不能实现,只需要在jdbc的配置文件中稍做配置: driver=com.mysql.jdbc.Driverur ...
- Mybatis+MySql 一个标签中执行多条sql语句
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/cxfly957/article/details/77896590 MySql默认是不支持这种骚操作的 ...
- Mybatis 动态sql标签
1.动态SQL片段 通过SQL片段达到代码复用 <!-- 动态条件分页查询 --> <sql id="sql_count"> ...
- MyBatis 动态sql标签trim
https://blog.csdn.net/zhangxing52077/article/details/75041053 序列序号在Mybatis中的使用的使用 将获得序列值获取返回到对象code字 ...
随机推荐
- vue3常见问题及解决方案(四)父组件切换行,然后子组件切换tab,子组件内的数据不刷新
问题描述 父组件切换行,然后子组件切换tab,子组件内的数据不刷新. 例如父组件为订单,子组件为订单相关商品和相关客户,商品和客户使用tab选项卡组织. 当tab显示商品页时,切换订单,商品页内容跟着 ...
- hihocoder 1193 树堆 解题报告
题目大意:给出一棵有根树(根为 \(0\) ),点有点权.可以删除点(非根),并将其子树接到其父亲上.我们称一个树为树堆当前仅当树上每个点都满足其权值大于等于其子树中所有点的点权.现在对于每个点要求其 ...
- String 为什么不可变?
转载来源:String为什么不可变 今天来分享一道群友去阿里云面试遇到的 Java 基础面试真题:"String.StringBuffer.StringBuilder 的区别?String ...
- 渗透测试之sql注入点查询
一切教程在于安全防范,不在于攻击别人黑别人系统为目的 寻找sql注入点方法: 拿到网页后进行查找注入点: 1.通过单引号 ' ; 在 url 后面输入单引号进行回车(如果报错可能存在sql注入为 ...
- 解决Mysql搭建成功后执行sql语句报错以及区分大小写问题
刚搭建完mysql 8.0以后会: 一.表区分大小写, 二.执行正确的sql语句成功且会报:[Err] 1055 - Expression #1 of ORDER BY clause is not i ...
- Python数据分析--Numpy常用函数介绍(6)--Numpy中矩阵和通用函数
在NumPy中,矩阵是 ndarray 的子类,与数学概念中的矩阵一样,NumPy中的矩阵也是二维的,可以使用 mat . matrix 以及 bmat 函数来创建矩阵. 一.创建矩阵 mat 函数创 ...
- C++对象间通信组件,让C++对象“无障碍交流”
介绍 这是很久之前的一个项目了,最近刚好有些时间,就来总结一下吧! 推荐初步熟悉项目后阅读本文: https://gitee.com/smalldyy/easy-msg-cpp 从何而来 这要从我从事 ...
- JS:函数的几种写法1
1.构造函数: var fn = new function(); 2.声明式: function fn(){}; 3.匿名函数(又称自调用函数): (function(){})(); 4.表达式: v ...
- 你真的很了解printf函数吗?
对C语言中经常使用的printf这个库函数,你是否真的吃透了呢? 系统化的学习C语言程序设计,是不是看过一两本C语言方面的经典著作就足够了呢?答案是显而易见的:不够.通过这种典型的入门级的学习方式,是 ...
- 3D可视化解决方案为巷道工程安全护航
最近山东栖霞笏山金矿事故中被困22名矿工的生命安全,在揪着全国民的心.大家都在祈求他们能从井下活着回来. 正是由于被困矿工的坚韧意志和政府相关部门不眠不休的奋力营救,11名矿工终于在被困十余日后平安升 ...