Mybatis的关联查询
转载:https://blog.csdn.net/z_ssyy/article/details/81706876
首先要了解对象的三种关联方式
*数据库表的关联关系有三种,一对一,一对多,多对多
一对一 是通过在任意一方的主键,引入对方主键作为外键来实现的,就是说主键与外键为同一字段
一对多 是通过在“多”的一方,添加“一”的一方的主键作为外键
多对多 是通过一张中间关系表,引入两张表的主键作为外键,两个主键成为联合主键或使用新的字段作为主键
*在java类中关联关系也有三种,一对一,一对多,多对多
一对一 在本类中定义对方类型的对象,如A类中定义B类类型的属性b,B类中定义A类类型的属性a
一对多 一个A类类型对应多个B类类型的情况,需要在A类中以集合的方式引入B类类型的对象,在B类中定义A类类型的属性a
多对多 在A类中定义B类类型的集合,在B类中定义A类类型的集合
表与表之间的关联:
- association:用于映射关联单个对象信息
- collection:对关联查询到的多条记录映射到集合对象中
- property:关联的属性名,就是将用户对象关联到某个表的那个属性
- column:数据库中的字段名
- javaType: 属性的类型
- ofType: 指明集合中的元素的类型
一对一查询
需求:根据订单id查询订单信息,以及关联的用户信息
Order类:
public class Order { private Integer id; private Date createtime; private String state; //关联属性 private User user; //订单属于哪一个用户
Order表的Sql映射文件:
<!-- 定义一个属性与列的映射 --> <resultMap type="Order" id="OrderAndUserMap"> <!-- order 表的映射 --> <id column="id" property="id"/> <result column="createtime" property="createtime"/> <result column="state" property="state"/> <!-- 配置关联属性user的信息 association:用于映射关联单个对象信息 property:关联的属性名,就是将用户对象关联到Order的那个属性 avaType: 属性的类型 --> <association property="user" javaType="User"> <id column="u_id" property="UserId"/> <result column="username" property="name"/> <result column="password" property="password"/> <result column="sex" property="sex"/> <result column="address" property="address"/> <result column="brithday" property="brithday"/> </association> </resultMap>
SQL语句的定义:
<!-- 查询一个这个订单的用户信息 --> <select id="findUserByOrderId" parameterType="int" resultMap="OrderAndUserMap"> select <include refid="UserOrderColumn"/> from t_user u ,t_order o where u.id = o.USID and o.ID = #{id} </select> <!-- id名一样,会取第一个值,取个别名避免错误 --> <sql id="UserOrderColumn"> u.id u_id,u.username,u.password,u.sex,u.brithday,u.address,o.id,o.createtime,o.state </sql>
OrderMapper接口:
//查询一个这个订单的用户信息 Order findUserByOrderId (int oid);
测试代码:
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class); Order order = orderMapper.findUserByOrderId(1); System.out.println(order); sqlSession.close();
第二种方式:(推荐)
User表的Sql映射文件:(有根据id查询的语句)
//UserMapper.java接口 // 根据id查询用户: User queryUserById(int id) throws Exception;
<mapper namespace="com.mybatis.mapper.UserMapper">//地址 <!-- 使用resurtMap,映射属性 --> <resultMap type="User" id="UserMap"> <id column="id" property="UserId"/> <result column="username" property="name"/> </resultMap> <!-- 根据id查询 --> <select id="queryUserById" parameterType="int" resultMap="UserMap" > select * from t_user where id = #{id} </select>
修改Order表的Sql映射文件:
select: namespace.statementId , 关联属性通过哪一个statement查询 根据用户id查询用户信息
column: 列名, 从主查询,吧哪一个列的值作为参数,传递给调用的statement
<select id="findUserByOrderId" parameterType="int" resultMap="OrderAndUserMap2"> select * from t_order where id = #{id} </select> <resultMap type="Order" id="OrderAndUserMap2"> <!-- order 表的映射 --> <id column="id" property="id"/> <result column="createtime" property="createtime"/> <result column="state" property="state"/> <!-- 配置关联属性 --> <association property="user" javaType="User" select="com.mybatis.mapper.UserMapper.queryUserById" column="usid"> (关联order表的id字段) </association> </resultMap>
测试:执行了两条语句,简化代码
一对多查询
需求:查询用户,及用户下的所有订单信息
User类:
public class User { private Integer UserId; private String name; private String password; private String sex; private Date brithday; private String address; //new出对象,避免空指针异常 private List<Order> orders = new ArrayList<>();
User表的Sql映射文件:
<!-- 定义一个属性与列的映射 --> <resultMap type="User" id="UserAndOrderMap"> <!-- 映射的User --> <id column="id" property="UserId"/> <result column="username" property="name"/> <result column="password" property="password"/> <result column="sex" property="sex"/> <result column="address" property="address"/> <result column="brithday" property="brithday"/> <!-- 配置集合关联属性 collection属性 property: 关联属性名: ofType: 集合元素的类型, 列映射的Order类 --> <collection property="orders" ofType="Order" > <id column="o_id" property="id"/> <result column="createtime" property="createtime"/> <result column="state" property="state"/> </collection> </resultMap>
SQL语句的定义:
<!-- 根据一个用户id查询所有订单信息 --> <select id="findInfoByorderId" parameterType="int" resultMap="UserAndOrderMap"> select <include refid="UserOrderColumn"/> from t_user u ,t_order o where u.id = o.USID and u.ID = #{UserId} </select> <!-- id名一样,会取第一个值,取个别名避免错误 --> <sql id="UserOrderColumn"> u.id,u.username,u.password,u.sex,u.brithday,u.address,o.id o_id,o.createtime,o.state </sql>
UserMapper接口:
//根据一个用户id查询所有订单信息 User findInfoByorderId(int oid) throws Exception;
测试:
UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.findInfoByorderId(27); System.out.println(user);
多对多查询
需求:根据用户id,查询响应的订单,订单详情,商品详情信息
映射思路:
将用户信息映射到user中。
在user类中添加订单列表属性List<Orders> orders,将用户创建的订单映射到orders
在Orders中添加订单明细列表属性List<OrderDetail>orderdetials,将订单的明细映射到orderdetials
实体类:
User表关联Order表:
public class User { private Integer UserId; private String name; private String password; private String sex; private Date brithday; private String address; private List<Order> orders = new ArrayList<>();
Order表关联Orderdetail表:
public class Order { private Integer id; private Date createtime; private String state; //关联属性, 订单详情 集合关联属性 private List<Orderdetail> orderdetails = new ArrayList<>();
Orderdetail表关联product表:
public class Orderdetail { private Integer id; private Integer num; private Double price; //关联属性 商品 单个关联属性 private Product product;
UserMapper.java接口方法:
//根据id查询用户以及用户所有的订单信息,以及订单详情及商品信息(方法名越长,越方便理解) User findUserAndOrderAndOrderdetailAndProductById(int id) throws Exception;
User表的Sql映射文件:
<resultMap type="User" id="userOrderOrderdetailProductMap"> <!-- order 表的映射 --> <id column="id" property="UserId"/> <result column="username" property="name"/> <result column="password" property="password"/> <result column="sex" property="sex"/> <result column="address" property="address"/> <result column="brithday" property="brithday"/> <!-- 配置关联Order属性 --> <collection property="orders" ofType="Order" > <id column="o_id" property="id"/> <result column="createtime" property="createtime"/> <result column="state" property="state"/> <!-- 配置关联orderdetails属性 --> <collection property="orderdetails" ofType="Orderdetail" > <id column="od_id" property="id"/> <result column="num" property="num"/> <result column="price" property="price"/> <!-- 关联属性: product 单个的关联属性--> <association property="product" javaType="Product"> <id column="p_id" property="id" /> <result column="name" property="name" /> <result column="p_price" property="price" /> <result column="description" property="description" /> </association> </collection> </collection> </resultMap>
sql语句的定义:
<!-- 根据id查询用户以及用户所有的订单信息,以及订单详情及商品信息(多对多查询 --> <select id="findUserAndOrderAndOrderdetailAndProductById" parameterType="int"
resultMap="userOrderOrderdetailProductMap"> select <include refid="userOrderOrderdetailProductColumn"/> from t_user u join t_order o on u.id = o.usid join t_orderdetail od on o.id = od.id join t_product p on od.productid = p.id where u.id = #{id} </select> <sql id="userOrderOrderdetailProductColumn"> u.*, o.id o_id,o.CREATETIME,o.STATE,od.id od_id, od.num,od.price, p.id p_id,p.name,p.price p_price,p.description </sql>
测试:
SqlSession sqlSession = MybatisUtil.openSession(); //根据id查询用户以及用户所有的订单信息,以及订单详情及商品信息(多对多查询 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.findUserAndOrderAndOrderdetailAndProductById(23); System.out.println(user); sqlSession.close();
总结
resultMap:
使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
association:
作用:将关联查询信息映射到一个对象中。
场合:为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的关联属性中,
比如:查询订单及关联用户信息。
collection:
作用: 将关联查询信息映射到一个list集合中。
场合: 为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,
比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,
将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询.