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 会自动为参数分配名称 param1
, param2
, param3
等等。如果使用了 @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 会自动为参数分配名称 param1
, param2
等等。例如:
@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
注解。
示例
@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
。
表结构
-
Person
表id
(主键)name
address_id
(外键,指向 Address 表)
-
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);
}
解释
-
@Select
注解用于定义 SQL 查询。selectPersonById
方法通过SELECT * FROM person WHERE id = #{id}
查询Person
表。 -
@Results
注解用于将查询结果映射到实体类字段。@Result
注解包含三个主要属性:property
:实体类中的属性名。column
:数据库表中的列名。one
:定义一对一的关联查询。
-
@One
注解用于定义一对一映射,指定用于获取关联对象的查询方法。在这里,我们调用了selectAddressById
方法来获取Address
对象。
解释@One
在 MyBatis 中,@Result
注解的 column
属性并不是直接赋值给 address_id
,而是用来指定一个查询结果列名,然后将该列的值用作参数传递给 selectAddressById
方法。
具体流程
-
主查询:
selectPersonById
方法被调用时,它执行SELECT * FROM person WHERE id = #{id}
查询,假设返回以下结果(根据id
查询得到):id name address_id 1 张三 101 -
映射配置:
@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
方法。
-
关联查询:调用
selectAddressById(101)
方法,这会执行SELECT * FROM address WHERE id = #{id}
查询。-
假设返回结果为:
id street city 101 中山路 100 号 北京
-
-
子查询结果的映射:
- 获得的
Address
对象如下:id
: 101street
: 中山路 100 号city
: 北京
- 获得的
-
对象填充:将整个
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);
}
解释
-
@Select
注解:用于定义 SQL 查询。这种方式直接在 Mapper 接口的方法上定义 SQL 查询。 -
@Results
和@Result
注解:用于定义查询结果的映射。property
:实体类中的属性名。column
:数据库表中的列名,作为关联查询的外键。
-
@Many
注解:用于定义一对多关系,指定当列对应的值为参数时调用的方法。在这里,它用于获取Author
的所有Book
具体流程
-
主查询:调用
selectAuthorById
方法时,执行SELECT * FROM author WHERE id = #{id}
,假设返回以下结果:id name 1 王小波 -
映射配置:
@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
方法。
- 将这个值(1)作为参数传递给
-
关联查询:执行
selectBooksByAuthorId(1)
,这会执行 SQL 查询SELECT * FROM book WHERE author_id = #{authorId}
。-
假设返回结果为:
id title author_id 101 黄金时代 1 102 白银时代 1
-
-
子查询结果的映射:
- 获得的
Book
对象列表如下:Book 1
:{id: 101, title: “黄金时代”, authorId: 1}Book 2
:{id: 102, title: “白银时代”, authorId: 1}
- 获得的
-
对象填充:将整个
Book
对象列表映射到Author
对象的books
属性中。