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,total=200.0,username='lucy'}}
Order{id=3,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.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">
我们来测试一下:
@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,user=null},Order{id=2,user=null}]}
User{id=2,username='李四',orderList=[Order{id=3,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,roleList=[Role{id=2,roleName='CFO'}]}
User{id=2,roleName='CFO'},Role{id=3,roleName='COO'}]}
User{id=3,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",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,username='李四'}}
5. 注解方式 一对多
我们现在再来通过注解的方式来进行一对多查询:
orders
表中包含了uid也就是用户id(user.id)按照一对一的思路分析我们可以得到两条sql:
select * from user
select * from orders where uid=#{userId}
//先查询出用户,再根据用户的id进行查询订单
UserMapper.java
//查询出所有用户和其订单信息 注解使用
@Results({
@Result(property ="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,total=100.0},}]}
User{id=2,total=300.0}]}
User{id=3,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",@Result(property = "roleList",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,Role{id=2,roleName='CFO'}],orderList=null}
User{id=2,roleName='COO'}],orderList=null}
User{id=3,roleName='CEO'}],orderList=null}
正确!
原文链接:https://www.f2er.com/mybatis/991596.html