07、MyBatis 实战 - 之使用MyBatis的小技巧

一、#{}和${}的区别

1、演示代码

(1)准备实体类 Account

package com.powernode.bank.pojo;

public class Account {
   
     
    private Long id ;
    private String actno;
    private Double balance;
    ....

(2)准备 AccountMapper.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="account">

    <select id="selectByActno" resultType="com.powernode.bank.pojo.Account">
        select * from t_act where actno ={actno}
    </select>
</mapper>

(3)测试类

public class Test {
   
     
    @org.junit.Test
    public void test1(){
   
     
        SqlSession sqlSession = SqlSessionUtil.openSqlSession();
        Account account = sqlSession.selectOne("account.selectByActno", "act001");
        System.out.println(account.toString());
    }
}

先测试 {} 语法,运行结果如下:

17:03:22.973 default [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@71ba6d4e]
17:03:22.978 default [main] DEBUG account.selectByActno - ==>  Preparing: select * from t_act where actno = ?
17:03:23.026 default [main] DEBUG account.selectByActno - ==> Parameters: act001(String)
17:03:23.080 default [main] DEBUG account.selectByActno - <==      Total: 1
Account{
   
     id=1, actno='act001', balance=10004.0}

在测试 ${}语法,运行结果如下:

17:04:15.335 default [main] DEBUG o.a.i.t.jdbc.JdbcTransaction - Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@1cf6d1be]
17:04:15.342 default [main] DEBUG account.selectByActno - ==>  Preparing: select * from t_act where actno = act001
17:04:15.414 default [main] DEBUG account.selectByActno - ==> Parameters: 
org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.sql.SQLSyntaxErrorException: Unknown column 'act001' in 'where clause'

2、区别描述

1、#{}:底层使用PreparedStatement。特点:先进行SQL语句的编译,
然后给SQL语句的占位符问号?传值。可以避免SQL注入的风险。

2、${}:底层使用Statement。特点:先进行SQL语句的拼接,
然后再对SQL语句进行编译。存在SQL注入的风险。优先使用#{},这是原则。
避免SQL注入的风险。

二、什么时候使用 ${}

1、当需要往sql语句中,传入关键字时,可以是使用${},比如 前端传递排序字段值 asc或者 desc

案例场景:前台传入排序字段值,该值为mysql关键字,我们分别使用#{}和${}来处理:

#{
   
     }的执行结果,将关键字加了单引号 ,造成语法错误:
select car_num as carNum, brandfrom t car order by produce_time 'asc'

${
   
     }的执行结果,相当于拼接了关键字:
select car_num as carNum, brandfrom t car order by produce_time asc

2、或者想先进行sql语句拼接,然后再对sql语句进行编译,再执行时,也可以使用 ${} 

三、拼接表名

场景:
现实业务当中,可能会存在分表存储数据的情况。因为一张表存的话,数据量太大。查询效率比较低。可以将这些数据有规律的分表存储,这样在查询的时候效率就比较高。因为扫描的数据量变少了。
日志表:专门存储日志信息的。如果t_log只有一张表,这张表中每一天都会产生很多log,慢慢的,这个表中数据会很多。

怎么解决问题?
可以每天生成一个新表。每张表以当天日期作为名称,例如:
t_log_20220901 t_log_20220902
....
你想知道某一天的日志信息怎么办?
假设今天是20220901,那么直接查:t_log_20220901的表即可。

所以 ,向SQL语句当中拼接表名,就需要使用${}

四、批量删除

1、批量删除:一次删除多条记录。
2、批量删除的SQL语句有两种写法:
第一种or: delete from t car where id=1 or id=2 or id=3
第二种int: delete from t car where id in(1,2,3);

应该采用 ${} 的方式:
delete from t_car where id in(${ids});

代码如下:

<?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="account">
    <delete id="deleteBatch">
        delete from t_act where id in (${ids})
    </delete>
</mapper>

	@Test
    public void testDelete(){
   
     
        SqlSession sqlSession = SqlSessionUtil.openSqlSession();
        int deleteBatch = sqlSession.delete("deleteBatch", "1,2");
        System.out.println(deleteBatch);
        sqlSession.commit();
        sqlSession.close();
    }

运行结果

22:20:06.304 default [main] DEBUG account.deleteBatch - ==>  Preparing: delete from t_act where id in (1,2)
22:20:06.376 default [main] DEBUG account.deleteBatch - ==> Parameters: 
22:20:06.380 default [main] DEBUG account.deleteBatch - <==    Updates: 2
2

五、模糊查询

模糊查询: like

需求:根据汽车品牌进行模糊查询
select * from t car where brand like'%奔驰%'; 
select * from t car where brand like'%比亚迪%';

在mybatis的xml文件中有如下写法:

第一种方案:	'%${brand}%'
第二种方案:concat函数,这个是mysql数据库当中的一个函数,专门进行字符串拼接
concat('%' ,#{brand},'%')
第三种方案:比较鸡肋了。可以不算。
concat('%','${brand}', '%')
第四种方案:		"%"#{brand} "%"

六、起别名

1、核心配置文件mybatis-config.xml 增加typeAliases标签,用来配置别名

<?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>
    <properties resource="jdbc.properties"/>
    <typeAliases>
        <typeAlias type="com.powernode.bank.pojo.Account" alias="account"/>
    </typeAliases>
    <environments default="development">
    .......

2、修改sql文件,resultType的值可以直接使用别名,并且不区分大小写

<select id="selectActLike" resultType="account">
          select * from t_act where actno like concat ('',#{actno},'%')
    </select>

七、mybatis-config.xml文件的mapper配置

1、mybatis-config.xml文件中的mappers标签。

<mapper resource="CarMapper.xml"/> 要求类的根路径下必须有:CarMapper.xml
<mapper url="file:///d:/CarMapper.xml"/> 要求在d:/下有CarMapper.xml文件
<mapper class="全限定接口名,带有包名"/>

2、mapper标签的属性可以有三个:

resource:这种方式是从类的根路径下开始查找资源。采用这种方式的话,
你的配置文件需要放到类路径当中才行。

url:这种方式是一种绝对路径的方式,这种方式不要求配置文件必须放到类路径当中,
哪里都行,只要提供一个绝对路径就行。这种方式使用极少

 class:这个位置提供的是mapper接口的全限定接口名,必须带有包名的。

3、思考:mapper标签的作用是指定SalMapper.xml文件的路径,指定接口名有什么用呢?

<mapper class="com.powernode.mybatis.mapper.CarMapper"/>
如果你class指定是:com.powernode.mybatis.mapper.CarMapper
那么mybatis框架会自动去com/powernode/mybatis/mapper目录下查找CarMapper.xml文件。

注意:也就是说:

如果你采用这种方式,那么你必须保证CarMapper.xml文件和CarMapper接口必须在同一个目录下。
并且名字一致。 CarMapper接口-> CarMapper.xml LogMapper接口-> LogMapper.xml
....

八、获取插入数据时自动生成的主键

<insert id="insertAct" useGeneratedKeys="true" keyProperty="id">
        insert into t_act values (null,#{actno},#{balance})
    </insert>

说明:

useGeneratedKeys="true"  使用自动生成的主键值
keyProperty="id"	 指定主键值赋给对象的哪个属性