mybatis中#{}和${}的区别

本章节主要讲解mybatis中#{}和${}的区别

 

首先我们先通过代码事例查看下二者的区别:

在EmployeeMapper接口中有这么一个方法:

Employee getEmpByIdAndLastName(@Param("id")Integer id, @Param("lastName") String lastName);

在对应的EmployeeMapper.xml 映射文件中的sql语法:

<select id="getEmpByIdAndLastName" resultType="employee">
    select id,last_name ,email,gender from tbl_employee where id = ${id} and last_name = #{lastName}
</select>

测试代码:

public class MybatisTest {
    public SqlSessionFactory sessionFactory = null;

    @BeforeEach
    public void test()throws Exception{
    // 根据全局配置文件(xml)创建一个SqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void selectTest(){
        // 获取 SqlSession 的实例 。SqlSession 完全包含了面向数据库执行 SQL 命令所需的所有方法。通过 SqlSession 实例来直接执行已映射的 SQL 语句
        SqlSession sqlSession = null;
        try {
            sqlSession = sessionFactory.openSession();
            // 通过获取接口代理对象来执行sql语句
            EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
            Employee employee = mapper.getEmpByIdAndLastName(2,"BB");
            System.out.println(employee.getLastName()); // AA
        } finally {
            // 资源关闭,放在finally中确保一定会执行
            sqlSession.close();
        }
    }
}

最终的执行结果为:

DEBUG 05-07 22:52:42,700 ==>  Preparing: select id,last_name ,email,gender from tbl_employee where id = 2 and last_name = ?   (BaseJdbcLogger.java:145) 
DEBUG 05-07 22:52:42,801 ==> Parameters: BB(String)  (BaseJdbcLogger.java:145) 
DEBUG 05-07 22:52:42,823 <==      Total: 1  (BaseJdbcLogger.java:145) 
BB

请注意:在日志记录中的sql语句为

select id,last_name ,email,gender from tbl_employee where id = 2 and last_name = ?   

其中${id}直接被传入的参数所替代,而#{lastName}则是以预编译的方式变成?

总结:

相同点:

  • #{}:可以获取map中的值或者pojo对象属性的值;
  • ${}:可以获取map中的值或者pojo对象属性的值;


区别:

  • #{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
  • ${}:取出的值直接拼装在sql语句中;会有安全问题;

注意:大多情况下,我们去参数的值都应该去使用#{};
        

什么情况下使用${}:

        原生jdbc不支持占位符的地方我们就可以使用${}进行取值,比如列名、分表、排序。。。 

// 按照年份分表
select * from ${year}_salary where xxx;

// 排序
select * from tbl_employee order by ${f_name} ${order}

#{}更丰富的用法

首先,像 MyBatis 的其他部分一样,参数也可以指定一个特殊的数据类型。

#{property,javaType=int,jdbcType=NUMERIC}

像 MyBatis 的其它部分一样,javaType 几乎总是可以根据参数对象的类型确定下来,除非该对象是一个 HashMap。这个时候,你需要显式指定 javaType 来确保正确的类型处理器(TypeHandler)被使用。

提示 JDBC 要求,如果一个列允许 null 值,并且会传递值 null 的参数,就必须要指定 JDBC Type。阅读 PreparedStatement.setNull()的 JavaDoc 文档来获取更多信息。

要更进一步地自定义类型处理方式,你也可以指定一个特殊的类型处理器类(或别名),比如:

#{age,javaType=int,jdbcType=NUMERIC,typeHandler=MyTypeHandler}

尽管看起来配置变得越来越繁琐,但实际上,很少需要如此繁琐的配置。

对于数值类型,还有一个小数保留位数的设置,来指定小数点后保留的位数。

#{height,javaType=double,jdbcType=NUMERIC,numericScale=2}

最后,mode 属性允许你指定 IN,OUT 或 INOUT 参数。如果参数的 mode 为 OUT 或 INOUT,就像你在指定输出参数时所期望的行为那样,参数对象的属性实际值将会被改变。 如果 mode 为 OUT(或 INOUT),而且 jdbcType 为 CURSOR(也就是 Oracle 的 REFCURSOR),你必须指定一个 resultMap 引用来将结果集 ResultMap 映射到参数的类型上。要注意这里的 javaType 属性是可选的,如果留空并且 jdbcType 是 CURSOR,它会被自动地被设为 ResultMap。

#{department, mode=OUT, jdbcType=CURSOR, javaType=ResultSet, resultMap=departmentResultMap}

MyBatis 也支持很多高级的数据类型,比如结构体(structs),但是当使用 out 参数时,你必须显式设置类型的名称。比如(再次提示,在实际中要像这样不能换行):

#{middleInitial, mode=OUT, jdbcType=STRUCT, jdbcTypeName=MY_TYPE, resultMap=departmentResultMap}

尽管所有这些选项很强大,但大多时候你只须简单地指定属性名,其他的事情 MyBatis 会自己去推断,顶多要为可能为空的列指定 jdbcType。

#{firstName}
#{middleInitial,jdbcType=VARCHAR}
#{lastName}

 

 

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值