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字 ...
随机推荐
- 使用pdfcrack & crunch暴力破解PDF密码
crunch是密码字典生成器,可以根据指定的字符来生成组合密码字典. pdfcrack是Linux下一个PDF暴力破解密工具,可以使用crunch生成的密码字典来暴力破解PDF文件的密码. 注:没有强 ...
- Spark: 单词计数(Word Count)的MapReduce实现(Java/Python)
1 导引 我们在博客<Hadoop: 单词计数(Word Count)的MapReduce实现 >中学习了如何用Hadoop-MapReduce实现单词计数,现在我们来看如何用Spark来 ...
- SQL语言DDL
MySQL数据库基本操作-DDL -- ctrl+/和# :注释 -- SQL语言不区分大小写: DDL:数据定义语言: 对数据库的常用操作: -- 查看所有的数据库: show databases; ...
- 从单例谈double-check必要性,多种单例各取所需
theme: fancy 前言 前面铺掉了那么多都是在讲原则,讲图例.很多同学可能都觉得和设计模式不是很搭边.虽说设计模式也是理论的东西,但是设计原则可能对我们理解而言更加的抽象.不过好在原则东西不是 ...
- jenkins 自动化部署vue前端+java后端项目 进阶一
今天又不想写了,那么我来将我参考的文章直接分享给大家好了,大家也可以直接进行参考: 这里以centos7为例搭建自动化部署项目: 1.搭建部署前端服务代理nginx: 借鉴于:https://blog ...
- 李呈祥:bilibili在湖仓一体查询加速上的实践与探索
导读: 本文主要介绍哔哩哔哩在数据湖与数据仓库一体架构下,探索查询加速以及索引增强的一些实践.主要内容包括: 什么是湖仓一体架构 哔哩哔哩目前的湖仓一体架构 湖仓一体架构下,数据的排序组织优化 湖仓一 ...
- python 基础知识-day10(面向对象)
1.面向对象的概念 拥有共同属性的一类进行归类的过程叫做面向对象. 2.注意事项 class定义类的时候,类名的首字母必须大写 3.面向对象案例 1 class Person(object): 2 d ...
- RPA人力资源简历筛选机器人
简历自动筛选及分析机器人,支持前程无忧.猎聘 1.自动登录招聘网站 2.自动填充简历筛选条件 3.RPA依次读取所筛选的简历信息 4.自动将简历数据复制到本地文档中 5.完成简历信息收集及分析表 6. ...
- 使用.NetCore自带的后台作业,出入队简单模拟生产者消费者处理请求响应的数据
环境:Core:3.1的项目 说明:由于该方案为个人测试项目,重启时队列中的部分数据很可能会丢失, 对数据有要求的该方案不适用,不能照搬需要持久化处理, 另外发布到Linux Docker中通常不会自 ...
- Java中时间方法大全01(持续更新)
下面这些方法都可以封装到一个工具类中 /** * 获取当前时间的时间戳 */ public static int getCurrentTimeIntValue() { return (int) (Sy ...