• mybatis 使用resultMap实现表间关联


    AutoMapping

      auto mapping,直译过来就是自动映射,工作原理大概如下:

      假设我们有一张表,表名为person,包含id,name,age,addr这4个字段

    mysql> desc person;
    +-------+-------------+------+-----+---------+----------------+
    | Field | Type        | Null | Key | Default | Extra          |
    +-------+-------------+------+-----+---------+----------------+
    | id    | int(11)     | NO   | PRI | NULL    | auto_increment |
    | name  | varchar(30) | NO   |     | NULL    |                |
    | age   | int(2)      | NO   |     | NULL    |                |
    | addr  | varchar(30) | NO   |     | NULL    |                |
    +-------+-------------+------+-----+---------+----------------+
    

      

      同时我们会创建一个实体类Person来与这张person表进行对应,此时Person类的属性名称和person表中的字段名称一一对应,不仅是名称对应,数据类型也是一一对应的:

    package lixin.gan.pojo;
    
    public class Person {
    
    	private int id;
    	private String name;
    	private int age;
    	private String addr;
    	
    	// 省略了构造方法、setter、getter、toString
    }
    

        

      之后我们会创建PersonMapper.xml这个映射文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="lixin.gan.mapper.PersonMapper">
    	<select id="selectAll"  resultType="lixin.gan.pojo.Person">
    		select * from person
    	</select>
    </mapper>
    

      注意上面的resultType,这里的resultType已经指明了返回值的类型,于是mybatis在从结果集中取出一条数据后,会将每一行记录的字段名,对应到Person类的同名属性,将字段值赋值给Person类的同名属性。

      此时需要注意:如果从person表中查询数据,取出结果集中的字段名称,和Person类中的属性值对应不上(名称不相同),那么返回的Person类的对象对应的那个属性就会设置为null。举个例子,person表中的name字段,应该auto mapping到Person类的name属性,但如果,Person类中,没有name属性,却有一个name1属性,那么再返回结果的时候,name1属性就会初始为null。

      虽然resultType很方便,可以自动的实现映射,但是,我们往往需要进行自定义的映射,此时就可以使用resultMap了。

    使用resultMap实现单表映射

      假设实体类中Person.java的属性更改如下:

    package lixin.gan.pojo;
    
    public class Person {
    
    	private int id1;
    	private String name1;
    	private int age1;
    	private String addr1;
    	
    	// 省略了构造方法、setter、getter、toString
    }
    

      

      要想使用mybatis时,person表的字段仍能正确对应到Person类中的准确字段中,使用resultMap来指定对应关系,可以这样做:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="lixin.gan.mapper.PersonMapper">
    
    	<!-- 定义数据表中的字段,与实体类中的属性对应关系 -->
    	<resultMap type="lixin.gan.pojo.Person" id="testResultMap">
    		<!-- 数据表中的主键列字段使用<id />标签, 其他字段使用<result />标签 -->
    		<!-- column表示的是数据表中的字段, property表示的是实体类中对应的属性 -->
    		<id 	column="id"   property="id1" 	/>
    		<result column="name" property="name1"	/>
    		<result column="age"  property="age1" 	/>
    		<result column="addr" property="addr1"	/>
    	</resultMap>	
    	
    	<!-- 此时不用resultType属性,而是使用resultMap属性,属性值就是前面定义的对应关系id -->
    	<select id="selectAll"  resultMap="testResultMap">
    		select * from person
    	</select>
    </mapper>
    

      

    使用resultMap实现n+1查询

      n+1查询是指:先查询出某个表的全部信息,然后根据这个表的信息,去查询另外一个表的信息。

      举下面一个例子:查询student表后,根据student表中的tid,查询对应的teacher表中信息。

      Teacher类(对应teacher表),实体类定义如下:

    package lixin.gan.pojo;
    
    public class Teacher {
    	private int id;
    	private String name;
    	
    	// 省略了构造方法、setter、getter、toString
    }
    

      

      TeacherMapper.xml中的内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="lixin.gan.mapper.TeacherMapper">
    
    	<resultMap type="lixin.gan.pojo.Teacher" id="teacherMap">
    		<id 	column="id"   property="id" 	/>
    		<result column="name" property="name"	/>
    	</resultMap>	
    	
    	<select id="selectAllTeacher"  resultMap="teacherMap">
    		select * from teacher
    	</select>
    	
    	<select id="selectTeacherById" resultType="teacher" parameterType="int">
    		select * from teacher where id=#{0}
    	</select>
    </mapper>
    

      

      现在有一个Student类(对应student表),实体类定义如下:

    package lixin.gan.pojo;
    
    public class Student {
    	private int id;		// 学生id
    	private int age;	// 学生年龄
    	private String name;// 学生姓名
    	private int tid;	// 老师的id
    	private Teacher teacher;  // 包含一个Teacher对象
    	// 省略了构造方法、setter、getter、toString
    }
    

      与此同时,StudentMapper.xml中的内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="lixin.gan.mapper.StudentMapper">
    
    	<!-- 定义数据表中的字段,与实体类中的属性对应关系 -->
    	<resultMap type="lixin.gan.pojo.Student" id="studentMap">
    		<id 	column="id"   property="id" 	/>
    		
    		<result column="name" property="name"	/>
    		<result column="age"  property="age" 	/>
    		<result column="tid" property="tid"	/>
    		
    		<!-- 如果当前xml对应的实体类中包含一个类对象,那么可以使用association标签来进行关联 -->
    		<!-- property仍旧指的是实体类中的属性名,select表示要为该属性赋值,需要执行的查询操作(id),column表示传入的参数-->
    		<association 
    			property="teacher"   
    			select="lixin.gan.mapper.TeacherMapper.selectTeacherById" 
    			column="tid"
    		></association>
    		
    		<!-- 如果当前的xml对应的实体来中包含一个容器集合,那么可以使用collection标签来进行关联 -->
    		<!-- <collection property=""></collection> -->
    	</resultMap>	
    	
    	<select id="selectAllStudent"  resultMap="studentMap">
    		select * from student
    	</select>
    </mapper>
    

      

      测试代码:

    package lixin.gan.test;
    
    import java.io.InputStream;
    import java.util.List;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import lixin.gan.pojo.Student;
    
    public class Test {
    	public static void main(String[] args) throws Exception{
    		InputStream config = Resources.getResourceAsStream("mybatis.xml");
    		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);
    		
    		SqlSession session = factory.openSession();
    		
    		List<Student> list = session.selectList("lixin.gan.mapper.StudentMapper.selectAllStudent");
    
    		for (Student stu : list) {
    			System.out.println(stu);
    		}
    	}
    }
    

      运行结果,打印log4j日志:

    ==>  Preparing: select * from student 
    ==> Parameters: 
    ====>  Preparing: select * from teacher where id=? 
    ====> Parameters: 2(Integer)
    <====      Total: 1
    ====>  Preparing: select * from teacher where id=? 
    ====> Parameters: 1(Integer)
    <====      Total: 1
    ====>  Preparing: select * from teacher where id=? 
    ====> Parameters: 5(Integer)
    <====      Total: 1
    ====>  Preparing: select * from teacher where id=? 
    ====> Parameters: 4(Integer)
    <====      Total: 1
    <==      Total: 4
    Student [id=1, age=5, name=张三, tid=2, teacher=Teacher [id=2, name=黄老师]]
    Student [id=2, age=10, name=李四, tid=1, teacher=Teacher [id=1, name=李老师]]
    Student [id=3, age=25, name=王五, tid=5, teacher=Teacher [id=5, name=方老师]]
    Student [id=4, age=30, name=赵六, tid=4, teacher=Teacher [id=4, name=蔡老师]]
    

      

    使用resultMap关联集合对象

      关联集合对象,可以理解为,一个类A的某个属性,是包含另一个类B的集合。

      举例:一个老师有多个学生,查询所有老师,并且查出老师的学生。

      Student.java实体类如下:

    package lixin.gan.pojo;
    
    public class Student {
    	private int id;		// 学生id
    	private int age;	// 学生年龄
    	private String name;// 学生姓名
    	private int tid;	// 老师的id
    	
    	// 省略了构造方法,setter、getter、toString
    }
    

      对应的StudentMapper.xml为:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="lixin.gan.mapper.StudentMapper">	
    	<select id="selectStudentById"  resultType="lixin.gan.pojo.Student">
    		select * from student where tid=#{0}
    	</select>
    </mapper>
    

      

      Teacher.java实体类内容如下:

    package lixin.gan.pojo;
    
    import java.util.List;
    
    public class Teacher {
    	private int id;
    	private String name;
    	
    	private List<Student> list;
    	
    	// 省略了构造方法,setter、getter、toString
    }
    

      TeacherMapper.xml对应的内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="lixin.gan.mapper.TeacherMapper">
    
    	<resultMap type="lixin.gan.pojo.Teacher" id="teacherMap">
    		<id 	column="id"   property="id" 	/>
    		<result column="name" property="name"	/>
    		
    		<!-- 当关联的类型是集合类型,那么就需要使用collection标签,并且要指定ofType,表示集合中元素的值 -->
    		<collection 
    			property="list" 
    			select="lixin.gan.mapper.StudentMapper.selectStudentById" 
    			ofType="lixin.gan.pojo.Student"
    			column="id"
    		></collection>
    	</resultMap>	
    	
    	<select id="selectAllTeacher"  resultMap="teacherMap">
    		select * from teacher
    	</select>
    	
    </mapper>
    

      

      运行测试代码:

    package lixin.gan.test;
    
    import java.io.InputStream;
    import java.util.List;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import lixin.gan.pojo.Teacher;
    
    public class Test {
    	public static void main(String[] args) throws Exception{
    		InputStream config = Resources.getResourceAsStream("mybatis.xml");
    		SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(config);
    		
    		SqlSession session = factory.openSession();
    		
    		List<Teacher> list = session.selectList("lixin.gan.mapper.TeacherMapper.selectAllTeacher");
    
    		for (Teacher teacher : list) {
    			System.out.println(teacher);
    		}
    	}
    }
    

      

      利用log4j打印的日志,以及程序运行输出如下:

    ==>  Preparing: select * from teacher 
    ==> Parameters: 
    ====>  Preparing: select * from student where tid=? 
    ====> Parameters: 1(Integer)
    <====      Total: 1
    ====>  Preparing: select * from student where tid=? 
    ====> Parameters: 2(Integer)
    <====      Total: 3
    ====>  Preparing: select * from student where tid=? 
    ====> Parameters: 3(Integer)
    <====      Total: 0
    ====>  Preparing: select * from student where tid=? 
    ====> Parameters: 4(Integer)
    <====      Total: 2
    ====>  Preparing: select * from student where tid=? 
    ====> Parameters: 5(Integer)
    <====      Total: 1
    <==      Total: 5
    Teacher [id=1, name=李老师, list=[Student [id=2, age=10, name=李四, tid=1]]]
    Teacher [id=2, name=黄老师, list=[Student [id=1, age=5, name=张三, tid=2], Student [id=5, age=22, name=小红, tid=2], Student [id=6, age=23, name=小花, tid=2]]]
    Teacher [id=3, name=王老师, list=[]]
    Teacher [id=4, name=蔡老师, list=[Student [id=4, age=30, name=赵六, tid=4], Student [id=7, age=30, name=小黄, tid=4]]]
    Teacher [id=5, name=方老师, list=[Student [id=3, age=25, name=王五, tid=5]]]
    

      

      

  • 相关阅读:
    BCD码、十六进制与十进制互转
    UNIX环境高级编程 使用方法
    Windows下NFS服务器SFU设置(可以共享linux系统)
    Linux学习之CentOS(一)--CentOS6.4环境搭建
    WORKGROUP无法访问,您可能没有权限使用网络资源,请与这台服务器的管理员联系以....
    嵌入式学习步骤
    asp.net core-6.Bind读取配置文件到C#实例中
    asp.net core-5.控制台读取json文件
    asp.net core-4.命令行配置
    asp.net core-3.应用程序部署到iis
  • 原文地址:https://www.cnblogs.com/-beyond/p/10135635.html
Copyright © 2020-2023  润新知