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} 分别引用了方法参数 id 和 name。@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 对象的 id 和 name 属性。

关联查询

一对一

假设我们有两个表:Person 和 Address。一个 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);
}

一对多

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

  • 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 属性中。

相关推荐
wljt14 小时前
公司二-面试题
java·开发语言·mybatis
VimorphTech17 小时前
文本已经改了,旧的音频生成结果还能回写吗?
java·数据库·mybatis
麻瓜code1 天前
双写一致性:为什么是“删缓存“,而不是“改缓存“
java·缓存·mybatis
郭小李2 天前
mybatis 动态 sql
java·sql·mybatis
知守观2 天前
技术考古:iBATIS 2.3.4 时代的持久层,是如何用 Map 玩转 307 个存储过程的?
java·后端·mybatis
captain3762 天前
MyBatis Plus(1)
java·服务器·mybatis
代码不停2 天前
MyBatis进阶
spring boot·mybatis
captain3762 天前
MyBatis(入门5)其他查询操作
java·数据库·spring boot·mybatis
captain3762 天前
MyBatis(进阶1)
mybatis
郭小李3 天前
mybatis的 Mapper.xml语法
xml·java·mybatis