MyBatis-参数处理与查询结果映射

实际开发中应用细节

#{}和${}的区别?

'#{}':先编译sql语句,再给占位符传值,底层是PreparedStatement实现,可以防止sql注入,比较常用。

'#{}'传来的字符串类型的数据会自带单引号,比如:user_name=#{name} 会编译为 user_name='张三'

${}:先进行sql语句拼接,再编译sql语句,底层是Statement实现。存在sql注入现象。只有在需要进行sql关键字拼接的情况下才会用到。

${}传来的字符串类型的数据不带单引号,比如:user_name=#{name} 会编译为 user_name=张三 。这样会报语法错误。

优先使用#{}

那么什么时候使用${}呢?

在使用sql拼接的时候会用到,比如一个数据的查询结果是升序还是降序有前端传来的参数决定。因此使用${}更合适:

order by age=${orderType} 会编译为 order by age=asc。

如果使用#{}处理的话会编译为order by age='asc' 会报语法错误!

当拼接表名时也会用到。

一些数据会分表存储。比如日志表,因为日志数据会非常大,可以每天生成一个日志表,每张表以当天的日期作为名称,例如:

log_2022-02-11、log_2022-02-12、log_2022-02-13.

这样查某一天的日志时,可以将log_和日期进行拼接 然后查询,此时就要用到${}

批量删除

批量删除时,参数一般为字符串,比如传来的参数id值为:'1,2,3,4'。直接用where id in (#{id})会失效。

这里应该使用$() 。sql会编译为where id in (1,2,3,4) 结果执行成功。

模糊查询

方案一:使用sql语句拼接 where name like '%${name}%'

方案二:使用concat函数 where name like concat('%',#{name},'%') 此时会编译为 where name like concat('%','涨三','%') 执行成功。

方案三:where name like "%"#{name}"%"

别名机制

当XxxMapper.xml中resultType的值太长,也就是返回值的全限定类名太长,可以使用别名机制。

  1. 先在mybatis-config.xml中配置如下:

    xml 复制代码
    <!--    起别名,typeAliases标签要放在properties、settings 标签后面-->
        <typeAliases>
          <!--  type:指定给哪个类型起别名
            alias:指定别名。别名不区分大小写
            然后在CarMapper.xml文件中就可以直接使用别名car来代替全类名com.ali.pojo.Car了
            -->
            <typeAlias type="com.ali.pojo.Car" alias="car"/>
        </typeAliases>

    这里的alias属性其实可以省略。当alias省略时,别名就是类的简名,比如:

    复制代码
     <typeAlias type="com.ali.pojo.Car"/> 的别名就是car、CAR等,不区分大小写。

​ 还有更加方便的一种方式,可以指定包名,mybatis会自动给这个包下的所i有类起别名,别名就是类名:

xml 复制代码
    <typeAliases>
        <package name="com.ali.pojo"/>
    </typeAliases>
  1. 在CarMapper.xml中就可以使用别名了

    xml 复制代码
    <select id="selectCarById" resultType="car">
        SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType
        FROM t_car
        WHERE id = #{id}
    </select>

注意:这里的别名不区分大小写。即使写成resultType="Car" 也会执行成功!

mapper的配置

xml 复制代码
    <mappers>
<!--        执行xxxMapper.xml文件中的SQL语句-->
<!--        resource属性自动从类的路径下加载xxxMapper.xml文件
            url属性直接从文件系统绝对路径加载xxxMapper.xml文件,不推荐,移植性太差。
            class属性指定一个全限定接口名,mybaits会去这个接口的同级目录下查找对应Mapepr.xml文件
            比如以下配置,Mybatis会去com.ali.mapper包下查找CarMapper.xml文件。
            -->
        <mapper class="com.ali.mapper.CarMapper"/>
        <mapper resource="CarMapper.xml"/>
        <!--package:表示从指定的包下查找所有的xxxMapper.xml文件,并且自动加载它们。
			前提必须把xml文件和接口放在统计目录下。并且名字一致。
			实际开发中 使用这种方式-->
        <package name="com.ali.mapper"/>
    </mappers>

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

xml 复制代码
<!-- useGeneratedKeys="true" 表示使用JDBC的getGeneratedKeys方法获取数据库自动生成的主键值,
 keyProperty="id"表示将获取到的主键值封装到Car对象的id属性中。-->
 <insert id="insertCarGetId" useGeneratedKeys="true" keyProperty="id">
     INSERT INTO t_car (id, car_num, brand,guide_price,produce_time,car_type)
     VALUES (null, #{carNum}, #{brand},#{guidePrice},#{produceTime},#{carType})
 </insert>

这样设置后,在新增时传入的car对象在sql执行完后,主键的值可以从car.getId()方法中获得。

MyBatis参数处理

简单类型参数

byte、int、short、long、char、float、double、String、Date,及其对应的包装类都适用简单类型参数。

下面以Long类型为例:

xml 复制代码
<!--    对应的接口方法: Car selectCarById(Long id);
        parameterType属性:指定传入参数的类型。在这个例子中,传入参数是一个Long类型的id。
        mybatis框架自带类型推断机制,所以大部分情况下parameterType属性可以省略不写,
       -->
    <select id="selectCarById" resultType="car" parameterType="java.lang.Long">
        SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType
        FROM t_car
        WHERE id = #{id}
    </select>

Map参数

xml 复制代码
<!--    对应的接口方法: int insertCar(Map<String,Object> map);
        参数类型时map集合。
-->
        <insert id="insertCar" parameterType="map">
            INSERT INTO t_car (id, car_num, brand,guide_price,produce_time,car_type)
            VALUES (null, #{carNum}, #{brand},#{guidePrice},#{produceTime},#{carType})
        </insert>

实体类参数

xml 复制代码
<!--对应的接口方法: int insertCarByPojo(Car car);
参数类型是Pojo类。-->
<insert id="insertCarByPojo" >
    INSERT INTO t_car (id, car_num, brand,guide_price,produce_time,car_type)
    VALUES (null, #{carNum}, #{brand},#{guidePrice},#{produceTime},#{carType})
</insert>

多参数

xml 复制代码
<!--对应的接口方法: List<Car> selectCarByNameAndCarType(String name,String carType);
    这种多参数的情况,mybatis框架会将多个参数封装成一个map集合,并且map会这样设置:
    map.put("arg0",第一个参数值);  map.put("arg1",第二个参数值);
    map.put("param1",第一个参数值);  map.put("param2",第二个参数值);
   所以#{arg0} 和#{param1}都可以获取到第一个参数值,#{arg1}和#{param2}都可以获取到第二个参数值。
-->
<select id="selectCarByNameAndCarType" resultType="car" parameterType="java.lang.Long">
    SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType
    FROM t_car
    WHERE brand = #{arg0} and car_type = #{arg1}
</select>

@Param注解

xml 复制代码
  <!--对应的接口方法: List<Car> selectCarByNameAndCarType2(@Param("name") String name,@Param("carType") String carType);
        @Param注解会将底层封装的map中arg0、arg1替换成我们指定的key值name和carType。
         param1、param2不会被替换,可以继续使用
-->
    <select id="selectCarByNameAndCarType2" resultType="car" parameterType="java.lang.Long">
        SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType
        FROM t_car
        WHERE brand = #{name} and car_type = #{carType}
    </select>

MyBatis查询语句

当sql返回多条记录时,不能使用单个pojo对象接收,不然会报错。

单条查询时,用List 接收是没有任何问题的。

返回Map

当返回的数据,没有合适的实体类对应的话,可以采用Map接收。key是字段名,value是字段值。

当返回多条数据时,使用List 接收。

xml 复制代码
<!--   对应的接口方法: Map<String,Object> selectCarByIdRetMap(Long id);
     resultType="map"表示将查询结果封装成一个map集合,map的key是列名,value是列值。
     如果需要查询多条记录并封装成map集合,可以使用resultType="list"来封装成一个list集合,list集合中的每个元素都是一个map集合。
-->
    <select id="selectCarByIdRetMap" resultType="map" >
        SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType
        FROM t_car
        WHERE id = #{id}
    </select>

返回Map<String,Map>

以每条记录的主键作为key,一条记录作为value

xml 复制代码
<!--   接口对应的方法:
   @MapKey("id") // 这个注解表示map的key是id列的值,value是整个记录封装成的map集合。
   List<Map<Long,Map<String,Object>> selectAllCarRetMap();
   -->
   <select id="selectAllCarRetMap" resultType="map">
       SELECT id, car_num AS carNum, brand, guide_price AS guidePrice, produce_time AS produceTime, car_type AS carType
       FROM t_car
   </select>

resultMap结果映射

查询结果的列名和Java对象的属性名对应不上怎么办?

方案一:as 起别名

方案二:使用resultMap进行结果映射

方案三:开启驼峰命名自动映射

xml 复制代码
<!--定义一个结果映射,在结果映射中,指定数据库表的字段和Java对象的属性之间的映射关系。
id属性是结果映射的唯一标识,将来要用在select标签中;type属性是结果映射对应的Java类型。-->
<resultMap id="carResultMap" type="Car">
    <!--建议配上主键,因为主键在结果映射中有特殊的意义,
    主键会被mybatis框架缓存起来,如果查询结果中有重复的主键值,mybatis框架会将它们封装成同一个Java对象。-->
    <id property="id" column="id"></id>
    <!--property指定Java对象的属性,column指定数据库表的字段。
    当数据库表的字段名和Java对象的属性名一致时,可以不配置-->
    <result property="carNum" column="car_num"></result>
    <result property="guidePrice" column="guide_price"></result>
    <result property="produceTime" column="produce_time"></result>
    <result property="carType" column="car_type"></result>
</resultMap>
<!--resultMap表示指定使用哪个结果映射,resultMap的值时resultMap标签的id-->
<select id="selectAllCarResultMap" resultMap="carResultMap">
    SELECT * FROM t_car
</select>

开启驼峰命名自动映射

前提时Java的属性名和数据库表的字段名必须符合命名规范。

可以将car_type对应为carType

在mybatis-config.xml文件中进行如下配置即可开启该功能,默认值是false:

xml 复制代码
<settings>
    <setting name="mapUnderscoreToCameCase" value="true"/>
</settings>

返回总记录条数

xml 复制代码
<!--  对应的接口方法: long selectTotalCount();   -->
  <select id="selectTotalCount" resultType="long">
      SELECT count(*) FROM t_car
  </select>
相关推荐
神明不懂浪漫1 小时前
【第五章】Java中的继承与多态
java·开发语言
AI多Agent协作实战派3 小时前
AI多Agent协作系统实战(十七):凌晨4点,我的AI系统在“假装工作“——3个bug同时爆炸的5小时
java·前端·bug
gaolei_eit3 小时前
Java+Ai+vue
java·spring·maven
qq_2518364573 小时前
基于java Web 动漫视频网站毕业论文
java·开发语言·前端
LayZhangStrive3 小时前
JUC相关的函数、注解、变量杂记
java·面试·多线程·juc
未秃头的程序猿3 小时前
给公司做了个AI客服Agent,用的Spring AI 1.0,3天上线领导拍板了
java·后端·ai编程
曹牧3 小时前
Eclipse 批量文本替换
java·ide·eclipse
程序员清风3 小时前
OpenAI官方发布最新提示词技巧!
java·后端·面试
一只枫林3 小时前
MySQL内、外连接知识点汇总
java·前端·数据库
梅头脑3 小时前
写了3年CRUD,volatile和synchronized的区别还是答不清——直到我画出了这张三性两锁边界图
java