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字 ...
随机推荐
- 主管发话:一周搞不定用友U8 ERP跨业务数据分析,明天就可以“毕业”了
随着月末来临,又到了汇报总结的时刻. (图片来自网络) 到了这个特殊时期,你的老板就一定想要查看企业整体的运转情况.销售业绩.客户实况分析.客户活跃度.Top10 sales. 产品情况.订单处理情况 ...
- [NOI2011]阿狸打字机
题意:一开始是个空串s,有三种操作:(1.末尾加一个字符 2.末尾减一个字符 3.存储该字符串) 思路: 一开始在trie树上动态加点很好处理,3操作的时候记录一下此时trie树上的pos,同时记录d ...
- 测试open
// 此处,返回的 undefined 是 JS 中的一个值 return undefined } // 这种写法是明确指定函数返回值类型为 void,与上面不指定返回值类型相同 const add ...
- 从零开始实现lmax-Disruptor队列(一)RingBuffer与单生产者、单消费者工作原理解析
1.lmax-Disruptor队列介绍 disruptor是英国著名的金融交易所lmax旗下技术团队开发的一款java实现的高性能内存队列框架 其发明disruptor的主要目的是为了改进传统的内存 ...
- 攻防世界pwn题:forgot
0x00:查看文件信息 该文件是32位的,canary和PIE保护机制没开. 0x01:用IDA进行静态分析 总览: 该函数就是:v5初值为1,对v2输入一串字符.然后执行一个会根据输入的字符串而修改 ...
- 30.Mysql主从复制、读写分离
Mysql主从复制.读写分离 目录 Mysql主从复制.读写分离 读写分离 读写分离概述 为什么要读写分离 什么时候要读写分离 主从复制与读写分离 mysql支持的复制类型 主从复制的工作过程 初始环 ...
- HDLBits->Verilog Language->Modules:Hierarchy->Modules and vectors
题目要求如上不再赘述,主要关注到最后的四选一多路选择器. 最初编写的选择器代码如下 always@(sel) case(sel) 2'd0:q <= d; 2'd1:q <= in1; 2 ...
- RPA应用场景-报税机器人
场景概述 报税机器人 所涉系统名称 税务网站 人工操作(时间/次) 53分钟 所涉人工数量 60 操作频率 每月 场景流程 1.通过RPA自动将财税信息从对应系统中导出 2.RPA根据不同的税务报表规 ...
- RPA应用场景-账套建立
所涉人工数量5操作频率 不定时 场景流程 1.客户按照项目开设专项财务管理,每个项目需要在初期建立自己的账套: 2.运营专员通过邮件发送账套建立申请: 3.根据申请进入金蝶运维后台,依据规则完成账套建 ...
- sql-sql优化
SQL执行流程 a. 编写过程: select dinstinct .. from .. join .. on .. where .. group by .. having .. order by . ...