Mybatis复杂映射

本文详细介绍了Mybatis中如何实现动态删除、修改、查询操作,以及使用可变参数的注意事项。同时,讨论了parameterType和resultType的使用,并通过实例展示了关联查询的实现,包括一对一、一对多关系的处理,以及如何通过resultMap返回关联查询结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可变参数

java中方法参数的位置支持一中语法

方法名([类型]… 变量名)
上面的写法就是可变参数

//声明带有可变参数的方法
public  void sum(int... nums){
    //参数...表示这个参数指定的变量按照数组来处理
    //这种声明方式每个方法只能出现一个
    // 而且必须是最后一个参数
    //将nums中所有元素的和输出
    int sum=0;
    for(int i=0;i<nums.length;i++){
        sum+=nums[i];
    }
    System.out.println(sum);
}
@Test
void param(){
    //调用可变参数的方法,直接传入多个类型匹配的参数即可
    //参数数量不限0~多个都可以
    sum(5,9,7,6);
    sum();
}

使用可变参数的注意事项

定义方法时:

可变参数必须是方法所有参数的最后一个
方法中将可变参数看做一个数组来操作
方法调用时:

调用可变参数的方法时,可以传入的参数数量不限,类型匹配即可
参数数量不限表示不传参数也可以
直接传入一个类型匹配的数组也可以

Mybatis实现动态删除操作

我们项目中有一个需求,需求一次性删除指定的多个id的行
比如我们要删除id为2,4,7,11的行
一次性删除效率高sql代码如下 delete from t_user where id in(?,?,?,?)

但是每次删除不一定是4个
那么我们就需要根据用户传入的要删除的id的数组生成同样数量的?
这样的需求我们就只能通过xml文件中的动态sql生成实现了
下面我们在UserMapperPlus接口中添加一个方法来对应这个动态的删除
可以采用上面学习的可变参数来声明
代码如下

//实现动态删除的方法
Integer deleteByIds(Integer... ids);

回到UserMapperPlus.xml文件中编写对应这个删除的代码

<!--
  删除操作使用 delete标签 id对应接口中的方法名
  因为是增删改操作,不需要声明返回值类型resultType,默认就是int
  至于参数类型,系统常用的参数都能自动识别 基本数据类型,String,数组等
 -->
<!--  
collection指定要遍历的数组  array表示参数接收到的数组
item表示遍历的过程中数组中的单个元素,id是这个元素的名称 
separator指定循环过程中每次循环间隔出现的分隔符
foreach标签中编写#{}占位符,占位符中的内容是item属性指定的"id"
 -->
<delete id="deleteByIds">
    delete from t_user where id in(
    <foreach collection="array" item="id" separator=",">
        #{id}
    </foreach>
    ) 
</delete>

测试类开启日志
private static Logger log=
LoggerFactory.getLogger(MybatisPlusTest.class);
测试类

@Autowired
UserMapperPlus userMapper;
@Test
void deleteIds(){
    int num=userMapper.deleteByIds(2,4,7,11);
    System.out.println(num);
}

在这里插入图片描述

Mybatis实现动态修改操作

在开发项目的过程中可能有如下需求:
修改用户信息
用户可能指定某些信息进行修改
可能修改用户名,年龄
也可能修改电话和email,
这个需求可能修改用户的任意一行
如果使用全行修改需要先查询再修改,是比较消耗性能的,我们需要针对用户输入的属性动态生成只修改用户输入属性的sql语句

分析:
如果什么都可以修改参数最好还是User类型
我们可以判断User类型对象有哪些属性被赋值,哪些属性就需要修改,如果为null就不修改
先声明接口中的方法
代码如下

//实现动态修改的方法
Integer updateUserInfo(User user);

xml文件中添加动态修改的代码

<!--  动态修改方法  -->
<!--  因为这个方法的参数不是系统提供的常用类型
      需要使用parameterType来指定User的全类名 -->
<!--  if标签中需要使用test来指定一个boolean类型结果
       如果结果为true 就会将if标签中间的内容生成在sql语句中
       这里的具体逻辑是:只要user对象的某个属性不是空,
       就生成修改这个属性的sql语句-->
<!--  <set>标签的作用
        1.在<set>标签的位置生成set关键字
        2.<set>标签会删除最后一个多余的","完成sql语句的生成
 -->
<update id="updateUserInfo"
        parameterType="cn.tedu.mybatis.model.User">
    update t_user
    <set>
        <if test="username != null">
            username=#{username},
        </if>
        <if test="password != null">
            password=#{password},
        </if>
        <if test="age != null">
            age=#{age},
        </if>
        <if test="phone != null">
            phone=#{phone},
        </if>
        <if test="email != null">
            email=#{email}
        </if>
    </set>
    where id=#{id}
</update>

测试类

@Test
void update(){
    User user=new User();
    user.setId(16);
    //user.setUsername("天蓬元帅");
    user.setPassword("666");
    user.setAge(800);
    int num=userMapper.updateUserInfo(user);
    System.out.println(num);
}

Mybatis实现动态查询

在这里插入图片描述
实际开发中我们经常会遇到这个或类似这样的需求
有如下几种情况

1.不输入条件直接查询
select * from t_user
2.输入某一个条进行查询
select * from t_user where username like ?
3.输入某两个条进行查询
select * from t_user where username like ? and age=?
4.输入三个条进行查询
select * from t_user where username like ? and age=? and phone like ?

实际上上面的查询也是一个根据用户输入的条件动态生成sql语句的过程
UserMapperPlus接口中添加动态查询的方法
代码如下

List<User> findUsersByParam(
        @Param("username") String username,
        @Param("age") Integer age,
        @Param("phone") String phone);

xml文件代码如下

<!--  动态查询的方法  -->
<!--  查询是必须声明返回值类型的resultType  -->
<!--  Mybatis中一个查询返回一个对象或一个集合返回值的类型
                                   都指定具体的实体类类型  -->
<!--  <where>标签和<set>标签类似
       当没有任何条件是where关键字不会出现
       当有条件是<where>标签负责处理多余的and-->
<select id="findUsersByParam"
        resultType="cn.tedu.mybatis.model.User" >
    select
        id,username,password,age,phone,email
    from
        t_user
    <where>
        <if test="username != null">
            username like #{username}
        </if>
        <if test="age != null">
            and age = #{age}
        </if>
        <if test="phone != null">
            and phone like #{phone}
        </if>
    </where>
</select>

测试类

@Test
void select(){
    List<User> users=userMapper.findUsersByParam(
            null,24,null);
    for(User u:users){
        System.out.println(u);
    }
}

parameterType和resultType的使用

resultType是指定当前方法的返回值的属性
所有select标签既查询操作必须指明
如果是增删改操作不需要指明默认int

parameterType是指定当前方法参数类型的属性
任何增删改查操作都可能需要
如果参数类型不是基本数据类型不是String,不是数组或集合
那就必须编写,比如我们自己声明创建的实体类就需要编写出来

Mybatis实现关联查询

数据库中的关联关系

关系型数据库表与表之间的关系存在如下几种
一对一
一对多(多对一)
多对多

以一对多为例我们来讲解一下Mybatis框架中处理关联查询的解决方案
我们将t_user表看做是一个员工表
我们再设计一个部门表,让部门和员工表建立一个一对多的关系
既一个部门有多个员工,部门是一的一方,每个员工只能属于一个部门员工是多的一方
在这里插入图片描述
要想实现这样的关系我们先要在数据库中建立这样的结构
依次进行如下操作

-- 创建 t_dept表  部门表
create table t_dept(
id int primary key auto_increment comment '部门id',
name varchar(50) not null         comment '部门名'
)default charset=utf8
​
-- t_user表需要添加一个dept_id列表示自己的部门
alter table t_user add column dept_id int
也可以这样: ALTER TABLE t_user ADD COLUMN dept_id INT NOT NULL AFTER email
​
-- 部门表中添加3行数据表示3个部门
insert into t_dept(name) values('java'),('c++'),('linux')
​
-- 将id小于10的user的dept_id赋值为1
update t_user set dept_id=1 where id<10
-- 将id大于等于10的user的dept_id赋值为2
update t_user set dept_id=2 where id>=10

两张表的关系依靠t_user表的dept_id列来表示
这个列的值如果是1,表示他是java部门的
但是这个值现在可以随意修改如果随意修改,就不能保证用户的dept_id列的值能够对应一个真实存在的部门了这样是不行的
要想设置dept_id列的取值只能在存在的部门中,那么就需要设置外键约束

-- 创建外键约束
-- 约束t_user表的dept_id列只能从t_dept表的id列中取值
​
alter table t_user
add constraint dept_user foreign key (dept_id)
references t_dept(id)
​
-- constraint(约束) references(引用)

外键的创建会使数据引用时不会出现错误数据

使数据库中的数据正确性更高更可靠

但是由于外键带来了很多维护操作,是比较麻烦的

现在有些公司在开发软件时不创建外键,获得更简便的维护

实现连接查询的sql语句

如果我们想查询的结果如下
在这里插入图片描述
上面查询的sql语句要这样写
– 查询user的id user的username 和dept的name
select
u.id,username,name
from t_dept d
join t_user u
on d.id=u.dept_id

java中如果想执行这样的连接查询并返回结果的话需要怎么做
最简单的办法就是新建一个实体类来完成这个连接查询
创建一个UserVo类代码如下(VO: Value Object)

@Data
public class UserVo {
​
    private Integer id;
    private String username;
    private String deptname;
}

mapper包中新建一个接口XmlMapper代码如下

@Repository
public interface XmlMapper {
​
    //连接查询的方法
    List<UserVo> findUserDept();
}

这个接口要对应一个新的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="cn.tedu.mybatis.mapper.XmlMapper">
    <select id="findUserDept"
            resultType="cn.tedu.mybatis.vo.UserVo">
    select
   u.id,username,name deptname   别名要对应pojo中的名字
    from t_dept d
    join t_user u
    on  d.id=u.dept_id
​
    </select>
</mapper>

测试代码

@Autowired
XmlMapper xmlMapper;
@Test
void join(){
    List<UserVo> users=xmlMapper.findUserDept();
    for(UserVo user: users){
        System.out.println(user);
    }
}

使用Mybatis查询返回关联查询结果

实际开发中如果遇到较多的连接查询

每个连接查询都创建不同的Vo类的话,Vo类的数量就会比较多

看一下这个图的结构
在这里插入图片描述
这个图的含义是我们可以创建一个Dept类型的实体类对应t_dept表

在这个实体类中我们可以声明一个集合保存若干user\员工的信息

Dept类的代码如下

@Data
public class Dept {
​
    private Integer id;
    private String name;
    //声明一个保存员工对象的集合
    private List<User> users;
}

我们编写一个根据指定部门id 查询部门信息和这个部门包含的所有员工的信息的sql语句
代码如下

select 
   *
from 
    t_dept d
left join  
    t_user u
on
    d.id=u.dept_id
where d.id=1    

要实现上面的查询我们就需要在接口中添加一个方法
继续在XmlMapper接口中添加方法

//查询部门关联部门员工的方法
Dept findDeptWithUserById(Integer id);

在XmlMapper.xml文件中添加代码如下
注意resultMap的使用

<!--  我们需要一个结构的声明
  这个结构是一个Dept类型的结构,其中包含Dept中的id和name
  还要包含Dept中保存的List<User>users的信息
  这里还要对User的每个列(包括sql语句中设置的别名列)
  都做出对应关系的声明
  这样才能让Mybatis在返回一个Dept对象时也能将Dept中的User集合中
  的每个员工赋上值
  -->
<!--  resultMap就是专门来设置每个列和对象中每个属性的映射关系的
  它支持映射一个对象中的集合中的列
  id是resultMap的唯一标识,哪个查询需要哪个查询指定
  type指定这个结果返回值的载体,这里指包含着员工信息的Dept对象-->
<resultMap id="deptMap" type="cn.tedu.mybatis.model.Dept">
    <!--  一个result标签表示一条对应关系,
    指java中的哪个属性对应数据库中的哪个列
    
      column指定数据库查询结果的列名,对应数据库  ,property指定实例类中的属性名-->
    <result column="id" property="id" />
    <result column="name" property="name"/>
    <!-- collection是集合的意思,表示当前Dept类
                        除了id和name之外还有一个集合
         property指定集合的属性名
         ofType指定集合的泛型的类型-->
    <collection property="users"
                ofType="cn.tedu.mybatis.model.User">
        <!-- 这里来指定本次查询的哪个列对应user对象的哪个属性 -->
        <result column="userId" property="id" />
        <result column="username" property="username" />
        <result column="password" property="password" />
        <result column="age" property="age" />
        <result column="phone" property="phone" />
        <result column="email" property="email" />
    </collection>
</resultMap>
​
​
<select id="findDeptWithUserById"
        resultMap="deptMap">
select
    d.id,
    name,
    u.id userId,
    username,
    password,
    age,
    phone,
    email
from
    t_dept d
left join
    t_user u
on
    d.id=u.dept_id
where d.id=#{id}
</select>

测试代码

@Test
void dept(){
    Dept d=xmlMapper.findDeptWithUserById(3);
    System.out.println(d);
}

代码
在这里插入图片描述

查询示意图
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值