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(主键)nameaddress_id(外键,指向 Address 表)
-
Address表id(主键)streetcity
实体类
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(主键)titleauthor_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属性中。
