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字 ...
随机推荐
- Hadoop常见shell命令
Hadoop中常见的shell命令 1.如何将Linux本地的数据上传到HDFS中? hadoop fs -put 本地的文件 HDFS中的目录hdfs dfs -put 本地的文件 HDFS中的目录 ...
- 一文学完Linux Shell编程,比书都好懂
一. Shell 编程 1. 简介 Shell 是一个用 C 语言编写的程序,通过 Shell 用户可以访问操作系统内核服务. Shell 既是一种命令语言,又是一种程序设计语言. Shell scr ...
- Tarjan入门
Tarjan系列!我愿称Tarjan为爆搜之王! 1.Tarjan求LCA 利用并查集在一遍DFS中可以完成所所有询问.是一种离线算法. 遍历到一个点时,我们先将并查集初始化,再遍历完一个子树之后,将 ...
- 如何在 pyqt 中捕获并处理 Alt+F4 快捷键
前言 如果在 Windows 系统的任意一个窗口中按下 Alt+F4,默认行为是关闭窗口(或者最小化到托盘).对于使用了亚克力效果的窗口,使用 Alt+F4 最小化到托盘,再次弹出窗口的时候可能出现亚 ...
- 2021年第十二届蓝桥杯javaA组省赛部分题目
试题 D: 路径 本题总分:10 分 [问题描述] 小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图 中的最短路径. 小蓝的图由 2021 个结点组成,依次编号 1 至 2021. 对 ...
- MTK 平台sensor arch 介绍-scp
架构介绍 路径:vendor/mediatek/proprietary/tinysys/scp 1.[build]编译相关 2.[driver]scp 的driver,I2C,power,eint 3 ...
- bintree
Python实现二叉树的建立与遍历 创建(二叉)树节点类 class Node: def __init__(self,data,l=None,r=None): self.val = data self ...
- .NET中检测文件是否被其他进程占用
更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月2日. 一.检测文件是否被进程占用的几种方式 在.NET中主要有以下方式进行检测文件是否被进程占用的几种方式: 通过直接打开文件等 ...
- SAP 定义用户组
SUGR,可进行创建.查看.删除等维护性操作,并可指定本组的用户
- (数据科学学习手札139)geopandas 0.11版本重要新特性一览
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,就在几天前,geopandas ...