zoukankan      html  css  js  c++  java
  • Mybatis复杂映射


    XML方式:

    1. 一对一

    假如我有一个需求,两张表,用户表和订单表。从订单的角度出发,一个订单只能有一个用户
    image-20201109221253438

    user.id和orders.id关联。

    正确的SQL应该这样写
    SELECT * FROM USER u , orders o WHERE u.id=o.uid
    image-20201109221530198

    此时的结果既有订单信息,又有用户信息。我们把结果不论封装到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>

      image-20201109223957187
      我们可以在数据库的返回结果中看到,因为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. 一对多

    假设我们有一个需求,同样是两张表userorders从用户的角度出发,一个用户可以拥有多个订单这也就是一对多关系,我们要查询出所有用户的信息,以及每个用户的订单信息。
    image-20201109221253438

    正确的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. 多对多

    一个用户有多个角色,一个角色也可以被多个用户使用。这个结构是这样的:
    image-20201109231505275

    我们有个需求,查询出用户,并查询出该用户所拥有的角色

    对应的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
    

    结果:
    image-20201109231959380

    多对多其实就是两个一对多,我们在编写代码时都是差不多的。

    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>
    

    很简单,和一对多一样。但是有一点要注意:
    image-20201109233646895

    所以我们这里使用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'}]}
    

    结果正确!

    注解方式:

    image-20201109235347337

    我们在使用xml方式的时候会使用到很多标签,那么换成注解该如何使用呢?

    xml 注解
    @Results
    @Result
    @One
    @Many

    以上,不同的标签对应不同的注解

    4. 注解方式 一对一

    image-20201109221253438

    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.方法名组成。
    

    image-20201110003116367

    先执行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. 注解方式 一对多

    image-20201109221253438

    我们现在再来通过注解的方式来进行一对多查询:

    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. 注解方式 多对多

    image-20201109231505275

    同理,我们可以分析出两条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}
    

    正确!

  • 相关阅读:
    Android程序对不同手机屏幕分辨率自适应的方法
    用户管理和身份验证
    vue----scoped独立样式作用域
    vue----component动态组件
    css----行内元素&&块状元素
    html----rem结合vw布局
    js----jsonp原理
    js----白屏事件&&dom ready时间
    js----var a=b=2解析
    js----常见的表示false的有哪些
  • 原文地址:https://www.cnblogs.com/isdxh/p/13956234.html
Copyright © 2011-2022 走看看