mybatis : sql标签中 "#「」" 和 "$「」" 的作用和比较

"#{}"占位符

作用

  • 传参大部分使用"#{}",在数据库底层使用的是:PreparedStatement预编译处理对象
  • 数据库底层被解析为"?",用来传值,是安全的数据库访问,可以防止sql注入
  • 通过在SqlMapConfig.xml添加日志输出配置,在后文测试输出的结果中可以验证
<?xml version="1.0" encoding="UTF-8" ?>                    

写法

  • "#{}"里参数的写法,要参考parameterType的类型
  • 如果parameterType的类型是简单类型(8种基本类型(封装) + String类型),则"#{}"里变量名称任意
    
  • 如果parameterType的类型是实体类的类型,则"#{}"里只能是类中成员变量的名称,而且区分大小写
//User实体类中的属性public class User {    private Integer id;    private String userName;    private Date birthday;    private String sex;    private String address;}
            insert into                users(username, birthday, sex, address)        values(#{userName}, #{birthday}, #{sex}, #{address})    

"${}"占位符

用于字符串的拼接和字符串的替换

字符串拼接

作用

  • 一般用于模糊查询,建议少用,因为存在sql注入风险

写法

  • "${}"中参数名称的写法,分两种情况,与"#{}"的两种情况相同,可参考之
  • 注意:对于parameterType的类型是简单类型时,"${}"里变量名称随便写,但是分版本如果是3.5.1及以下版本,只能写"value"

模糊查询示例

  • 未优化前,存在sql注入风险
    
  • 优化后,使用"#{}"接受传参,底层是preparedStatement预编译对象,可以防止sql注入
    

字符串替换("${}"的主要作用)

需求:在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 getByNameOrAddress(            @Param("colName")            String colName,            @Param("userName")            String userName    );}
  • 接口分析:当接口中的方法的参数有多个时,用注解标识参数,sql标签可通过注解中声明的参数名获取参数

UsersMapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>            
  • 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 users = usersMapper.getByNameOrAddress("username", "小");        //List 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 ConnectionCreated 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: 3Users{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 ConnectionCreated 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: 2Users{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),起到占位传值作用
作用   标签   sql
发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章