"#{}"占位符

作用

  • 传参大部分使用"#{}",在数据库底层使用的是: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标签中 "#{}" 和 "${}" 的作用和比较的更多相关文章

  1. 9.mybatis动态SQL标签的用法

    mybatis动态SQL标签的用法   动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么 ...

  2. Mybatis笔记 - SQL标签方法

    Mpper.xml映射文件中定义了操作数据库的sql,并且提供了各种标签方法实现动态拼接sql.每个sql是一个statement,映射文件是mybatis的核心. 一.内容标签 1.NamePlac ...

  3. MyBatis 动态 SQL 语句中出现 '<' 的问题

    问题描述 映射接口方法如下: /** * 根据姓名和年龄查询用户信息 * @param name 姓名 * @param user 获取年龄 * @return */ public List<U ...

  4. mybatis动态SQL标签的用法

    动态 SQL MyBatis 的强大特性之一便是它的动态 SQL.如果你有使用 JDBC 或其他类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句有多么痛苦.拼接的时候要确保不能忘了必要的空格 ...

  5. sql语句中having的作用是?

    HAVING对由sum或其它集合函数运算结果的输出进行限制.比如,我们可能只希望看到Store_Information数据表中销售总额超过1500美圆的商店的信息,这时我们就需要使用HAVING从句. ...

  6. Mybatis+MySql 一个标签中执行多条sql语句 这个坑 ,我心中有一句MMP

    解决办法 转自网友: 亲测 解决了问题@ MySql默认是不支持这种骚操作的,但是并不代表不能实现,只需要在jdbc的配置文件中稍做配置: driver=com.mysql.jdbc.Driverur ...

  7. Mybatis+MySql 一个标签中执行多条sql语句

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/cxfly957/article/details/77896590 MySql默认是不支持这种骚操作的 ...

  8. Mybatis 动态sql标签

    1.动态SQL片段 通过SQL片段达到代码复用         <!-- 动态条件分页查询 -->          <sql id="sql_count"> ...

  9. MyBatis 动态sql标签trim

    https://blog.csdn.net/zhangxing52077/article/details/75041053 序列序号在Mybatis中的使用的使用 将获得序列值获取返回到对象code字 ...

随机推荐

  1. IDEA快捷生成循环♻️

    itar 生成array for代码块 //itar for (int i = 0; i < array.length; i++) { = array[i]; } itco 生成Collecti ...

  2. 04C++核心编程

    Day01 笔记 1 C++概述 1.1 C++两大编程思想 1.1.1 面向对象 1.1.2 泛型编程 1.2 移植性和标准 1.2.1 ANSI 在1998制定出C++第一套标准 2 c++初识 ...

  3. 【SpringSecurity系列2】基于SpringSecurity实现前后端分离无状态Rest API的权限控制原理分析

    源码传送门: https://github.com/ningzuoxin/zxning-springsecurity-demos/tree/master/01-springsecurity-state ...

  4. python基础学习7

    python基础学习7 内容概要 字符串的内置方法 字符串的内置方法(补充) 列表的内置方法 可变类型与不可变类型 队列与堆栈 内容详情 字符串的内置方法 # 1.strip 移除字符串首尾的指定字符 ...

  5. csv.reader(f)和f.readlines()、追加数据

    假如某个文档f中存储如下内容: 你好,中国. 1,2,3,4 共两行内容. 当你使用csv.reader(f),则会存储为如下形式: [['你','好','中','国'] ['1','2','3',' ...

  6. 为什么要使用TypeScript(Why Typescript?)

    客观原因 静态类型. 在编译期即可进行静态类型分析, 减少JS运行时类型错误. 语法功能强大 对于大型项目具有更好构建机制,加入了类.接口.泛型.模块等概念. 兼容JavaScript 与现存的Jav ...

  7. python logging模块使用方法

    # -*- coding: utf-8 -*- # @ModuleName: logger # @Time: 2022/6/10 11:48 # @Author : Free-A # @Descrip ...

  8. Vscode个性化设置:让一个小萌妹陪你敲代码

    前言 大家平时都用什么代码编辑器啊!我个人比较喜欢用vscode,因为有以下几点: 开源,免费: 自定义配置 集成git 智能提示强大 支持各种文件格式(html/jade/css/less/sass ...

  9. arcgis创建postgre企业级数据库

    什么是企业级地理数据库? 企业级地理数据库(ArcSD Enterprise,sde)是和 arcGIS 套件集成程度最高的地理数据库:创建时需要用到安装 arcGIS Server 时的 [ecp ...

  10. Python快速下载商品数据,并连接数据库,保存数据

    开发环境 python 3.8 pycharm 2021.2 专业版 代码实现 发送请求 获取数据 解析数据(筛选数据) 保存数据 连接数据库 开始代码 请求数据 # 伪装 headers = { ' ...