当前位置: 首页 > news >正文

Mybatis基于注解的关系查询

现在有以下场景:一个身份证对应一个人。具体场景和下面文章场景一致:

先编写pojo实体类:

public class IdCard {private Integer id;private String code;//....
}
public class Person {private Integer id;private String name;private Integer age;private String sex;private IdCard card;//.....
}

然后编写dao层的Mapper接口文件

public interface IdCardMapper {@Select("select * from t_idcard where id = #{param01}")IdCard selectIdCardById(@Param("param01") Integer id);//因为是接口,所以不能实现具体函数。
}
public interface PersonMapper {@Select("select * from t_person where id = #{param01}")@Results({@Result(column = "card_id",property = "card",one = @One(select = "com.cupk.dao.IdCardMapper.selectIdCardById"))})//这里的column = "card_id"表示从上面的@Select语句中查询出来的结果中提取card_id,作为参数传入到这个@One里面的参数。而这个property = "card"表示下面的语句查询出的结果对应Person selectPersonById(@Param("param01") Integer id);
}

接着测试

    //基于注解的,一对一查关联查询@Testpublic void selectPersonByTest(){SqlSession session = MybatisUtils.getSession();PersonMapper mapper = session.getMapper(PersonMapper.class);Person person = mapper.selectPersonById(2);System.out.println(person);session.close();}

@Select注解

@Select 注解

@Select 是 MyBatis 提供的一个注解,用于直接在 Mapper 接口方法上编写 SQL 查询语句。通过 @Select 注解,你可以避免编写 XML 形式的 SQL 映射文件,使代码更加简洁。@Select 注解通常与 @Results 注解结合使用,以定义查询结果的映射关系。

基本用法
@Select("SELECT * FROM t_person WHERE id = #{id}")
Person selectPersonById(@Param("id") Integer id);

在这个示例中,@Select 注解直接定义了一条 SQL 查询语句。#{id} 是一个参数占位符,用于接收方法参数 id@Param 注解用于指定参数的名称,这样在 SQL 语句中就可以通过 #{id} 来引用这个参数。

传递参数:#{param01}

在 MyBatis 中,#{param01} 是一种参数占位符,用于在 SQL 语句中引用传递的参数。param01 是默认的参数名称,当在 Mapper 方法中没有使用 @Param 注解时,MyBatis 会自动为参数分配名称 param1param2param3 等等。如果使用了 @Param 注解,那么就可以通过 @Param 注解指定的名称来引用参数。

示例
@Select("SELECT * FROM t_person WHERE id = #{param1} AND name = #{param2}")
Person selectPersonByIdAndName(@Param("param1") Integer id, @Param("param2") String name);

在这个示例中,#{param1} 和 #{param2} 分别引用了方法参数 id 和 name@Param 注解用于指定参数的名称,这样在 SQL 语句中就可以通过 #{param1} 和 #{param2} 来引用这些参数。

使用 #{param01} 传递参数

如果没有使用 @Param 注解,MyBatis 会自动为参数分配名称 param1param2 等等。例如:

@Select("SELECT * FROM t_person WHERE id = #{param1} AND name = #{param2}")
Person selectPersonByIdAndName(Integer id, String name);

在这个示例中,MyBatis 会自动将第一个参数 id 命名为 param1,将第二个参数 name 命名为 param2。因此,在 SQL 语句中可以使用 #{param1} 和 #{param2} 来引用这些参数。

多个参数传递

当方法有多个参数时,MyBatis 会按照参数的顺序自动分配名称 param1param2 等等。如果想明确指定参数的名称,可以使用 @Param 注解。

示例
@Select("SELECT * FROM t_person WHERE id = #{id} AND age = #{age}")
Person selectPersonByIdAndAge(@Param("id") Integer id, @Param("age") Integer age);

在这个示例中,@Param 注解用于指定参数的名称,这样在 SQL 语句中就可以通过 #{id} 和 #{age} 来引用这些参数。

复杂参数传递

有时可能需要传递一个对象作为参数,例如一个 Person 对象。在这种情况下,可以直接在 SQL 语句中引用对象的属性

示例
@Select("SELECT * FROM t_person WHERE id = #{person.id} AND name = #{person.name}")
Person selectPersonByPerson(@Param("person") Person person);

在这个示例中,#{person.id} 和 #{person.name} 引用了 Person 对象的 id 和 name 属性。

关联查询

一对一

假设我们有两个表:Person 和 Address。一个 Person 关联一个 Address,即每个 Person 对应一个 Address

表结构

  1. Person 表

    • id (主键)
    • name
    • address_id (外键,指向 Address 表)
  2. Address 表

    • id (主键)
    • street
    • city

实体类

public class Person {private Integer id;private String name;private Address address;// getter 和 setter 方法
}public class Address {private Integer id;private String street;private String city;// getter 和 setter 方法
}

Mapper 接口

import org.apache.ibatis.annotations.*;public interface PersonMapper {@Select("SELECT * FROM person WHERE id = #{id}")@Results({@Result(property = "id", column = "id"),@Result(property = "name", column = "name"),@Result(property = "address", column = "address_id",one = @One(select = "selectAddressById"))})Person selectPersonById(Integer id);@Select("SELECT * FROM address WHERE id = #{id}")Address selectAddressById(Integer id);
}

解释

  1. @Select注解用于定义 SQL 查询。selectPersonById 方法通过 SELECT * FROM person WHERE id = #{id} 查询 Person 表。

  2. @Results注解用于将查询结果映射到实体类字段。

    • @Result注解包含三个主要属性:
      • property:实体类中的属性名。
      • column:数据库表中的列名。
      • one:定义一对一的关联查询。
  3. @One注解用于定义一对一映射,指定用于获取关联对象的查询方法。在这里,我们调用了 selectAddressById 方法来获取 Address 对象。

解释@One

在 MyBatis 中,@Result 注解的 column 属性并不是直接赋值给 address_id,而是用来指定一个查询结果列名,然后将该列的值用作参数传递给 selectAddressById 方法。

具体流程
  1. 主查询selectPersonById 方法被调用时,它执行 SELECT * FROM person WHERE id = #{id} 查询,假设返回以下结果(根据 id 查询得到):

    idnameaddress_id
    1张三101
  2. 映射配置

    • @Result(property = "id", column = "id"):将查询结果中的 id 列值(1)存入 Person 对象的 id 属性
    • @Result(property = "name", column = "name"):将查询结果中的 name 列值(张三)存入 Person 对象的 name 属性
    • @Result(property = "address", column = "address_id", one = @One(select = "selectAddressById"))
      • column = "address_id"从查询结果中获得这一列的值(101)
      • one = @One(select = "selectAddressById")
        • column = "address_id" 确定了要获取的列值是 101。
        • 将这个值(101)作为参数传递给 selectAddressById 方法
  3. 关联查询:调用 selectAddressById(101) 方法,这会执行 SELECT * FROM address WHERE id = #{id} 查询。

    • 假设返回结果为:

      idstreetcity
      101中山路 100 号北京
  4. 子查询结果的映射

    • 获得的 Address 对象如下:
      • id: 101
      • street: 中山路 100 号
      • city: 北京
  5. 对象填充:将整个 Address 对象映射到 Person 对象的 address 属性中。

另一种方法

import org.apache.ibatis.annotations.*;public interface PersonMapper {@Select("SELECT p.id AS person_id, p.name, a.id AS address_id, a.street, a.city " +"FROM person p " +"JOIN address a ON p.address_id = a.id " +"WHERE p.id = #{id}")@Results({@Result(property = "id", column = "person_id"),@Result(property = "name", column = "name"),@Result(property = "address.id", column = "address_id"),@Result(property = "address.street", column = "street"),@Result(property = "address.city", column = "city")})Person selectPersonByIdWithoutOne(Integer id);
}

一对多

假设我们有两个表:Author 和 Book

  • Author 表

    • id (主键)
    • name
  • Book 表

    • id (主键)
    • title
    • author_id (外键,指向 Author 表)

实体类

import java.util.List;public class Author {private Integer id;private String name;private List<Book> books; // 一个作者有多本书// getter 和 setter 方法
}public class Book {private Integer id;private String title;private Integer authorId;// getter 和 setter 方法
}

Mapper 接口

import org.apache.ibatis.annotations.*;import java.util.List;public interface AuthorMapper {@Select("SELECT * FROM author WHERE id = #{id}")@Results({@Result(property = "id", column = "id"),@Result(property = "name", column = "name"),@Result(property = "books", column = "id", many = @Many(select = "selectBooksByAuthorId"))})Author selectAuthorById(Integer id);@Select("SELECT * FROM book WHERE author_id = #{authorId}")List<Book> selectBooksByAuthorId(Integer authorId);
}

解释

  1. @Select注解:用于定义 SQL 查询。这种方式直接在 Mapper 接口的方法上定义 SQL 查询。

  2. @Results@Result注解:用于定义查询结果的映射。

    • property:实体类中的属性名。
    • column:数据库表中的列名,作为关联查询的外键。
  3. @Many注解:用于定义一对多关系,指定当列对应的值为参数时调用的方法。在这里,它用于获取 Author 的所有 Book

具体流程

  1. 主查询:调用 selectAuthorById 方法时,执行 SELECT * FROM author WHERE id = #{id},假设返回以下结果:

    idname
    1王小波
  2. 映射配置

    • @Result(property = "id", column = "id"):将查询结果中的 id 列值(1)存入 Author 对象的 id 属性。
    • @Result(property = "name", column = "name"):将查询结果中的 name 列值(王小波)存入 Author 对象的 name 属性。
    • @Result(property = "books", column = "id", many = @Many(select = "selectBooksByAuthorId"))
      • column = "id"从查询结果中获得这一列的值(1)
      • many = @Many(select = "selectBooksByAuthorId")
        • 将这个值(1)作为参数传递给 selectBooksByAuthorId 方法
  3. 关联查询:执行 selectBooksByAuthorId(1),这会执行 SQL 查询 SELECT * FROM book WHERE author_id = #{authorId}

    • 假设返回结果为:

      idtitleauthor_id
      101黄金时代1
      102白银时代1
  4. 子查询结果的映射

    • 获得的 Book 对象列表如下:
      • Book 1:{id: 101, title: “黄金时代”, authorId: 1}
      • Book 2:{id: 102, title: “白银时代”, authorId: 1}
  5. 对象填充:将整个 Book 对象列表映射到 Author 对象的 books 属性中。


http://www.mrgr.cn/news/65042.html

相关文章:

  • 近期学习前端的心得
  • SVD求解ICP旋转矩阵不正确处理
  • 动态规划—目标和
  • Django中分组查询(annotate 和 aggregate 使用)
  • 2024.10.4校招 实习 内推 面经
  • CSS 动画:网页设计的动态之美
  • 基于Docker搭建Maven私服仓库
  • java集合的fail-fast机制
  • 网络层4——网络控制协议ICMP
  • TEST2TEST2
  • DNS域名解析实验
  • 【踩坑】修复高版本dgl中distributed.load_partition不返回orig_id问题
  • 西门子五大系列PLC,该怎么选?
  • Java项目实战II基于Spring Boot的智能家居系统(开发文档+数据库+源码)
  • Transformer 架构简单理解;GPT-3.5 的架构,向量长度为 :12288;Transformer架构改进:BERT和GPT
  • 【数据结构】二叉树——判断是否为完全二叉树
  • 【AD】2-1 元件符号的绘制创建实例-电阻容/CHIP类器件
  • 网络层3——IP数据报转发的过程
  • 70B的模型需要多少张A10的卡可以部署成功,如果使用vLLM
  • 正向解析和反向解析
  • 【Vue框架】用 Vue 的时候应该选 JS 还是 TS?全面解析与实用建议
  • 【文献及模型、制图分享】中国城市家庭食物浪费行为及减量对策——以郑州市为例
  • LeetCode 876. 链表的中间结点
  • 中断处理和DMA(Direct Memory Access,直接内存访问)
  • C#-类:声明类、声明类对象
  • 中间件之XXL-Job