精华内容
下载资源
问答
  • 其实一对一和一对多映射,在前面的配置中已经接触到,我没在日志里直接说明,是因为想要在之后写一篇总结日志(就是本篇),总结这些高级映射的配置。例如一对一查询在关联的嵌套结果集查询中就涉及到,一对多查询则...

    多表之间的数据交互

    其实一对一和一对多映射,在前面的配置中已经接触到,我没在日志里直接说明,是因为想要在之后写一篇总结日志(就是本篇),总结这些高级映射的配置。例如一对一查询在关联的嵌套结果集查询中就涉及到,一对多查询则在这个基础上再加上一个或多个嵌套结果集,它们可以是一个实体类,或者是一个集合。多对多查询稍微有点复杂,举个例子来说,一个商城管理系统中,一名顾客在一个购物清单中可以有多件商品,而一件商品可以被多名顾客选购,它们之间的关系是多对对。假设现在有这么一个需求,查询数据表库中,所有的顾客信息,包括它们的购物清单,以及清单里面的商品信息,怎么做?下面会说。

    无论是一对一、一对多还是多对多查询,都涉及到不同表之间的数据交互,因为它们之间需要主外键关系来关联,例如顾客表和购物清单表都有顾客id属性,根据这个属性来查询不同顾客对应的购物清单,有了主外键关系后,就可以进行高级映射了。

     

    事例模型

    为了展示三种映射示例,首先建立一个商场管理系统模型,里面有三张数据表,分别是顾客表user,购物车(商品清单)表shoppingcart和商品表products。顾客和商品清单之间是一对多的关系,因为一名顾客可以多次进商场购物,每一次购物生成一个购物清单(购物车),而每一张购物清单只属于一名顾客,所以顾客表和购物车表之间是一对多的关系。   还有商品表product,因为一张购物清单中可以有多件商品,所以商品表和购物车表为一对多的关系。因为一名顾客可以购买多件商品,一件商品也可以属于多名顾客,所以顾客和商品又构成多对多关系。我们在测试时,可以建立基本的三张表,:顾客表、购物车表和商品表(当然最好多加几张表,例如商品评价表),它们之间的查询可以组合出一对一、一对多以及多对多的关系,理清各张表的关系后,就可以进行测试了。

     

    一对一嵌套结果集查询

    从上面的事例模型中可以看到,含一对一关系的两张表有,购物车表和用户表,要注意其中的顺序不要弄乱,购物车和顾客是一对一关系,但反过来不是,顾客和购物车是一对多的关系。在查询需求中,这种多表之间一对一查询的场景,典型的有:一对一嵌套结果集查询。举个例子,假如我们要查询购物车表中,某一张购物清单信息,以及对应的该名顾客的个人信息。有两种配置方式,或是说两种方法实现:

    resultType结合查询包装类

    实现上面的一对一嵌套结果集查询,如果使用resultType来配置SQL映射的话,因为涉及到两张表的交互,且最后只能映射到一个实体类中,所以需要新建一个查询包装类,来包括其中含有的两张表的结果集字段对应的属性(这句话表述的不好- -、)。也就是说,新创建一个查询包装类,里面既含有购物车表中的字段对应的属性,也含有用户表中字段对应的属性,这样才能接收结果集中包含的两个表里的数据。来看看这个查询包装类:

    // 购物车表一对多查询包装类
    public class ShoppingCartInstance extends ShoppingCart implements Serializable {	
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	private String username; //顾客姓名
    	private String gender; //性别
    	private String province; //省会
    	private String city; //城市
    
    	public ShoppingCartInstance() {
    		
    	}
    	
    	public ShoppingCartInstance(int cartId, int userId, int productId, 
    			String productName, int number, 
    			double price, User user, String username, String gender, String province, 
    			String city) {
    		super(cartId, userId, productId, productName, number, price);
    		this.username = username;
    		this.gender = gender;
    		this.province = province;
    		this.city = city;
    	}
        // 省略get()和set()方法
    }

    我们的查询包装类采用继承的方式得到购物车实体类的所有属性,当然你也可以重新一个一个自己定义,这样来舍去一些不需要的属性。接着在查询包装类中追加顾客表中的属性,对应返回结果集中顾客数据表的字段。

          数据包装类准备好后,接下来可以写我们的SQL语句和映射配置了:

    <!-- 一对一查询:resultType实现 -->
    	<select id="queryShoppingCartInstance1" parameterType="int" resultType="ShoppingCartInstance">
    		SELECT
    			S.cartId, S.productName, S.userId, S.price, S.number,
    			U.id, U.username, U.gender, U.province, U.city
    		FROM ShoppingCart S left outer join user U on S.userId = U.id 
    		WHERE S.cartId = #{id}
    	</select>

    SQL语句根据id查询出购物清单,并根据外键,顾客id关联另一张数据表user顾客表。

    	public void TestAssociationQuery() throws IOException {
    		SqlSession sqlSession = dataConn.getSqlSession();
    		List<ShoppingCartInstance> resultList = sqlSession.selectList("queryShoppingCartInstance1", 2);
    		StringBuffer result = new StringBuffer();
    		double totalAmount;
    		
    		System.out.println("顾客姓名: " + resultList.get(0).getUsername());
    		System.out.println("性别: " + resultList.get(0).getGender());
    		System.out.println("商品清单:" + "\r\n");
    		
    		for(int i=0; i<resultList.size(); i++) {
    			ShoppingCartInstance shoppingCartInstance = resultList.get(i);
    			result.append("商品名:" + shoppingCartInstance.getProductName() + "\r\n");
    			result.append("商品数量:" + shoppingCartInstance.getNumber() + "\r\n");
    			totalAmount = (shoppingCartInstance.getPrice()*shoppingCartInstance.getNumber());
    			result.append("商品总价:" + String.format("%.2f", totalAmount) + "\r\n");
    			
    			System.out.println(result.toString());
    			result.setLength(0);
    		}
    		
    		sqlSession.close();
    	}

    最后写个简单的测试用例,查询购物车id为2的商品清单信息,以及对应的顾客信息。

     

    resultMap结合association标签

    使用resultMap配置的话,灵活性就增强了许多,首先resultMap允许我们配置返回结果集中字段名和Java包装类中属性名的一一映射关系。且resultMap中提供的如association标签和collection标签,功能强大,可以配置多表之间的交互。还是上面的例子采用resultMap配置的话,在查询包装类中,我们可以直接追加一个User类的实例:

    public class ShoppingCartInstance extends ShoppingCart implements Serializable {	
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    //	private String username; //顾客姓名
    //	private String gender; //性别
    //	private String province; //省会
    //	private String city; //城市
    	private User user; //对应用户
    	private Product products;
    
    	public ShoppingCartInstance() {
    		
    	}
    	
    	public ShoppingCartInstance(int cartId, int userId, int productId, 
    			String productName, int number, 
    			double price, User user) {
    		super(cartId, userId, productId, productName, number, price);
    //		this.username = username;
    //		this.gender = gender;
    //		this.province = province;
    //		this.city = city;
    		this.user = user;
    	}
        // 省略get()和set()方法
    }

    这个User类实例就是用来接收返回结果集中的顾客信息。接下来就配置它们的映射关系:

    <resultMap type="shoppingCartInstance" id="shoppingCartResult">
    		<id property="id" column="shoppingCart_id"/>
    		<result property="cartId" column="cart_id"/>
    		<result property="productName" column="product_name"/>
    		<result property="price" column="product_price"/>
    		<result property="number" column="product_number"/>
    		<result property="productId" column="product_id"/>
    		<association property="user" column="cartUser_id" javaType="com.mybatis.po.User" 
    		resultMap="userResult"/>
    	</resultMap>
    	
    	<resultMap type="com.mybatis.po.User" id="userResult">
    		<id property="id" column="user_id"/>
    		<!-- 配置User类中的映射关系 -->
    		<result property="username" column="user_name"/>
    		<result property="gender" column="user_gender"/>
    		<result property="province" column="user_province"/>
    		<result property="city" column="user_city"/>
    	</resultMap>

    在查询包装类的映射关系配置resultMap中,type指明接收的实体类是shoppingCartInstance,下面除了配置各个数据库字段和实体类属性的映射外,还用assocaition标签配置关联的嵌套结果集,也就是查询包装类中的User类实例,并且指明User类的映射关系resultMap是引用外部的userResult(也就是下面那个)。

          配置完resultMap,那SQL语句就很简单,把resultType修改为resultMap就可以了:

    <!-- 一对多查询SQL语句 -->
    	<select id="queryShoppingCartInstance2" parameterType="int" resultMap="shoppingCartResult">
    		SELECT
    			S.cartId	as cart_id,
    			S.productName	as product_name,
    			S.userId	as cartUser_id,
    			S.price	as product_price,
    			S.number	as product_number,
    			U.id	as user_id,
    			U.username	as user_name,
    			U.gender	as user_gender,
    			U.province	as user_province,
    			U.city	as user_city
    		FROM ShoppingCart S left outer join user U on S.userId = U.id 
    		WHERE S.cartId = #{id}
    	</select>

    最后是测试用例:

    ​
    	public void TestAssociationQuery() throws IOException {
    		SqlSession sqlSession = dataConn.getSqlSession();
    		List<ShoppingCartInstance> resultList = sqlSession.selectList("queryShoppingCartInstance2", 2);
    		StringBuffer result = new StringBuffer();
    		double totalAmount;
    		
    		System.out.println("顾客姓名: " + resultList.get(0).getUser().getUsername());
    		System.out.println("性别: " + resultList.get(0).getUser().getGender());
    		System.out.println("商品清单:" + "\r\n");
    		
    		for(int i=0; i<resultList.size(); i++) {
    			ShoppingCartInstance shoppingCartInstance = resultList.get(i);
    			result.append("商品名:" + shoppingCartInstance.getProductName() + "\r\n");
    			result.append("商品数量:" + shoppingCartInstance.getNumber() + "\r\n");
    			totalAmount = (shoppingCartInstance.getPrice()*shoppingCartInstance.getNumber());
    			result.append("商品总价:" + String.format("%.2f", totalAmount) + "\r\n");
    			
    			System.out.println(result.toString());
    			result.setLength(0);
    		}
    		
    		sqlSession.close();
    	}
    
    ​

     

    一对多查询

    一对多查询,假如我们在上面例子的基础上,加上一个,查询出购物清单中每一件商品的一些商品信息,如顾客对件商品的评价,怎么做?

    包装类和SQL映射配置

    首先看查询包装类,既然是在上一个例子的基础上,增加查询顾客对商品的评价信息,那么只需要在原有的查询包装类中,加上一个结果集属性即可,因为一件商品可以被多名顾客做评价,所以商品的评价属性我们用一个集合List来表示:

    // 一对多查询包装类
    public class ShoppingCartInstance extends ShoppingCart implements Serializable {	
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	private User user; //对应用户
    	private List<ProductAppraise> productAppraise; //商品评价集合
    
    	public ShoppingCartInstance() {
    		
    	}
    	
    	public ShoppingCartInstance(int cartId, int userId, int productId, 
    			String productName, int number, 
    			double price, User user, List<ProductAppraise> productAppraise) {
    		super(cartId, userId, productId, productName, number, price);
    		this.user = user;
    		this.productAppraise = productAppraise;
    	}   
        // 省略get()和set()方法
    }

    查询包装类定义好后,接下来到SQL语句和映射配置。因为有嵌套结果集和结合的缘故,很明显我们要用resultMap来配置映射关系:

    <!-- 一对多映射配置 -->
    	<resultMap type="shoppingCartInstance" id="multiShoppingCartResult" 
    	extends="shoppingCartResult">
    		<collection property="productAppraise" ofType="ProductAppraise">
    			<!-- 主键 -->
    			<id column="id" property="id"/>
    			<result property="productId" column="productAppraise_id"/>
    			<result property="productScore" column="product_score"/>
    			<result property="userId" column="user_id"/>
    		</collection>
    	</resultMap>

    因为我们的需求是在上面的查询基础上,增加查询商品的评价,所以映射配置我们只需继承上面的resultMap,然后增加一个嵌套集合配置,使用collection标签即可。

          配置还没完,还有最重要的SQL语句:

    <!-- 一对多查询SQL语句 -->
    	<select id="queryShoppingCartInstance2" parameterType="int" resultMap="shoppingCartResult">
    		SELECT
    			S.cartId	as cart_id,
    			S.productName	as product_name,
    			S.userId	as cartUser_id,
    			S.price	as product_price,
    			S.number	as product_number,
    			U.id	as user_id,
    			U.username	as user_name,
    			U.gender	as user_gender,
    			U.province	as user_province,
    			U.city	as user_city
    		FROM ShoppingCart S left outer join user U on S.userId = U.id 
    		WHERE S.cartId = #{id}
    	</select>

    SQL语句中,查询三张表中的数据,根据外键顾客id来关联顾客和对应的购物车,根据商品号productId来关联购物车中的商品和商品评价信息。

    测试用例

    最后是一对多查询的测试用例:

    // 一对多查询测试用例
    public void TestAssociationQuery() throws IOException {
    		SqlSession sqlSession = dataConn.getSqlSession();
    		List<ShoppingCartInstance> resultList = sqlSession.selectList("queryShoppingCartInstance4");
    		StringBuffer result = new StringBuffer();
    		double totalAmount;
    		
    		System.out.println("顾客姓名: " + resultList.get(0).getUser().getUsername());
    		System.out.println("性别: " + resultList.get(0).getUser().getGender());
    		System.out.println("商品清单:" + "\r\n");
    		
    		for(int i=0; i<resultList.size(); i++) {
    			ShoppingCartInstance shoppingCartInstance = resultList.get(i);
    			result.append("商品名:" + shoppingCartInstance.getProductName() + "\r\n");
    			result.append("商品数量:" + shoppingCartInstance.getNumber() + "\r\n");
    			totalAmount = (shoppingCartInstance.getPrice()*shoppingCartInstance.getNumber());
    			result.append("商品总价:" + String.format("%.2f", totalAmount) + "\r\n");
    			
    			List<ProductAppraise> appraiseList = shoppingCartInstance.getProductAppraise();
    			for(int j=0; j<appraiseList.size(); j++) {
    				ProductAppraise productAppraise = appraiseList.get(j);
    				System.out.println("商品评分:" + productAppraise.getProductScore());
    			}
    			
    			System.out.println(result.toString());
    			result.setLength(0);
    		}
    		
    		sqlSession.close();
    	}

    测试用例中,每一次从结果集中拿到一个shoppingCartInstance对象后,第18行,都要从对象中再获取商品评价的集合,然后从商品评价集合中在获取商品评分,这里要注意一下。

    测试结果:

     

    多对多查询

    还有更复杂的需求,就是要用到多对多查询,由前面事例模型可知,具有多对多关系的是顾客和商品之间,因为一名顾客可以购买多种商品,同一种商品也可以被多名顾客购买,这就形成了很明显的多对多关系。假如现在有这么一个需求,查询所有的顾客,以及这些顾客对应的商品清单,还有清单里所有商品的商品id信息。怎么做?还是先从查询包装类开始:

    // 多对多查询包装类
    public class ShoppingCartInstance extends ShoppingCart implements Serializable {	
    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;
    	private User user; //对应用户
    	private Product products;
    
    	public ShoppingCartInstance() {
    		
    	}
    	
    	public ShoppingCartInstance(int cartId, int userId, int productId, 
    			String productName, int number, 
    			double price, User user, Product products) {
    		super(cartId, userId, productId, productName, number, price);
    		this.user = user;
    		this.products = products;
    	}
        // 省略get()和set()方法
    }

    为了简化示例,我们只查询商品信息中的商品id信息,再查询包装类中,我们在上面的示例基础上,移除商品评价集合,追加一个商品结果集实体类实例对象products,用来接收商品信息。

    多个association标签

    接下来到SQL映射配置:

        <resultMap type="shoppingCartInstance" id="shoppingCartResult">
    		<id property="id" column="shoppingCart_id"/>
    		<result property="cartId" column="cart_id"/>
    		<result property="productName" column="product_name"/>
    		<result property="price" column="product_price"/>
    		<result property="number" column="product_number"/>
    		<result property="productId" column="product_id"/>
    		<association property="user" column="cartUser_id" javaType="com.mybatis.po.User" 
    		resultMap="userResult"/>
    		<association property="products" column="cartUser_id" javaType="com.mybatis.po.Product">
    			<result property="productId" column="products_id"/>
    		</association>
    	</resultMap>
    	
    	<resultMap type="com.mybatis.po.User" id="userResult">
    		<id property="id" column="user_id"/>
    		<!-- 配置User类中的映射关系 -->
    		<result property="username" column="user_name"/>
    		<result property="gender" column="user_gender"/>
    		<result property="province" column="user_province"/>
    		<result property="city" column="user_city"/>
    	</resultMap>

    在多对多映射配置中,注意用了两个association标签,这是可以的,因为我们的查询包装类中,嵌套了两个实体类,一个顾客类和一个商品类。两个association标签配置有一点不同就是,顾客映射关系配置使用了外部的resultMap,而商品信息映射关系配置直接在association标签内配置,两种方法都可以。SQL映射配置完后,到SQL语句:

    <!-- 多对多查询SQL示例语句 -->
    	<select id="queryShoppingCartInstance4" resultMap="shoppingCartResult">
    		SELECT
    			S.cartId	as cart_id,
    			S.productName	as product_name,
    			S.userId	as cartUser_id,
    			S.price	as product_price,
    			S.number	as product_number,
    			S.productId as product_id,
    			U.id	as user_id,
    			U.username	as user_name,
    			U.gender	as user_gender,
    			U.province	as user_province,
    			U.city	as user_city,
    			P.productId as products_id
    		FROM Products P, ShoppingCart S, user U 
    		WHERE S.userId = U.id AND S.productId = P.productId
    	</select>

    这个比较简单,注意外键的关联即可,通过顾客id关联顾客和顾客的商品清单,通过商品id关联购物清单中的商品和商品信息。最后是测试用例:

    // 多对多测试用例
    public void TestAssociationQuery() throws IOException {
    		SqlSession sqlSession = dataConn.getSqlSession();
    		List<ShoppingCartInstance> resultList = sqlSession.selectList("queryShoppingCartInstance4");
    		StringBuffer result = new StringBuffer();
    		double totalAmount;
    		
    		for(int i=0; i<resultList.size(); i++) {
    			ShoppingCartInstance shoppingCartInstance = resultList.get(i);
    			result.append("顾客姓名: " + shoppingCartInstance.getUser().getUsername() + "\r\n");
    			result.append("性别: " + shoppingCartInstance.getUser().getGender() + "\r\n");
    			result.append("商品id:" + shoppingCartInstance.getProducts().getProductId() + "\r\n");
    			result.append("商品名:" + shoppingCartInstance.getProductName() + "\r\n");
    			result.append("商品数量:" + shoppingCartInstance.getNumber() + "\r\n");
    			totalAmount = (shoppingCartInstance.getPrice()*shoppingCartInstance.getNumber());
    			result.append("商品总价:" + String.format("%.2f", totalAmount) + "\r\n");
    
    			System.out.println(result.toString());
    			result.setLength(0);
    		}
    		
    		sqlSession.close();
    	}

    也比较简洁明了,因为所有信息都在一个查询包装类中,我们可以一一拿出来:

     

    完整实现已上传GitHub:

    https://github.com/justinzengtm/SSM-Framework

    展开全文
  • mybatis的一对多映射collection

    千次阅读 2020-10-28 09:32:46
    一对多映射 方式1:按照查询嵌套处理 方式2:按照结果嵌套处理 简单映射(一对一) mybatis结果集映射ResultMap 一对多映射 我们有2个类,一个班级类ClassRoom,一个学生类Student 班级类代码如下...

    简单映射(一对一)

    一对多映射

    方式1:按照查询嵌套处理

    方式2:按照结果嵌套处理


     

    简单映射(一对一)

    mybatis结果集映射ResultMap

    一对多映射

    我们有2个类,一个班级类ClassRoom,一个学生类Student

    班级类代码如下

    package com.lingaolu.pojo;
    
    /**
     * @author 林高禄
     * @create 2020-10-26-20:17
     */
    public class ClassRoom {
        private Long id;
        private String name;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "ClassRoom{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    

     

    学生类代码如下,下面的注解是使用lombokLombok的使用步骤

    package com.lingaolu.pojo;
    
    import lombok.*;
    
    /**
     * @author 林高禄
     * @create 2020-10-26-17:43
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Student {
        private Long id;
        private String name;
        private String ageNum;
        private Long classId;
    
    }
    

     

    现在我们想查询班级的时候,把相应的本级内的学生信息也查出来,所以我们建一个班级的vo类,ClassRoomVo,继承ClassRoom,另外加属性学生的集合students

    package com.lingaolu.vo;
    
    import com.lingaolu.pojo.ClassRoom;
    import com.lingaolu.pojo.Student;
    
    import java.util.List;
    
    /**
     * @author 林高禄
     * @create 2020-10-27-19:32
     */
    public class ClassRoomVo extends ClassRoom {
    
        private List<Student> students;
    
        public List<Student> getStudents() {
            return students;
        }
    
        public void setStudents(List<Student> students) {
            this.students = students;
        }
    
        @Override
        public String toString() {
            return "ClassRoomVo{" +
                    super.toString()+","+
                    "students=" + students +
                    '}';
        }
    }
    

     

    方式1:按照查询嵌套处理

    单元测试结果

    这里学生的年龄和班级id没有查出来,是因为属性名和数据库列名不一致导致的,所以查询学生的时候,在做一次映射就好了

    方式2:按照结果嵌套处理

    单元测试结果

     

     

    展开全文
  • MyBatis的一对多映射(九)

    千次阅读 2019-07-09 08:57:54
    年轻的时候,遇见了一个人,便以为余生再没有江湖,后来,才懂,她才是江湖的起源。... 可以与Hibernate的一对多进行比较性学习: Hibernate的一对多映射的单向关联和双向关联(九) 还是以常见的部门Dept ...

    年轻的时候,遇见了一个人,便以为余生再没有江湖,后来,才懂,她才是江湖的起源。

    上一章简单介绍了MyBatis的一对一映射(八),如果没有看过,请观看上一章

    一. MyBatis的一对多关联映射

    数据库中最常见的就是一对多的关联映射,业务开发中也很常见这一对多。 可以与Hibernate的一对多进行比较性学习: Hibernate的一对多映射的单向关联和双向关联(九)

    还是以常见的部门Dept 与用户 User 进行关联。 一个部门下有多个用户,但是一个用户只属于一个部门。

    部门图片。

    员工图片。

    其中,员工表里面的deptId 是关联的部门表里面的id, 看似是外键,但并没有设置外键,只是值一样而已。

    员工类 User.java

    package com.yjl.pojo;
    
    /**
     @author:yuejl
     @date: 2019年6月15日 上午11:11:02
     @Description Mybatis 使用的基本类 User
    */
    public class User {
    	/**
    	 * @param id id编号,自增
    	 * @param name 姓名
    	 * @param age 年龄
    	 * @param sex 性别
    	 * @param description 描述
    	 */
    	private Integer id;
    	private String name;
    	private Integer age;
    	private String sex;
    	private String description;
    	//引入部门的对象。
    	private Dept dept;
    	public User(){
    		
    	}
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public Integer getAge() {
    		return age;
    	}
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    	public String getSex() {
    		return sex;
    	}
    	public void setSex(String sex) {
    		this.sex = sex;
    	}
    	public String getDescription() {
    		return description;
    	}
    	public void setDescription(String description) {
    		this.description = description;
    	}
    	public Dept getDept() {
    		return dept;
    	}
    	public void setDept(Dept dept) {
    		this.dept = dept;
    	}
    	@Override
    	public String toString() {
    		return "User [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", description=" + description
    				+ "]";
    	}
    }
    
    

    部门类 Dept.java

    package com.yjl.pojo;
    
    import java.util.List;
    
    /**
     @author: yuejl
     @date: 2019年7月8日 上午10:15:08
     @Description 数据库中一的一方 部门实体
    */
    public class Dept {
    	/**
    	 * @param id 部门的编号
    	 * @param name 部门的名称
    	 * @param description 部门的描述
    	 */
    	private Integer id;
    	private String name;
    	private String description;
    	// 集合,用的是 List, 而不是Set
    	private List<User> allUser;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getDescription() {
    		return description;
    	}
    	public void setDescription(String description) {
    		this.description = description;
    	}
    	public List<User> getAllUser() {
    		return allUser;
    	}
    	public void setAllUser(List<User> allUser) {
    		this.allUser = allUser;
    	}
    	@Override
    	public String toString() {
    		return "Dept [id=" + id + ", name=" + name + ", description=" + description + "]";
    	}
    }
    
    

    二. 员工到部门的一对一 关联查询

    可以先复习一下,员工到部门的一对一查询, 一个员工只属于一个部门。 传入的是员工的编号,查询出来的有部门的相应信息。 一对一采用的是嵌套查询的方式。

    二.一 UserMapper.java 的接口

    UserMapper.java 中的接口:

    public User getDeptByIdWithSelect(int id);
    

    二.二 DeptMapper.java 的接口

    DeptMapper.java 中的接口:

    public Dept getById(int id);
    

    二.三 UserMapper.xml 的sql语句

    <resultMap type="user" id="userDeptResultMapWithSelect">
    		<!-- 普通的员工属性查询 -->
    		<id property="id" column="id"/>
    		<result property="name" column="name"/>
    		<result property="sex" column="sex"/>
    		<result property="age" column="age"/>
    		<result property="description" column="description"/>
    		<!-- 一对一的部门查询 ,传入参数是 deptId-->
    		<association property="dept" javaType="dept" 
    		column="deptId" select="com.yjl.mapper.DeptMapper.getById"></association>
    	</resultMap>
    	
    	<select id="getDeptByIdWithSelect" parameterType="int" resultMap="userDeptResultMapWithSelect">
    		select * from user u where u.id=#{id}
    	</select>
    

    二.四 DeptMapper.xml 的sql语句

    <resultMap type="dept" id="deptResultMap">
    		<id property="id" column="id"/>
    		<result property="name" column="name"/>
    		<result property="description" column="description"/>
    	</resultMap>
    
    <!-- 嵌套查询 -->
    	<select id="getById" parameterType="int" resultMap="deptResultMap">
    		select * from dept where id=#{id}
    	</select>
    

    二.五 测试方法

    @Test
    	public void getDeptByIdWithSelectTest(){
    		SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    		UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
    		User user=userMapper.getDeptByIdWithSelect(1);
    		System.out.println(user);
    		Dept dept=user.getDept();
    		System.out.println(dept);
    	}
    

    有图片。

    三. 部门到员工的一对多关联映射

    一对多关联映射,也有两种方式, 一种是一对多的嵌套结果, 一种是一对多的嵌套Select查询, 相比较一对一来说, 一对一查询出来的结果最多只有一个值,而一对多却可以查询出一个集合。 另外,一对一 用的是 javaType, 而一对多用的是 ofType. 这一点非常重要。

    三.一 一对多的嵌套结果方式

    DeptMapper.java 中接口:

    public Dept getAllInfoByIdWithResult(int id);
    

    DeptMapper.xml 中的sql语句:

    <resultMap type="dept" id="deptCollectionResultMapWithResult">
    		<id property="id" column="id"/>
    		<result property="name" column="name"/>
    		<result property="description" column="description"/>
    		<!-- 用的是ofType的类型。 -->
    		<collection property="allUser" ofType="user">
    			<id property="id" column="id"/>
    			<result property="name" column="name"/>
    			<result property="sex" column="sex"/>
    			<result property="age" column="age"/>
    			<result property="description" column="description"/>
    		</collection>
    	</resultMap>
    <select id="getAllInfoByIdWithResult" parameterType="int" resultMap="deptCollectionResultMapWithResult">
    		select * from dept d,user u where d.id=u.deptId and d.id=#{id}
    	</select>
    

    测试方法:

    @Test
    	public void getAllInfoByIdWithResultTest(){
    		SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    		DeptMapper deptMapper=sqlSession.getMapper(DeptMapper.class);
    		Dept dept=deptMapper.getAllInfoByIdWithResult(1);
    		System.out.println(dept);
    		List<User> allUser=dept.getAllUser();
    		allUser.forEach(n ->System.out.println(n));
    	}
    

    有图片。

    三.二 一对多的嵌套Select 查询

    DeptMapper.java 中的接口:

    public Dept getAllInfoByIdWithSelect(int id);
    

    UserMapper.java 中的接口:

    传入参数,用 @Param 注解的形式。

    public List<User> findUserByDeptId(@Param(value="deptId") int deptId);
    

    DeptMapper.xml 中的sql语句:

    <resultMap type="dept" id="deptCollectionResultMapWithSelect">
    		<id property="id" column="id"/>
    		<result property="name" column="name"/>
    		<result property="description" column="description"/>
    		<!-- 用的是ofType的类型。 -->
    		<collection property="allUser" ofType="user" column="id"
    		select="com.yjl.mapper.UserMapper.findUserByDeptId"></collection>
    </resultMap>
    
    <select id="getAllInfoByIdWithSelect" parameterType="int" resultMap="deptCollectionResultMapWithSelect">
    		select * from dept where id=#{id}
    </select>
    

    UserMapper.xml 中的sql语句:

    <resultMap type="user" id="userResultMap">
    		<id property="id" column="id"/>
    		<result property="name" column="name"/>
    		<result property="sex" column="sex"/>
    		<result property="age" column="age"/>
    		<result property="description" column="description"/>
    </resultMap>
    <select id="findUserByDeptId" parameterType="int" resultMap="userResultMap">
    		select * from user u where u.deptId=#{deptId}
    </select>
    

    测试方法:

    @Test
    	public void getAllInfoByIdWithSelectTest(){
    		SqlSession sqlSession=SqlSessionFactoryUtils.getSession();
    		DeptMapper deptMapper=sqlSession.getMapper(DeptMapper.class);
    		Dept dept=deptMapper.getAllInfoByIdWithSelect(1);
    		System.out.println(dept);
    		List<User> allUser=dept.getAllUser();
    		allUser.forEach(n ->System.out.println(n));
    	}
    

    有图片

    谢谢!!!

    展开全文
  • resultMap元素(结果映射)【*****】级联关系【*****】4.1 一对一关联查询 (association) - 用javaType来指定对象类型4.2 一对多、多对多关联查询 (collection) - 用ofType来制定对象类型 映射器  

    映射器

      MyBatis 的真正强大在于它的语句映射。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
    MyBatis文档地址:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

    XML映射器

    元素名称描 述备 注
    select映射查询语句,最常用、最复杂的元素之一可以自定义参数,返回结果集等
    insert映射插入语句执行后返回一个整数,代表插入的行数
    update映射更新语句执行后返回一个整数,代表更新的行数
    delete映射删除语句执行后返回一个整数,代表删除的行数
    sql定义一部分SQL,在多个位置被引用–被其它语句引用的可重用的语句块例如,一张表列名,一次定义,可1以在多个SQL语句中使用
    resultMap用来描述从数据库结果集中来加载对象,是最复杂也是最强大的元素提供映射规则
    cache-ref引用其它命名空间的缓存配置提供其它命名空间下的缓存映射
    cache该命名空间的缓存配置分为一级缓存和二级缓存

    1. select元素【**】

      MyBatis的查询语句

    属性名称描 述
    id它和Mapper的命名空间组合起来使用,是唯一标识符,供MyBatis调用
    parameterType表示传入SQL语句的参数类型的全限定名或别名。是个可选属性,MyBatis能推断出具体传入语句的参数。
    resultTypeSQL语句执行后返回的类型(全限定名或者别名)。如果是集合类型,返回的是集合元素的类型。返回时可以使用resultType或resultMap之一
    resultMap它是映射集的引用,与< resultMap>元素一起使用。返回时可以使用resultType或resultMap之一
    flushCache它的作用是在调用SQL语句后,是否要求MyBatis清空之前查询本地缓存和二级缓存。默认值为false。如果设置为true,则任何时候只要SQL语句被调用,都将清空本地缓存和二级缓存
    useCache启动二级缓存的开关。默认值为true,表示将查询结果存入二级缓存中
    timeout用于设置超时参数,单位是秒。超时将抛出异常。
    fetchSize获取记录的总条数设定
    statementType告诉MyBatis使用哪个JDBC的Statement工作,取值为STATEMENT(Statement)、PREPARED(PreparedStatement)、CALLABLE(CallableStatement)
    resultSetType这是针对JDBC的ResultSet接口而言,其值可设置为FORWARD_ONLY(只允许向前访问)、SCROLL_SENSITIVE(双向滚动,但不及时更新)、SCROLL_INSENSITIVE(双向滚动,及时更新)

    2. insert元素

      insert元素用于映射插入语句,update元素用于映射更新语句,delete元素用于映射删除语句。执行insert都将返回一个整数表示其影响的行数。

    2.1 insert元素特有的属性:

    insert的特有属性描述
    keyProperty该属性的作用是将插入或更新操作时的返回值赋值给PO类的某个属性,通常会设置为主键对应的属性。如果是联合主键,可以在多个值之间用逗号隔开。
    keyColumn该属性用于设置第几列是主键,当主键列不是表中的第一列时需要设置。如果是联合主键时,可以在多个值之间用逗号隔开。
    useGeneratedKeys该属性将使MyBatis使用JDBC的getGeneratedKeys()方法获取由数据库内部生产的主键,如MySQL、SQL Server等自动递增的字段,其默认值为false

    2.2 insert元素主键回填(设置为自动递增的主键)

    MySQL、SQL Server等数据库的表格可以采用自动递增的字段作为主键。有时可能需要使用这个刚刚产生的主键,用以关联其他业务。

    <!-- 添加一个用户,成功后将主键值回填给uid(javabean类的属性)-->
    	<insert id="addUser" parameterType="com.po.MyUser" 
    	keyProperty="uid" useGeneratedKeys="true">
    		insert into user (uname,usex) values(#{uname},#{usex})
    	</insert>
    

    2.3 自定义主键(实现主键自动递增)

    如果实际工程中使用的数据库不支持主键自动递增(如Oracle),或者取消了主键自动递增的规则时,可以使用MyBatis的**< selectKey >元素来自定义生成主键。**

    	<insert id="insertUser" parameterType="com.xgf.bean.User">
    		<!-- 先使用selectKey元素定义主键,然后再定义SQL语句 -->
    		<selectKey keyProperty="uid" resultType="Integer" order="BEFORE">
    		   select if(max(uid) is null, 1 , max(uid)+1) as newUid from user
    		</selectKey>
    		insert into user (uid,uname,usex) values(#{uid},#{uname},#{usex})
        </insert>
    
    

    3. update、delete元素

    和元素比较简单,它们的属性和元素、元素的属性差不多,执行后也返回一个整数,表示影响了数据库的记录行数

    	 <!-- 修改一个用户 -->
        <update id="updateUser" parameterType="com.xgf.bean.User">
    		update user set uname = #{uname},usex = #{usex} where uid = #{uid}
        </update>
        <!-- 删除一个用户 -->
        <delete id="deleteUser" parameterType="Integer"> 
    		delete from user where uid = #{uid}
        </delete>
    


    4. resultMap元素(结果映射)【*****】

      resultMap元素表示结果映射集,是MyBatis中最重要也是最强大的元素。主要用来定义映射规则、级联的更新以及定义类型转化器等。

    resultMap标签的属性:

    resultMap属性描述
    id当前命名空间中的一个唯一标识,用于标识一个结果映射。
    type类的完全限定名, 或者一个类型别名。
    autoMapping如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。

    resultMap的子元素:

    <resultMap type="" id="">
        <constructor>		<!-- 类在实例化时,用来注入结果到构造方法 -->
    		<idArg/>		<!-- ID参数,结果为ID -->
    		<arg/>			<!-- 注入到构造方法的一个普通结果 -->
        </constructor>
        <id/>				<!-- 用于表示哪个列是主键 -->
        <result/>			<!-- 注入到字段或JavaBean属性的普通结果,非主键外的 -->
        <association property=""/>		<!-- 用于一对一关联 -->
        <collection property=""/>		<!-- 用于一对多、多对多关联 -->
        <discriminator javaType="">		<!-- 使用结果值来决定使用哪个结果映射 -->
            <case value=""/>			<!-- 基于某些值的结果映射 -->
        </discriminator>
    </resultMap>
    

    基本案例写法:

    	<!-- 自定义resultMap 结果集类型 -->
    	<resultMap type="com.xgf.bean.User" id="userResultMap">
    		<!-- property对应的是javabean类中的属性-->
    		<!-- column对应的是数据库表的列名,可以来自不同的表 -->
    		<id property="uid" column="uid"/>
    		<result property="uname" column="uname"/>
    		<result property="usex" column="usex"/>
    	</resultMap>
    	
    	<!-- 使用自定义结果集类型查询所有用户 -->
    	<select id="selectAllUser" resultMap="userResultMap">
    		select uid,uname,usex from user
    	</select>
    
    

    级联关系【*****】

    4.1 一对一关联查询 (association) - 用javaType来指定对象类型

      MyBatis中,通过<resultMap>元素的子元素<association>处理这种一对一级联关系。

    属性描述
    property指定映射到实体类的对象属性(javabean对应的对象属性值) ---- 就是一对一关联的对象(定义的bean中的对象属性名)
    javaType指定映射到实体对象属性的类型(javabean对象的完全限定名/类型别名) —就是一对一关联的对象的完全限定名,或别名
    select指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询。
    	<!-- 一对一关联查询 person人和card身份证-->
    	<resultMap id="personMap" type="com.xgf.correlation.one_to_one.bean.Person" autoMapping="true">
            <!--
                <id>主键
                <result>其它属性列 
                如果设置了autoMapping="true" 自动映射,那么数据库表列名和类对象属性名一致的情况下
                ,可以不用写<result>属性,自动映射
            -->
           <id property="id" column="id"/>
           <result property="username" column="username"/>
            <!--
               封装person对象对应的card
               一对一关联 用association封装对象类型
               property就是关联对象card在的person类中的属性值,javaType就是person关联的对象完全限定名
            -->
           <association property="card" javaType="com.xgf.correlation.one_to_one.bean.Card">
               <id property="id" column="id"/>
               <result property="code" column="code"/>
           </association>
    
        </resultMap>
    
    <!--  查询结构封装成map对象  -->
        <select id="getPersonById" resultMap="personMap">
            select p.id,p.username,c.id,c.code
            from person p inner join card c on p.id_card = c.id
            where p.id = #{id}
        </select>
    
    4.2 一对多、多对多关联查询 (collection) - 用ofType来制定对象类型

      多对多关联就是两个一对多关联进行交互替换。

    一对多关联查询:

    <!--一对多关联关系 user和task表  一个user可以有多个task任务,一个task只能由一个user完成-->
       <resultMap id="userTaskMap" type="com.xgf.correlation.one_to_many.bean.User">
            <id column="id" property="id"/>
            <result property="username" column="username"/>
    
    		<!-- property就是在user中定义的task集合的属性名taskList
    			ofType就是对应这个集合的属性类task类的完全限定名	
    		 -->
            <collection property="taskList" ofType="com.xgf.correlation.one_to_many.bean.Task" >
                <id column="tid" property="id"/>
                <result column="taskName" property="taskName"/>
            </collection>
        </resultMap>
    
        <select id="getUserTaskById" resultMap="userTaskMap">
            SELECT u.id,u.username,t.id tid,t.taskName
            from users u inner join task t on u.id = t.userId
            where u.id=#{id}
        </select>
    

    多对多关联查询:

    	<!-- order订单表和product 产品表,一个订单可以有多份产品,一个产品可以有多个订单
    		创建中间表orders_product
    	 -->
     	<resultMap id="orderMap" type="com.xgf.mybatis.correlation.many_to_many.bean.Order">
            <id column="oid" property="id"/>
            <result property="description" column="description"/>
            <collection property="productList" ofType="com.xgf.mybatis.correlation.many_to_many.bean.Product">
                <id column="pid" property="id"/>
                <result property="name" column="name"/>
            </collection>
        </resultMap>
    
        <select id="getOrderById" parameterType="int" resultMap="orderMap">
               select o.id oid,o.description,p.id pid,p.name
                from orders o left outer join orders_product op on o.id = op.ordersId
                              left outer join product p on p.id = op.productId
                where o.id = #{id}
    
        </select>
    
    展开全文
  • mybatis多对一映射association详解

    千次阅读 2020-10-27 15:18:13
    简单映射一对一) 对一映射 方式1:按照查询嵌套处理 方式2:按照结果嵌套处理 简单映射一对一) mybatis结果集映射ResultMap 对一映射 我们有2个类,一个班级类ClassRoom,一个学生类...
  • 一对多的关系中, 主表的数据回对应关联表中的多条数据。 因此, 查询时就会查询出多条结果, 所以, 向类似的情况我们会使用 List 来进行存储关联表中获取到的信息。 1 数据准备 创建以下的名为 mybatis 的数据库...
  • MyBatis关联映射:一对一、一对多

    万次阅读 2017-06-20 21:00:59
    一、一对一场景:生活中每一个人都有一个身份证,这是最简单的一对一的关系。(1)用户表(2)身份证表(3)用户实体对象,...-- 一对一关系映射 --> <association column="card_id" p
  • 我们这里就利用订单和用户模型,从订单角度出发,一个订单只能给一个用户创建,所以是一对一,但是从用户角度出发,一个用户是可以创建多个订单的,所以是一对多。但是我们这里从订单角度出发,那么就可以当成一对一...
  • 分享一遍专门针对刚刚从事Java人员的MyBatis关联查询映射关系详细描述: ...(2)同理,实现一对多关系就现在实体类中添加一个你需要对应集合作为实体类的字段 实体类这里就这样了 重点是到下面的Mapper.x
  • 当我们学习heribnate的时候,也就是SSH框架的网上商城的时候,我们就学习过它对应的高级映射,一对一映射,一对多映射,多对多映射。对于SSM的Mybatis来说,肯定也是差不多的。既然开了头了,我们就也来简单说一些...
  • 【MyBatis学习09】高级映射一对多查询

    万次阅读 多人点赞 2016-06-14 07:14:12
    上一篇博文总结了一下一对一的映射,本文主要总结一下一对多映射,从上一篇文章中的映射关系图中可知,订单项和订单明细是一对多的关系,所以本文主要来查询订单表,然后关联订单明细表,这样就有一对多的问题出来...
  • Mybatis之高级映射【一对多映射

    千次阅读 2018-09-12 18:07:37
    一对多映射(两种方式) 三张表关联查询。当然resultType也能实现,需要将所查询的信息定义到一个pojo(详情见一对一映射中的resultType),这里讲的是resultMap。 需求:查询人员、部门信息并关联查询其父级部门信息。...
  • 在实际开发中我们不可能只是对单表进行操作,必然要操作多表,本文就来讲解多表操作中的一对一关联映射一对多(或多对一)关联映射,至于多对多关联映射实质上也是两个一对多(或多对一)关联映射,所以在这里我并不...
  • Mybatis resultMap实现一对多映射

    千次阅读 2019-03-20 19:16:47
    假设user和orders为一对多的关系,一个user对应多个订单 User.java package per.czt.ssm.domain; import java.util.List; import java.util.Set; public class User { private Integer id; private String ...
  • ssm 一对多映射关系

    千次阅读 2017-08-31 14:21:30
    关联关系大体分三类:一对一,一对多和多对多。 一对一  在实际项目中,几乎没有用不到一对一关系映射的,对一对一关系最好使用唯一主外键关联,即两张表使用外键关联关系,同时给外键列增加唯一约束。...
  • Hibernate关联映射一对多/多对多)

    万次阅读 2018-11-22 15:25:19
    3. Hibernate关联映射 上接Hibernate持久化类:... 目录 3. Hibernate关联映射 3.1 数据库表之间的关系 ...3.1.1 一对多关系 3.1.2 多对多关系 3.1.3 一对一关系(实际开发中使用较少) 3.2 实战Hibernate...
  • spring jpa data 查询多对一映射

    千次阅读 2016-09-27 16:05:10
    @Service public class CityServiceImpl implements CityService { @Autowired CityRepository cityRepository; public CityRepository getCityRepository() { return cityRepository; } En
  • 在网上寻了很久,大多数讲关系性的文章都是大篇幅的去将表照搬上来,本来就很生硬,此文就...在关系型数据库中,多表之间存在着三种关联关系,分别为一对一、一对多和多对多,如下图所示: 三种关系如下: 一对一...
  • 提供一对一、一对多、多对多等高级映射 2.当实体类对象与数据库字段不匹配时: 方案1:使用sql语句as 起别名的方式修改查询结果的名称 方案2:使用resultMap,完成数据库字段与实体类属性的映射。(可被多个sql...
  • 章介绍了多对一的关系,用到了,这是个复杂类型的关联。我们选择个示例来回顾下,比如:个博客有个用户,关联映射就工作于这种结果之上。首先看下,我们在本文中要用到的表结构字段: 博客 blog : id ...
  • spring-boot ,spring-data-jpa 关系映射关系,实现一对多,多对多,一对一 仅仅展示代码,不需要太多的其他无用字眼 1:多对多 @Entity public class User { @Id @GeneratedValue(strategy = GenerationType....
  • 一对多单向外键关联(XML/Annotation) 一对多双向外键关联(XML/Annotation) Many to Many 映射关系 多对多单向外键关联(XML/Annotation) 多对多双向外键关联(XML/Annotation) One to One 映射关系 作用:可通过映射...
  • 一对多关系表,如何在一个映射文件中实现对两个表的增删改查操作?
  • 前言先看看Mybatis官方介绍MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置... 可是,当我们的数据库表关系错综复杂,表与表之存在一对多、多对一、多对多
  • Mybatis中一对多映射详解

    万次阅读 2016-10-23 16:13:25
    这意味着讲师和课程之间存在一对多映射关系。 注意:在一对多关系中,数据库建表的时候外键一定是在多的那一方建立. 建表语句: drop table courses;表数据中,zs 讲师教授一个课程,而 ls 讲师教授两个课程 配置完...
  • 基本映射对一个实体进行映射,关联映射就是处理个实体之间的关系,将关联关系映射到数据库中,所谓的关联关系在对象模型中有个或个引用。
  • mybatis关系映射一对多和多对一

    万次阅读 多人点赞 2016-06-06 11:16:41
    本实例使用顾客和订单的例子做说明: 个顾客可以有个订单, 个订单只对应个顾客 二. 例子: 1. 代码结构图: 2. 建表语句: CREATE DATABASE test; USE test; CREATE TABLE person( ...
  • 高级结果映射 一、数据模型分析 1、 明确每张表存储的信息 ...二、一对映射 1、需求 查询订单信息,关联查询用户信息 2、SQL语句 主信息:orders 从信息:user SELECT orders....
  • mybatis是个持久层框架,是apache下的开源项目,前身是itbatis,是个不完全的ORM框架,mybatis提供输入和输出的映射,需要程序员自己写sql语句,mybatis重点 sql语句的灵活操作。 适合用于:需求变化频繁, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,141,719
精华内容 456,687
关键字:

一对多查询映射