MyBatis学习笔记——3

news2024/10/6 18:21:20

MyBatis学习笔记——3

  • 一、MyBatis小技巧
    • 1.1、#{}和${}
    • 1.2、typeAliases
    • 1.3、mappers
    • 1.4、插入数据时获取自动生成的主键
  • 二、MyBatis参数处理
    • 2.1、单个简单类型参数
    • 2.2、 Map参数
    • 2.3、实体类参数
    • 2.4、多参数
    • 2.5、 @Param注解(命名参数)
    • 2.6、 @Param源码分析
  • 三、MyBatis查询语句专题
    • 3.1、返回Car
    • 3.2、返回List<Car>
    • 3.3、返回Map
    • 3.4、返回List<Map>
    • 3.5、返回Map<String,Map>
    • 3.6、resultMap结果映射
    • 3.7、返回总记录条数
  • 四、动态SQL
    • 4.1、if标签
    • 4.2、Where标签
    • 4.3、trim标签
    • 4.4、set标签
    • 4.5、choose when otherwise
    • 4.6、foreach标签
      • 4.6.1、批量删除
      • 4.6.2、批量增加
    • 4.7、sql标签与include标签

一、MyBatis小技巧

1.1、#{}和${}

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

  • 使用该方法会自动给传入的值添加''

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

  • 比如在书写升降序查询功能的SQL时,就需要使用${}来时asc或desc不带''形式拼接到SQL语句中

    select id,car_num as carNum,brand,guide_price as guidePrice,produce_time as produceTime,car_type as carType from t_car order by carNum 'desc'

    desc是一个关键字,不能带单引号的,所以在进行sql语句关键字拼接的时候,必须使用${}

模糊查询

需求:查询奔驰系列的汽车。【只要品牌brand中含有奔驰两个字的都查询出来。】

使用${}

CarMapper接口

List<Car> selectLikeByBrand(String likeBrank);

CarMapper.xml

<select id="selectLikeByBrand" 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
  brand like '%${brand}%'
</select>

CarMapperTest.testSelectLikeByBrand

@Test
public void testSelectLikeByBrand(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = mapper.selectLikeByBrand("奔驰");
    cars.forEach(car -> System.out.println(car));
}

在这里插入图片描述

使用#{}

第一种:concat函数

<select id="selectLikeByBrand" 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
  brand like concat('%',#{brand},'%')
</select>

第二种:双引号方式

<select id="selectLikeByBrand" 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
  brand like "%"#{brand}"%"
</select>

1.2、typeAliases

第一种方式:typeAlias

<typeAliases>
  <typeAlias type="com.powernode.mybatis.pojo.Car" alias="Car"/>
</typeAliases>
  • 首先要注意typeAliases标签的放置位置,如果不清楚的话,可以看看错误提示信息。
  • typeAliases标签中的typeAlias可以写多个。
  • typeAlias:
  • type属性:指定给哪个类起别名
  • alias属性:别名。
    + alias属性不是必须的,如果缺省的话,type属性指定的类型名的简类名作为别名。
    + alias是大小写不敏感的。也就是说假设alias=“Car”,再用的时候,可以CAR,也可以car,也可以Car,都行。

第二种方式:package

如果一个包下的类太多,每个类都要起别名,会导致typeAlias标签配置较多,所以mybatis用提供package的配置方式,只需要指定包名,该包下的所有类都自动起别名,别名就是简类名。并且别名不区分大小写。

<typeAliases>
  <package name="com.powernode.mybatis.pojo"/>
</typeAliases>

package也可以配置多个的。

1.3、mappers

SQL映射文件的配置方式包括四种:

  • resource:从类路径中加载
  • url:从指定的全限定资源路径中加载
  • class:使用映射器接口实现类的完全限定类名
  • package:将包内的映射器接口实现全部注册为映射器

resource
这种方式是从类路径中加载配置文件,所以这种方式要求SQL映射文件必须放在resources目录下或其子目录下。

<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

url
这种方式显然使用了绝对路径的方式,这种配置对SQL映射文件存放的位置没有要求,随意。

<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

class
如果使用这种方式必须满足以下条件:

  • SQL映射文件和mapper接口放在同一个目录下。
  • SQL映射文件的名字也必须和mapper接口名一致。
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

将CarMapper.xml文件移动到和mapper接口同一个目录下:

  • 在resources目录下新建:com/powernode/mybatis/mapper【这里千万要注意:不能这样新建 com.powernode.mybatis.dao
  • 将CarMapper.xml文件移动到mapper目录下
  • 修改mybatis-config.xml文件
<mappers>
  <mapper class="com.powernode.mybatis.mapper.CarMapper"/>
</mappers>

package

如果class较多,可以使用这种package的方式,但前提条件和上一种方式一样。

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="com.powernode.mybatis.mapper"/>
</mappers>

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

前提是:主键是自动生成的。
业务背景:一个用户有多个角色。
在这里插入图片描述
插入一条新的记录之后,自动生成了主键,而这个主键需要在其他表中使用时。
插入一个用户数据的同时需要给该用户分配角色:需要将生成的用户的id插入到角色表的user_id字段上。

第一种方式:可以先插入用户数据,再写一条查询语句获取id,然后再插入user_id字段。【比较麻烦】
第二种方式:mybatis提供了一种方式更加便捷。

CarMapper接口

/**
     * 获取自动生成的主键
     * @param car
     */
void insertUseGeneratedKeys(Car car);

CarMapper.xml

<insert id="insertUseGeneratedKeys" 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>

CarMapperTest.testInsertUseGeneratedKeys

@Test
public void testInsertUseGeneratedKeys(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Car car = new Car();
    car.setCarNum("5262");
    car.setBrand("BYD汉");
    car.setGuidePrice(30.3);
    car.setProduceTime("2020-10-11");
    car.setCarType("新能源");
    mapper.insertUseGeneratedKeys(car);
    SqlSessionUtil.openSession().commit();
    System.out.println(car.getId());
}

二、MyBatis参数处理

2.1、单个简单类型参数

简单类型包括:

  • byte short int long float double char
  • Byte Short Integer Long Float Double Character
  • String
  • java.util.Date
  • java.sql.Date

简单类型对于mybatis来说都是可以自动类型识别的:

  • 也就是说对于mybatis来说,它是可以自动推断出ps.setXxxx()方法的。ps.setString()还是ps.setInt()。它可以自动推断。

其实SQL映射文件中的配置比较完整的写法是:

<select id="selectByName" resultType="student" parameterType="java.lang.String">
  select * from t_student where name = #{name, javaType=String, jdbcType=VARCHAR}
</select>

其中sql语句中的javaType,jdbcType,以及select标签中的parameterType属性,都是用来帮助mybatis进行类型确定的。不过这些配置多数是可以省略的。因为mybatis它有强大的自动类型推断机制。

  • javaType:可以省略
  • jdbcType:可以省略
  • parameterType:可以省略

2.2、 Map参数

需求:根据name和age查询

StudentMapper接口

/**
* 根据name和age查询
* @param paramMap
* @return
*/
List<Student> selectByParamMap(Map<String,Object> paramMap);

StudentMapperTest.testSelectByParamMap

@Test
public void testSelectByParamMap(){
    // 准备Map
    Map<String,Object> paramMap = new HashMap<>();
    paramMap.put("nameKey", "张三");
    paramMap.put("ageKey", 20);

    List<Student> students = mapper.selectByParamMap(paramMap);
    students.forEach(student -> System.out.println(student));
}

StudentMapper.xml

<select id="selectByParamMap" resultType="student">
  select * from t_student where name = #{nameKey} and age = #{ageKey}
</select>

测试运行正常。
这种方式是手动封装Map集合,将每个条件以key和value的形式存放到集合中。然后在使用的时候通过#{map集合的key}来取值。

2.3、实体类参数

需求:插入一条Student数据
StudentMapper接口

/**
 * 保存学生数据
 * @param student
 * @return
 */
int insert(Student student);

StudentMapper.xml

<insert id="insert">
  insert into t_student values(null,#{name},#{age},#{height},#{birth},#{sex})
</insert>

StudentMapperTest.testInsert

@Test
public void testInsert(){
    Student student = new Student();
    student.setName("李四");
    student.setAge(30);
    student.setHeight(1.70);
    student.setSex('男');
    student.setBirth(new Date());
    int count = mapper.insert(student);
    SqlSessionUtil.openSession().commit();
}

运行正常,数据库中成功添加一条数据。
这里需要注意的是:#{} 里面写的是属性名字。这个属性名其本质上是:set/get方法名去掉set/get之后的名字。

2.4、多参数

通过name和sex查询
StudentMapper接口

    /**
     * 根据name和sex查询
     * @param name
     * @param sex
     * @return
     */
    List<Student> selectByNameAndSex(String name, Character sex);

StudentMapperTest.testSelectByNameAndSex

@Test
public void testSelectByNameAndSex(){
    List<Student> students = mapper.selectByNameAndSex("张三", '女');
    students.forEach(student -> System.out.println(student));
}

StudentMapper.xml

<select id="selectByNameAndSex" resultType="student">
  select * from t_student where name = #{name} and sex = #{sex}
</select>

在这里插入图片描述
异常信息描述了:name参数找不到,可用的参数包括[arg1, arg0, param1, param2]
修改StudentMapper.xml配置文件:尝试使用[arg1, arg0, param1, param2]去参数

StudentMapper.xml

<select id="selectByNameAndSex" resultType="student">
  <!--select * from t_student where name = #{name} and sex = #{sex}-->
  select * from t_student where name = #{arg0} and sex = #{arg1}
</select>

再次尝试修改StudentMapper.xml文件

<select id="selectByNameAndSex" resultType="student">
  <!--select * from t_student where name = #{name} and sex = #{sex}-->
  <!--select * from t_student where name = #{arg0} and sex = #{arg1}-->
  <!--select * from t_student where name = #{param1} and sex = #{param2}-->
  select * from t_student where name = #{arg0} and sex = #{param2}
</select>

通过测试可以看到:

  • arg0 是第一个参数
  • param1是第一个参数
  • arg1 是第二个参数
  • param2是第二个参数

实现原理:实际上在mybatis底层会创建一个map集合,以arg0/param1为key,以方法上的参数为value,例如以下代码:

Map<String,Object> map = new HashMap<>();
map.put("arg0", name);
map.put("arg1", sex);
map.put("param1", name);
map.put("param2", sex);

// 所以可以这样取值:#{arg0} #{arg1} #{param1} #{param2}
// 其本质就是#{map集合的key}

注意:使用mybatis3.4.2之前的版本时:要用#{0}和#{1}这种形式。

2.5、 @Param注解(命名参数)

可以不用arg0 arg1 param1 param2吗?这个map集合的key我们自定义可以吗?当然可以。使用@Param注解即可。这样可以增强可读性。
需求:根据name和age查询

    /**
     * 根据name和age查询
     * @param name
     * @param age
     * @return
     */
    List<Student> selectByNameAndAge(@Param(value="name") String name, @Param("age") int age);
    @Test
    public void testSelectByNameAndAge(){
        List<Student> stus = mapper.selectByNameAndAge("张三", 20);
        stus.forEach(student -> System.out.println(student));
    }
<select id="selectByNameAndAge" resultType="student">
  select * from t_student where name = #{name} and age = #{age}
</select>

通过测试,一切正常。

核心:@Param(“这里填写的其实就是map集合的key”)

2.6、 @Param源码分析

在这里插入图片描述

三、MyBatis查询语句专题

模块名:mybatis-007-select
打包方式:jar
引入依赖:mysql驱动依赖、mybatis依赖、logback依赖、junit依赖。
引入配置文件:jdbc.properties、mybatis-config.xml、logback.xml
创建pojo类:Car
创建Mapper接口:CarMapper
创建Mapper接口对应的映射文件:com/powernode/mybatis/mapper/CarMapper.xml
创建单元测试:CarMapperTest
拷贝工具类:SqlSessionUtil

3.1、返回Car

当查询的结果,有对应的实体类,并且查询结果只有一条时:

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;
public interface CarMapper {

    /**
     * 根据id主键查询:结果最多只有一条
     * @param id
     * @return
     */
    Car selectById(Long id);
}

<?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.powernode.mybatis.mapper.CarMapper">
    <select id="selectById" resultType="Car">
        select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}
    </select>
</mapper>
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.junit.Test;

public class CarMapperTest {

    @Test
    public void testSelectById(){
        CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
        Car car = mapper.selectById(35L);
        System.out.println(car);
    }
}

查询结果是一条的话也可以使用List集合接收

3.2、返回List

当查询的记录条数是多条的时候,必须使用集合接收。如果使用单个实体类接收会出现异常。

/**
* 查询所有的Car
* @return
*/
List<Car> selectAll();
<select id="selectAll" resultType="Car">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
@Test
public void testSelectAll(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = mapper.selectAll();
    cars.forEach(car -> System.out.println(car));
}

在这里插入图片描述

如果返回多条记录,采用单个实体类接收会怎样?

/**
* 查询多条记录,采用单个实体类接收会怎样?
* @return
*/
Car selectAll2();
<select id="selectAll2" resultType="Car">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
@Test
public void testSelectAll2(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Car car = mapper.selectAll2();
    System.out.println(car);
}

在这里插入图片描述

3.3、返回Map

当返回的数据,没有合适的实体类对应的话,可以采用Map集合接收。字段名做key,字段值做value。
查询如果可以保证只有一条数据,则返回一个Map集合即可。

在这里插入图片描述

/**
 * 通过id查询一条记录,返回Map集合
 * @param id
 * @return
 */
Map<String, Object> selectByIdRetMap(Long id);
<select id="selectByIdRetMap" resultType="map">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car where id = #{id}
</select>

resultMap=“map”,这是因为mybatis内置了很多别名。【参见mybatis开发手册】

@Test
public void testSelectByIdRetMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Map<String,Object> car = mapper.selectByIdRetMap(35L);
    System.out.println(car);
}

在这里插入图片描述

当然,如果返回一个Map集合,可以将Map集合放到List集合中吗?当然可以,这里就不再测试了。
反过来,如果返回的不是一条记录,是多条记录的话,只采用单个Map集合接收,这样同样会出现之前的异常:TooManyResultsException

3.4、返回List

查询结果条数大于等于1条数据,则可以返回一个存储Map集合的List集合。List等同于List
在这里插入图片描述

/**
     * 查询所有的Car,返回一个List集合。List集合中存储的是Map集合。
     * @return
     */
List<Map<String,Object>> selectAllRetListMap();
<select id="selectAllRetListMap" resultType="map">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
@Test
public void testSelectAllRetListMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Map<String,Object>> cars = mapper.selectAllRetListMap();
    System.out.println(cars);
}
[
  {carType=燃油车, carNum=103, guidePrice=50.30, produceTime=2020-10-01, id=33, brand=奔驰E300L}, 
  {carType=电车, carNum=102, guidePrice=30.23, produceTime=2018-09-10, id=34, brand=比亚迪汉}, 
  {carType=燃油车, carNum=103, guidePrice=50.30, produceTime=2020-10-01, id=35, brand=奔驰E300L}, 
  {carType=燃油车, carNum=103, guidePrice=33.23, produceTime=2020-10-11, id=36, brand=奔驰C200},
  ......
]

3.5、返回Map<String,Map>

拿Car的id做key,以后取出对应的Map集合时更方便。
在这里插入图片描述

/**
     * 获取所有的Car,返回一个Map集合。
     * Map集合的key是Car的id。
     * Map集合的value是对应Car。
     * @return
     */
@MapKey("id")
Map<Long,Map<String,Object>> selectAllRetMap();
<select id="selectAllRetMap" resultType="map">
  select id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType from t_car
</select>
@Test
public void testSelectAllRetMap(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Map<Long,Map<String,Object>> cars = mapper.selectAllRetMap();
    System.out.println(cars);
}

执行结果:

{
64={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=64, brand=丰田霸道}, 
66={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=66, brand=丰田霸道}, 
67={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=67, brand=丰田霸道}, 
69={carType=燃油车, carNum=133, guidePrice=50.30, produceTime=2020-01-10, id=69, brand=丰田霸道},
......
}

3.6、resultMap结果映射

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

  • 第一种方式:as 给列起别名
  • 第二种方式:使用resultMap进行结果映射
  • 第三种方式:是否开启驼峰命名自动映射(配置settings)

使用resultMap进行结果映射

/**
     * 查询所有Car,使用resultMap进行结果映射
     * @return
     */
List<Car> selectAllByResultMap();
<!--
        resultMap:
            id:这个结果映射的标识,作为select标签的resultMap属性的值。
            type:结果集要映射的类。可以使用别名。
-->
<resultMap id="carResultMap" type="car">
  <!--对象的唯一标识,官方解释是:为了提高mybatis的性能。建议写上。-->
  <id property="id" column="id"/>
  <result property="carNum" column="car_num"/>
  <!--当属性名和数据库列名一致时,可以省略。但建议都写上。-->
  <!--javaType用来指定属性类型。jdbcType用来指定列类型。一般可以省略。-->
  <result property="brand" column="brand" javaType="string" jdbcType="VARCHAR"/>
  <result property="guidePrice" column="guide_price"/>
  <result property="produceTime" column="produce_time"/>
  <result property="carType" column="car_type"/>
</resultMap>

<!--resultMap属性的值必须和resultMap标签中id属性值一致。-->
<select id="selectAllByResultMap" resultMap="carResultMap">
  select * from t_car
</select>
@Test
public void testSelectAllByResultMap(){
    CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = carMapper.selectAllByResultMap();
    System.out.println(cars);
}

执行结果正常。

是否开启驼峰命名自动映射

使用这种方式的前提是:属性名遵循Java的命名规范,数据库表的列名遵循SQL的命名规范。
Java命名规范:首字母小写,后面每个单词首字母大写,遵循驼峰命名方式。
SQL命名规范:全部小写,单词之间采用下划线分割。

比如以下的对应关系:

实体类中的属性名数据库表的别名
carNumcar_num
carTypecar_type
produceTimeproduce_time

如何启用该功能,在mybatis-config.xml文件中进行配置:

<!--放在properties标签后面-->
<settings>
  <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
/**
* 查询所有Car,启用驼峰命名自动映射
* @return
*/
List<Car> selectAllByMapUnderscoreToCamelCase();
<select id="selectAllByMapUnderscoreToCamelCase" resultType="Car">
  select * from t_car
</select>
@Test
public void testSelectAllByMapUnderscoreToCamelCase(){
    CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    List<Car> cars = carMapper.selectAllByMapUnderscoreToCamelCase();
    System.out.println(cars);
}

执行结果正常。

3.7、返回总记录条数

需求:查询总记录条数

/**
     * 获取总记录条数
     * @return
     */
Long selectTotal();
<!--long是别名,可参考mybatis开发手册。-->
<select id="selectTotal" resultType="long">
  select count(*) from t_car
</select>
@Test
public void testSelectTotal(){
    CarMapper carMapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Long total = carMapper.selectTotal();
    System.out.println(total);
}

在这里插入图片描述

四、动态SQL

4.1、if标签

  1. if标签中test属性是必须的。
  2. if标签中test属性的值是false或者true
  3. 如果testtrue,则if标签中的sql语句就会拼接。反之,则不会拼接。
  4. test属性中可以使用的是:
    • 当使用了@Param注解,那么test中要出现的是@Param注解指定的参数名。@Param("brand"),那么这里只能使用brand
    • 当没有使用@Param注解,那么test中要出现的是: param1 param2 param3 arg0 arg1 arg2. . . .
    • 当使用了POJO,那么test中出现的是POJO类的属性名。
  5. 在mybatis的动态SQL当中,不能使用&&,只能使用and
<?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.Smulll.Mapper.CarMapper">
    <select id="selectByMultiConditional" resultType="car">
        select
            *
        from
            t_car
        where
            <if test="brand !=null and brand !=''">
                brand like "%"#{brand}"%"
            </if>
            <if test="guidePrice !=null and guidePrice !=''">
                and guide_price > #{guidePrice}
            </if>
            <if test="carType !=null and carType !=''">
                and car_type = #{carType}
            </if>
    </select>
</mapper>

4.2、Where标签

where标签的作用:让where子句更加动态智能。

  • 所有条件都为空时,where标签保证不会生成where子句。
  • 自动去除某些条件前面多余的andor。后面的无法去除

继续使用if标签中的需求。

<select id="selectByMultiConditionWithWhere" resultType="car">
  select * from t_car
  <where>
    <if test="brand != null and brand != ''">
      and brand like #{brand}"%"
    </if>
    <if test="guidePrice != null and guidePrice != ''">
      and guide_price >= #{guidePrice}
    </if>
    <if test="carType != null and carType != ''">
      and car_type = #{carType}
    </if>
  </where>
</select>

4.3、trim标签

trim标签的属性:

  • prefix:在trim标签中的语句前添加内容
  • suffix:在trim标签中的语句后添加内容
  • prefixOverrides:前缀覆盖掉(去掉)
  • suffixOverrides:后缀覆盖掉(去掉)
<select id="selectByMultiConditionWithTrim" resultType="car">
  select * from t_car
  <!--prefix="where" 在trim标签前面加where -->
  <!--suffixOverrides="and|or" 把trim标签中内容的后缀and或or去掉-->
  <trim prefix="where" suffixOverrides="and|or">
    <if test="brand != null and brand != ''">
      brand like #{brand}"%" and
    </if>
    <if test="guidePrice != null and guidePrice != ''">
      guide_price >= #{guidePrice} and
    </if>
    <if test="carType != null and carType != ''">
      car_type = #{carType}
    </if>
  </trim>
</select>

4.4、set标签

主要使用在update语句当中,用来生成set关键字,同时去掉最后多余的“,”

比如我们只更新提交的不为空的字段,如果提交的数据是空或者"",那么这个字段我们将不更新。

/**
* 更新信息,使用set标签
* @param car
* @return
*/
int updateWithSet(Car car);
<update id="updateWithSet">
  update t_car
  <set>
    <if test="carNum != null and carNum != ''">car_num = #{carNum},</if>
    <if test="brand != null and brand != ''">brand = #{brand},</if>
    <if test="guidePrice != null and guidePrice != ''">guide_price = #{guidePrice},</if>
    <if test="produceTime != null and produceTime != ''">produce_time = #{produceTime},</if>
    <if test="carType != null and carType != ''">car_type = #{carType},</if>
  </set>
  where id = #{id}
</update>
@Test
public void testUpdateWithSet(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Car car = new Car(38L,"1001","丰田霸道2",10.0,"",null);
    int count = mapper.updateWithSet(car);
    System.out.println(count);
    SqlSessionUtil.openSession().commit();
}

4.5、choose when otherwise

这三个标签是在一起使用的:

语法格式:

<choose>
  <when></when>
  <when></when>
  <when></when>
  <otherwise></otherwise>
</choose>

等同于:

if(){
    
}else if(){
    
}else if(){
    
}else if(){
    
}else{

}

只有一个分支会被选择!!!!

/**
* 使用choose when otherwise标签查询
* @param brand
* @param guidePrice
* @param produceTime
* @return
*/
List<Car> selectWithChoose(@Param("brand") String brand, @Param("guidePrice") Double guidePrice, @Param("produceTime") String produceTime);
<select id="selectWithChoose" resultType="car">
  select * from t_car
  <where>
    <choose>
      <when test="brand != null and brand != ''">
        brand like #{brand}"%"
      </when>
      <when test="guidePrice != null and guidePrice != ''">
        guide_price >= #{guidePrice}
      </when>
      <otherwise>
        produce_time >= #{produceTime}
      </otherwise>
    </choose>
  </where>
</select>
@Test
public void testSelectWithChoose(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    //List<Car> cars = mapper.selectWithChoose("丰田霸道", 20.0, "2000-10-10"); 根据第一个查询
    //List<Car> cars = mapper.selectWithChoose("", 20.0, "2000-10-10");	根据第二个查询
    //List<Car> cars = mapper.selectWithChoose("", null, "2000-10-10");	根据第三个查询
    List<Car> cars = mapper.selectWithChoose("", null, "");	// 根据第三个查询
    System.out.println(cars);
}

4.6、foreach标签

循环数组或集合,动态生成sql,比如这样的SQL:
批量删除

delete from t_car where id in(1,2,3);
delete from t_car where id = 1 or id = 2 or id = 3;

批量增加

insert into t_car values
  (null,'1001','凯美瑞',35.0,'2010-10-11','燃油车'),
  (null,'1002','比亚迪唐',31.0,'2020-11-11','新能源'),
  (null,'1003','比亚迪宋',32.0,'2020-10-11','新能源')

4.6.1、批量删除

  • 用in来删除

属性:
collection:集合或数组
item:集合或数组中的元素
separator:分隔符
open:foreach标签中所有内容的开始
close:foreach标签中所有内容的结束

/**
* 通过foreach完成批量删除
* @param ids
* @return
*/
int deleteBatchByForeach(@Param("ids") Long[] ids);
<!--
collection:集合或数组
item:集合或数组中的元素
separator:分隔符
open:foreach标签中所有内容的开始
close:foreach标签中所有内容的结束
-->
<delete id="deleteBatchByForeach">
  delete from t_car where id in
  <foreach collection="ids" item="id" separator="," open="(" close=")">
    #{id}
  </foreach>
</delete>
@Test
public void testDeleteBatchByForeach(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    int count = mapper.deleteBatchByForeach(new Long[]{40L, 41L, 42L});
    System.out.println("删除了几条记录:" + count);
    SqlSessionUtil.openSession().commit();
}
  • 用or来删除
/**
* 通过foreach完成批量删除
* @param ids
* @return
*/
int deleteBatchByForeach2(@Param("ids") Long[] ids);
<delete id="deleteBatchByForeach2">
  delete from t_car where
  <foreach collection="ids" item="id" separator="or">
    id = #{id}
  </foreach>
</delete>
@Test
public void testDeleteBatchByForeach2(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    int count = mapper.deleteBatchByForeach2(new Long[]{40L, 41L, 42L});
    System.out.println("删除了几条记录:" + count);
    SqlSessionUtil.openSession().commit();
}

4.6.2、批量增加

/**
* 批量添加,使用foreach标签
* @param cars
* @return
*/
int insertBatchByForeach(@Param("cars") List<Car> cars);
<insert id="insertBatchByForeach">
  insert into t_car values 
  <foreach collection="cars" item="car" separator=",">
    (null,#{car.carNum},#{car.brand},#{car.guidePrice},#{car.produceTime},#{car.carType})
  </foreach>
</insert>
@Test
public void testInsertBatchByForeach(){
    CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
    Car car1 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");
    Car car2 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");
    Car car3 = new Car(null, "2001", "兰博基尼", 100.0, "1998-10-11", "燃油车");
    List<Car> cars = Arrays.asList(car1, car2, car3);
    int count = mapper.insertBatchByForeach(cars);
    System.out.println("插入了几条记录" + count);
    SqlSessionUtil.openSession().commit();
}

4.7、sql标签与include标签

sql标签用来声明sql片段

include标签用来将声明的sql片段包含到某个sql语句当中

作用:代码复用。易维护。

<sql id="carCols">id,car_num carNum,brand,guide_price guidePrice,produce_time produceTime,car_type carType</sql>

<select id="selectAllRetMap" resultType="map">
  select <include refid="carCols"/> from t_car
</select>

<select id="selectAllRetListMap" resultType="map">
  select <include refid="carCols"/> carType from t_car
</select>

<select id="selectByIdRetMap" resultType="map">
  select <include refid="carCols"/> from t_car where id = #{id}
</select>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/783004.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络安全(黑客)就业分析指导

一、针对网络安全市场分析 市场需求量高&#xff1b;则是发展相对成熟入门比较容易。所需要的技术水平国家政策环境 对于国家与企业的地位愈发重要&#xff0c;没有网络安全就没有国家安全 更有为国效力的正义黑客—红客联盟 可见其重视程度。 需要掌握的知识点偏多 外围打点…

【全面解析】Windows 如何使用 SSH 密钥远程连接 Linux 服务器

创建密钥 创建 linux 服务器端的终端中执行命令 ssh-keygen&#xff0c;之后一直按Enter即可&#xff0c;这样会在将在 ~/.ssh/ 路径下生成公钥(id_rsa.pub)和私钥(id_rsa) 注意&#xff1a;也可以在 windows 端生成密钥&#xff0c;只需要保证公钥在服务器端&#xff0c;私钥…

30天自制操作系统 day 1 写一个可以在没有操作系统的计算机上输出字符串的程序,并在计算机上运行

day 1 工具&#xff1a;qemu 模拟器 今日任务 计算机启动后&#xff0c;在屏幕打印一串字符串。 理论 显示字符的原理 把一些机器指令写在第一扇区。通过int 0x10中断&#xff0c;让显卡在屏幕上显示字符。只需要在0x10之前按照规定准备好寄存器&#xff0c;显卡就能正确…

2020年下半年系统架构设计师考试案例分析真题(参考答案)

试题一 1、阅读以下关于软件架构设计与评估的叙述&#xff0c;在答题纸上回答问题1和问题2。 [说明] 某公司拟开发--套在线软件开发系统&#xff0c;支持用户通过浏览器在线进行软件开发活动。该系统的重要功能包括代码编辑、语法高亮显示、代码编译、系统调试、代码仓库管理等…

Spring数据源

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;JavaEE、Spring 目录 1、简介2、作用3、开发步骤3.1、导入坐标3.2、创建对象c3p0druid提取jdbc.properties读取配…

【iOS】App仿写--3GShare

文章目录 前言一、账号界面二、主页界面二、搜索界面三、文章界面四、活动界面五、我的界面总结 前言 这周写了3GShare的demo&#xff0c;这是一个十分麻烦的demo&#xff0c;比网易云需要设计的知识更多&#xff0c;特此撰写一下博客记录总结 一、账号界面 这里账号界面主要…

SourceTree使用ssh密钥

设置Git的user name和email&#xff1a; $ git config --global user.name "xxx" $ git config --global user.email "xxx.mailxxx.com".检查是不是已经存在密钥&#xff08;能进去说明已经存在&#xff0c;就删掉文件夹&#xff0c;重新创建&#xff09;…

SPSS数据文件的结构重组

前言&#xff1a; 本专栏参考教材为《SPSS22.0从入门到精通》&#xff0c;由于软件版本原因&#xff0c;部分内容有所改变&#xff0c;为适应软件版本的变化&#xff0c;特此创作此专栏便于大家学习。本专栏使用软件为&#xff1a;SPSS25.0 本专栏所有的数据文件可在个人主页—…

python:GEDI 波形数据提取

作者:CSDN @ _养乐多_ 在这篇博客中,我们将介绍如何使用 Python 处理和可视化 GEDI(Global Ecosystem Dynamics Investigation)激光雷达数据。GEDI 是 NASA(美国国家航空航天局)推出的激光雷达地球观测任务,用于获取全球各地生态系统的三维结构信息。本文将以提取研究区…

VSCode同时编译多个C文件

一.环境说明 1.系统&#xff1a;Ubuntu 22.04.2 LTS 2.Visual Studio Code: 1.80.1 二.问题描述 今天使用VSCode编译《Programming Abstractions In C》书中的gymjudge.c代码时遇到错误&#xff0c;错误提示为&#xff1a; (base) codistspc:~/projects/Programming-Abstracti…

Ubuntu下打开QtCreator环境变量LD_LIBRARY_PATH与终端不一致

问题描述&#xff1a; 在unbuntu下使用QtCreator编译、运行程序时&#xff0c;总是出现XXX.so: cannot open shared object file: No such file or directory这类问题&#xff0c;但是在终端中编译或者运行程序则不会出现这些问题。在网上查了好久才明白QtCreator在打开时&…

【Visual Studio】Qt 在其他 cpp 文件中调用主工程下文件中的函数

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 还整了一个如何在其他文件中调用 ui 控件的文章&#xff0c;感兴趣可以看&#xff1a;【Visual Studio】Qt 在其他 cpp 文件中调用操作 ui 界面控件。 文章目…

机器学习实战10-基于spark大数据技术与机器学习的结合应用实战

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下机器学习实战10-基于spark大数据技术与机器学习的结合应用实战&#xff0c;Spark是一种快速、通用的大数据处理框架。它是由加州大学伯克利分校AMPLab开发。Spark提供了一个分布式计算的平台&#xff0c;可以在集群…

计算机组成与体系结构 概述

文章目录 计算机组成与体系结构 概述计算机系统概述计算机系统的组成计算机层次结构 计算机性能评价 计算机组成与体系结构 概述 计算机系统概述 计算机系统的组成 计算机的基本部件&#xff1a; 运算器&#xff1a;ALU、GPRs&#xff08;通用寄存器组&#xff09;、标志寄…

Java编程教程-Java ObjectStreamClass

ObjectStreamClass作为类的序列化描述符。该类包含类的名称和serialVersionUID。 # 方法 # 示例 toString() It returns a string describing this ObjectStreamClass.Exampleimport java.io.ObjectStreamClass; import java.util.Calendar; public class ObjectStreamCl…

谷歌插件(Chrome扩展) “Service Worker (无效)” 解决方法

问题描述&#xff1a; 写 background 文件的时候报错了&#xff0c;说 Service Worker 设置的 background 无效。 解决&#xff08;检查&#xff09;方法&#xff1a; 检查配置文件&#xff08;manifest.json&#xff09; 中的 manifest_version 是否为 3。 background 中的…

深入探索Spring的Bean注入:四种方式解析与循环依赖探讨

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Docker-Compose 轻松搭建 Grafana+InfluxDb 实用 Jmeter 监控面板

目录 前言&#xff1a; 1、背景 2、GranfanaInfluxDB 配置 2.1 服务搭建 2.2 配置 Grafana 数据源 2.3 配置 Grafana 面板 3、Jmeter 配置 3.1 配置 InfluxDB 监听器 3.2 实际效果 前言&#xff1a; Grafana 和 InfluxDB 是两个非常流行的监控工具&#xff0c;它们可…

【力扣每日一题】2023.7.20 环形子数组的最大和

题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目描述的有点复杂,特别是那个公式,一看到我就烦. 其实意思就是找出一个子数组(连续),要求这个子数组的和是所有子数组中最大的,并且这个数组是环形的,意思就是我这个子数组可以从原数组的尾部开始,到原数组的头部结束,…

Nginx文件下载预览加权限验证的思考和实现

做的项目中多个模块涉及到附件、图片、PDF/Excel等文件的处理&#xff0c;包括预览、导出和下载等功能。对于体积较小的文件&#xff0c;可以直接由后端以流形式传输给前端处理&#xff1b;而较大的文件则需要通过nginx进行转发。但是如果nginx中不设置鉴权服务&#xff0c;可能…