Mybatis基于注解的关系查询

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

先编写pojo实体类:

java 复制代码
public class IdCard {
    private Integer id;
    private String code;

    //....
}
java 复制代码
public class Person {
    private Integer id;
    private String name;
    private Integer age;
    private String sex;
    private IdCard card;
    //.....
}

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

java 复制代码
public interface IdCardMapper {
    @Select("select * from t_idcard where id = #{param01}")
    IdCard selectIdCardById(@Param("param01") Integer id);//因为是接口,所以不能实现具体函数。
}
java 复制代码
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);
}

接着测试

java 复制代码
    //基于注解的,一对一查关联查询
    @Test
    public 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 注解结合使用,以定义查询结果的映射关系。

基本用法
java 复制代码
@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 会自动为参数分配名称 param1, param2, param3 等等。如果使用了 @Param 注解,那么就可以通过 @Param 注解指定的名称来引用参数。

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

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

使用 #{param01} 传递参数

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

java 复制代码
@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 会按照参数的顺序自动分配名称 param1, param2 等等。如果想明确指定参数的名称,可以使用 @Param 注解。

示例
java 复制代码
@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 语句中引用对象的属性

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

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

关联查询

一对一

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

表结构

  1. Person

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

    • id (主键)
    • street
    • city

实体类

java 复制代码
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 接口

java 复制代码
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 查询得到):

    id name address_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} 查询。

    • 假设返回结果为:

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

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

另一种方法

java 复制代码
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);
}

一对多

假设我们有两个表:AuthorBook

  • Author

    • id (主键)
    • name
  • Book

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

实体类

java 复制代码
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 接口

java 复制代码
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},假设返回以下结果:

    id name
    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}

    • 假设返回结果为:

      id title author_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 属性中。

相关推荐
ZWZhangYu14 小时前
【MyBatis源码分析】使用 Java 动态代理,实现一个简单的插件机制
java·python·mybatis
程序员大金16 小时前
基于SSM+Vue的个性化旅游推荐系统
前端·vue.js·mysql·java-ee·tomcat·mybatis·旅游
奔跑草-20 小时前
【服务器】MyBatis是如何在java中使用并进行分页的?
java·服务器·mybatis
秋恬意1 天前
接口绑定有几种实现方式
mybatis
谢家小布柔1 天前
MyBatis入门的详细应用实例
mybatis
雅俗共赏zyyyyyy1 天前
Mybatis分页插件的使用问题记录
mybatis
陈大爷(有低保)2 天前
mybatisPlus使用步骤详解
java·后端·mybatis
武子康2 天前
Java-31 深入浅出 Spring - IoC 基础 启动IoC XML与注解结合的方式 配置改造 applicationContext.xml
java·大数据·spring·mybatis·springboot
猿java2 天前
这样理解 MyBatis缓存机制,真香!
java·后端·mybatis
豪宇刘2 天前
深入了解 MyBatis:简化 Java 数据库交互
java·数据库·mybatis