Mybatis复杂映射
XML方式:
1. 一对一
假如我有一个需求,两张表,用户表和订单表。从订单的角度出发,一个订单只能有一个用户
user.id和orders.id关联。
正确的SQL应该这样写
SELECT * FROM USER u , orders o WHERE u.id=o.uid
此时的结果既有订单信息,又有用户信息。我们把结果不论封装到User
中还是Order
中都是不行的。我们可以在Order实体类中加入User
//Order.java
public class Order {
private Integer id;
private String orderTime;
private Double total;
//表示该订单属于哪个用户
private User user;
//省略getSet、toString
}
//User.java
public class User {
private Integer id;
private String username;
//省略getSet、toString
}
Mapper:
package com.dxh.dao;
import com.dxh.pojo.Order;
import java.util.List;
public interface OrderMapper {
public List<Order> findOrderAndUser();
}
XML:
<mapper namespace="com.dxh.dao.OrderMapper">
<resultMap id="orderMap" type="com.dxh.pojo.Order">
<result property="id" column="id"></result>
<result property="orderTime" column="orderTime"></result>
<result property="total" column="total"></result>
<association property="user" javaType="com.dxh.pojo.User">
<result property="id" column="uid"></result>
<result property="username" column="username"></result>
</association>
</resultMap>
<select id="findOrderAndUser" resultMap="orderMap">
SELECT * FROM orders o ,USER u WHERE u.id=o.uid
</select>
</mapper>
-
<select id="findOrderAndUser" resultMap="orderMap">
resultMap表示:手动配置实体属性与表字段的映射关系,值填写<resultMap>
标签中的id -
<resultMap id="orderMap" type="com.dxh.pojo.Order">
id与select标签中的resultMap的值一致。 -
<result property="id" column="id"></result>
表示实体属性id与数据库返回的字段id对应 -
<association property="user" javaType="com.dxh.pojo.User">
property 就是Order实体中的user这个属性javaType就是其类型
-
<result property="id" column="uid"></result>
我们可以在数据库的返回结果中看到,因为orders
表和user
表中都有id这个字段,id又是其外键,而orders
表中的uid其实就是user
的id,因此我们填写uid
我们测试一下:
@Test
public void test3() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List<Order> orderAndUser = mapper.findOrderAndUser();
for (Order order : orderAndUser) {
System.out.println(order);
}
}
结果:
Order{id=1, orderTime='2020-11-09', total=100.0, user=User{id=1, username='lucy'}}
Order{id=2, orderTime='2020-11-09', total=200.0, user=User{id=1, username='lucy'}}
Order{id=3, orderTime='2020-11-09', total=300.0, user=User{id=2, username='李四'}}
2. 一对多
假设我们有一个需求,同样是两张表user
和orders
,从用户的角度出发,一个用户可以拥有多个订单 ,这也就是一对多关系,我们要查询出所有用户的信息,以及每个用户的订单信息。
正确的SQL应该是:
SELECT u.*,o.id oid,o.ordertime,o.total,o.uid FROM user u LEFT JOIN orders o on u.id=o.uid
我们在User实体类中增加订单的信息。
public class User {
private Integer id;
private String username;
//该用户具有的订单信息
private List<Order> orderList;
//getset、toString方法省略
}
UserMapper.java
//查询出所有用户和其订单信息
public List<User> findAllUser();
UserMapper.xml
<resultMap id="userMap" type="com.dxh.pojo.User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<collection property="orderList" ofType="com.dxh.pojo.Order">
<result property="id" column="oid"></result>
<result property="orderTime" column="orderTime"></result>
<result property="total" column="total"></result>
</collection>
</resultMap>
<select id="findAllUser" resultMap="userMap">
SELECT u.*,o.id oid,o.ordertime,o.total,o.uid FROM user u LEFT JOIN orders o on u.id=o.uid
</select>
我们来看一下与一对一不同的地方:
<id property="id" column="id"></id>
表示主键<collection property="orderList" ofType="com.dxh.pojo.Order">
<collection>
标签,我们想要配置User实体中的orderList,而orderList属性是一个集合,所以使用<collection>
property="orderList"
表示User实体中的orderList的属性名ofType="com.dxh.pojo.Order"
表示property
中那个属性名所对应集合的泛型
我们来测试一下:
@Test
public void test4() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allUser = mapper.findAllUser();
for (User user : allUser) {
System.out.println(user);
}
}
User{id=1, username='lucy', orderList=[Order{id=1, orderTime='2020-11-09', total=100.0, user=null}, Order{id=2, orderTime='2020-11-09', total=200.0, user=null}]}
User{id=2, username='李四', orderList=[Order{id=3, orderTime='2020-11-09', total=300.0, user=null}]}
User{id=3, username='zhaowu', orderList=[]}
结果正确!
3. 多对多
一个用户有多个角色,一个角色也可以被多个用户使用。这个结构是这样的:
我们有个需求,查询出用户,并查询出该用户所拥有的角色
对应的SQL语句:
SELECT
*
FROM
USER u
LEFT JOIN user_role ur ON u.id = ur.user_id
LEFT JOIN role r ON r.id = ur.role_id
结果:
多对多其实就是两个一对多,我们在编写代码时都是差不多的。
User.java和Role.java
//User.java
public class User {
private Integer id;
private String username;
//当前用户具备哪些角色
private List<Role> roleList;
private List<Order> orderList;
//getSet、toString方法省略
}
//Role.java
public class Role {
private Integer id;
private String roleName;
//getSet、toString方法省略
}
UserMapper.java
//查询出所有用户和其角色信息
public List<User> findAllUserAndRole();
UserMapper.xml
<resultMap id="userRoleMap" type="com.dxh.pojo.User">
<id property="id" column="user_id"></id>
<result property="username" column="username"></result>
<collection property="roleList" ofType="com.dxh.pojo.Role">
<result property="id" column="role_id"></result>
<result property="username" column="username"></result>
</collection>
</resultMap>
<select id="findAllUserAndRole" resultMap="userRoleMap">
SELECT
*
FROM
USER u
LEFT JOIN user_role ur ON u.id = ur.user_id
LEFT JOIN role r ON r.id = ur.role_id
</select>
很简单,和一对多一样。但是有一点要注意:
所以我们这里使用userid和roleid
....
<id property="id" column="user_id"></id>
....
<result property="id" column="role_id"></result>
测试一下:
@Test
public void test5() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allUser = mapper.findAllUserAndRole();
for (User user : allUser) {
System.out.println(user);
}
}
User{id=1, username='lucy', roleList=[Role{id=2, roleName='CFO'}]}
User{id=2, username='李四', roleList=[Role{id=2, roleName='CFO'}, Role{id=3, roleName='COO'}]}
User{id=3, username='zhaowu', roleList=[Role{id=1, roleName='CEO'}]}
结果正确!
注解方式:
我们在使用xml方式的时候会使用到很多标签,那么换成注解该如何使用呢?
xml | 注解 |
---|---|
@Results | |
@Result | |
@One | |
@Many |
以上,不同的标签对应不同的注解
4. 注解方式 一对一
OrderMapper.java:
package com.dxh.dao;
import com.dxh.pojo.Order;
import com.dxh.pojo.User;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface OrderMapper {
@Results({
@Result(property = "id",column = "id"),
@Result(property = "orderTime",column = "orderTime"),
@Result(property = "total",column = "total"),
@Result(property = "user",column = "uid" ,javaType = User.class,
one = @One(select = "com.dxh.dao.UserMapper.findById")
)
})
@Select("select * from orders")
public List<Order> findOrderAndUserAnnotation();
}
UserMapper.java:
//根据id查询用户 注解使用
@Select("select * from user where id=#{id}")
public User findById(Integer id);
我们刚才图中说了,不同的标签对应不同的注解。这里很好理解,那么为什么只写了@Select("select * from orders")
以及@Result(property = "user",column = "uid"
为什么这个column 写了uid呢?
我们来分析一下:
//第一步通过select标记查询出Order的所有字段:id、orderTime、total、uid
//id、orderTime、total很好理解
@Result(property = "user",column = "uid" ,javaType = User.class, one = @One(select = "com.dxh.dao.UserMapper.findById") )
//这里表示的是把 uid作为参数,传入到statementId=com.dxh.dao.UserMapper.findById 这个的查询语句中。
//所以@One(select = "这里传入将要查询的sql的statementId"), statementId=namespace.方法名组成。
先执行select * from orders
再执行select * from user where id=#{id}
,而#{id}的值就是 "uid"的值、
我们来测试一下结果:
@Test
public void test6() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
List<Order> orderAndUserAnnotation = mapper.findOrderAndUserAnnotation();
for (Order order : orderAndUserAnnotation) {
System.out.println(order);
}
}
Order{id=1, orderTime='2020-11-09', total=100.0, user=User{id=1, username='lucy'}}
Order{id=2, orderTime='2020-11-09', total=200.0, user=User{id=1, username='lucy'}}
Order{id=3, orderTime='2020-11-09', total=300.0, user=User{id=2, username='李四'}}
5. 注解方式 一对多
我们现在再来通过注解的方式来进行一对多查询:
orders
表中包含了uid也就是用户id(user.id)按照一对一的思路分析我们可以得到两条sql:
select * from user
select * from orders where uid=#{userId}
//先查询出用户,再根据用户的id进行查询订单
UserMapper.java
//查询出所有用户和其订单信息 注解使用
@Results({
@Result(property ="id",column = "id"),
@Result(property ="username",column = "username"),
@Result(property ="orderList",column = "id", javaType = List.class ,many = @Many(select ="com.dxh.dao.OrderMapper.findOrdersByUesrId" ))
})
@Select("select * from user")
public List<User> findAllUserAnnotation();
OrderMapper.java
@Select("select * from orders where uid = #{uid}")
public List<Order> findOrdersByUesrId(Integer uid);
大致都和一对一一样的,因为一对多 order是一个list,因此javaType = List.class
。 同时我们使用了many = @Many
测试一下:
@Test
public void test7() throws IOException {
InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream);
SqlSession sqlSession = build.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> allUserAnnotation = mapper.findAllUserAnnotation();
for (User user : allUserAnnotation) {
System.out.println(user);
}
}
User{id=1, username='lucy',orderList=[Order{id=1, orderTime='2020-11-09', total=100.0}, Order{id=2, orderTime='2020-11-09', total=200.0, }]}
User{id=2, username='李四', orderList=[Order{id=3, orderTime='2020-11-09', total=300.0}]}
User{id=3, username='zhaowu', orderList=[]}
结果正确!
6. 注解方式 多对多
同理,我们可以分析出两条sql
SELECT * from user
select * from user_role ur LEFT JOIN role r on ur.role_id=r.id where ur.user_id=#{userId}
//先通过第一条sql得到用户id,再通过用户id得到角色信息
UserMapper.java:
//查询出所有用户,以及他们的角色
@Select("SELECT * from user ")
@Results({
@Result(property ="id",column = "id"),
@Result(property ="username",column = "username"),
@Result(property = "roleList",column = "id" ,javaType = List.class,many = @Many(select = "com.dxh.dao.RoleMapper.findRoleById"))
})
public List<User> findAllUserAndRoleAnnotation();
新建RoleMapper.java
package com.dxh.dao;
import com.dxh.pojo.Role;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface RoleMapper {
@Select("select * from user_role ur , role r where ur.role_id=r.id and ur.user_id=#{userId}")
public List<Role> findRoleById(Integer userId);
}
结果:
User{id=1, username='lucy', roleList=[Role{id=2, roleName='CFO'}, Role{id=2, roleName='CFO'}], orderList=null}
User{id=2, username='李四', roleList=[Role{id=2, roleName='CFO'}, Role{id=3, roleName='COO'}], orderList=null}
User{id=3, username='zhaowu', roleList=[Role{id=1, roleName='CEO'}], orderList=null}
正确!
本文来自博客园,作者:邓晓晖,转载请注明原文链接:https://www.cnblogs.com/isdxh/p/13956234.html