SpringBoot使用Mybatis注解進行一對多和多對多查詢
GitHub的完整示例項目地址kingboy-springboot-data
一、模擬的業務查詢
系統中的用戶user都有唯一對應的地址信息address,每個用戶可以有多量車car,類似如下結構
|-- user |-- address |-- carList |-- car1 |-- car2
二、對應的實體類如下
/省略setter/getter public class Address { private Long id; private String province; private String city; } public class Car { private Long id; private String color; private String name; //用戶id private Long userId; } public class User { private Long id; //地址信息,和用戶是一對一的關系 private Address address; //地址id private Long addressId; //用戶擁有的車,和用戶是一對多的關系 private List<Car> cars; }
三、對應的建表語句和模擬數據如下
CREATE TABLE IF NOT EXISTS `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `nick_name` varchar(50) DEFAULT NULL, `address_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `address` ( `id` int(11) NOT NULL AUTO_INCREMENT, `province` varchar(50) DEFAULT NULL, `city` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `car` ( `id` int(11) NOT NULL AUTO_INCREMENT, `color` varchar(50) DEFAULT NULL, `name` varchar(50) DEFAULT NULL, `user_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `user` VALUES ('1', 'baby', '1'), ('2', 'kingboy', '2'), ('3', 'boy', '3'), ('4', 'kingbaby', '4'); INSERT INTO `address` VALUES ('1', '北京', '北京'), ('2', '天津', '天津'), ('3', '安徽', '宿州'), ('4', '廣東', '廣州'); INSERT INTO `car` VALUES ('1', 'green', '路虎', '1'), ('2', 'white', '奔馳', '2'), ('3', 'blue', '瑪莎拉蒂', '4'), ('4', 'yellow', '蘭博基尼', '4');
四、@One一對一映射
以獲取用戶的唯一地址為例,首先我們定義一個根據地址id查詢地址的查詢方法
public interface AddressRepository { /** * 根據地址id查詢地址 */ @Select("SELECT * FROM `address` WHERE id = #{id}") Address findAddressById(Long id); }
然后我們定義一個根據用戶id查詢用戶的方法
public interface UserRepository { @Select("SELECT * FROM `user` where id = #{id}") User findUserWithAddress(Long id); }
這個時候我們查詢出來的user對象中的address屬性是空的,和address並沒有任何關聯。
那么我們要把user中的addressId傳遞給AddressRepository的查詢地址的方法,
然后把查詢出的地址對象address賦值給user的address屬性,那么我們怎么做呢?
public interface UserRepository { @Select("SELECT * FROM `user` where id = #{id}") @Results({ @Result(property = "address", column = "address_id", one = @One(select = "com.kingboy.repository.address.AddressRepository.findAddressById")) }) User findUserWithAddress(Long id); }
我們要使用@Resutl注解對返回的結果進行配置,
- property = “address”, 表示要將返回的查詢結果賦值給user的address屬性
- column = “address_id” 是指將user表中的address_id作為com.kingboy.repository.address.AddressRepository.findAddressById的查詢參數
- one 表示這是一個一對一的查詢
- @One(select = “方法全路徑) 表示我們調用的方法
五、@Many一對多查詢
以獲取用戶擁有的所有車car為例,首先我們定義一個根據用戶id查詢車的查詢方法
public interface CarRepository { /** * 根據用戶id查詢所有的車 */ @Select("SELECT * FROM `car` WHERE user_id = #{userId}") List<Car> findCarByUserId(Long userId); }
然后我們定義一個根據用戶id查詢用戶的方法
public interface UserRepository { @Select("SELECT * FROM `user` where id = #{id}") User findUserWithAddress(Long id); }
這個時候我們查詢出來的user對象中的List屬性是空的,和car的查詢方法並沒有任何關聯。
那么我們要把user中的用戶id傳遞給CarRepository的查詢車的方法,
然后把查詢出的集合對象List賦值給user的cars屬性,那么我們怎么做呢?
public interface UserRepository { /** * 查詢帶有車信息的用戶===============演示一對多(關於多對多其實就是兩個一對多組成) */ @Select("SELECT * FROM `user` WHERE id = #{id}") @Results({ @Result(property = "cars", column = "id", many = @Many(select = "com.kingboy.repository.car.CarRepository.findCarByUserId")) }) User getUserWithCar(Long id); }
我們要使用@Resutl注解對返回的結果進行配置, - property = “cars”, 表示要將返回的查詢結果賦值給user的cars屬性 - column = “id” 是指將user表中的用戶主鍵id作為com.kingboy.repository.address.CarRepository.findCarByUserId的查詢參數 - many 表示這是一個一對多的查詢 - @Many(select = “方法全路徑) 表示我們調用的方法, 方法參數userId就是上面column指定的列值
六、@One @Many的總結
首先我們統一下概念:查詢Address或Car的方法,接下來統稱為User的附屬查詢。
共同點:
- 無論是一對一還是一對多,都是通過附屬查詢來實現的,我們需要定義這個附屬查詢方法。
- 在主查詢方法中通過@One、@Many指定附屬查詢方法的全路徑。
- 都通過column來傳遞參數給附屬方法。
不同點:
- 一對一,那么附屬方法返回的是一個單獨的對象
- 一對多,那么附屬方法返回的是一個對象集合