zoukankan      html  css  js  c++  java
  • mybatis 使用auto mapping原理实现表间关联

    Auto mapping的示例

      数据库中有一个person表,结构如下:

    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表中的字段名一一对应。

    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="selectAllPerson" resultType="lixin.gan.pojo.Person" >
    		select * from person
    	</select>
    	
    </mapper>
    

      

      在调用lixin.gan.mapper.PersonMapper.selectAllPerson方法时,返回结果集中,每一条数据,都对应到一个Person类对象,应该将person表中字段值对应到Person对象的同名属性中,于是,我们在测试的时候,获得的结果就是这样的:

    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.Person;
    
    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<Person> list = session.selectList("lixin.gan.mapper.PersonMapper.selectAllPerson");
    		
    		for (Person p : list) {
    			System.out.println(p);
    		}
    		
    		session.close();
    	}
    }
    

      运行结果如下:

    ==>  Preparing: select * from person 
    ==> Parameters: 
    <==      Total: 4
    Person [id=1, name=张三, age=30, addr=北京]
    Person [id=2, name=李四, age=40, addr=上海]
    Person [id=3, name=王五, age=20, addr=广州]
    Person [id=4, name=赵六, age=35, addr=深圳]
    

      

      现在如果将Person类中的name属性更改为name1,age更改为age1,那么再次运行测试代码:

    package lixin.gan.pojo;
    
    public class Person {
    	private int id;
    	private String name1;
    	private int age1;
    	private String addr;
    	
    	//省略了构造方法,setter、getter、toString
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getName1() {
    		return name1;
    	}
    	public void setName1(String name1) {
    		this.name1 = name1;
    	}
    	public int getAge1() {
    		return age1;
    	}
    	public void setAge1(int age1) {
    		this.age1 = age1;
    	}
    	public String getAddr() {
    		return addr;
    	}
    	public void setAddr(String addr) {
    		this.addr = addr;
    	}
    }
    

      

      运行结果:

    ==>  Preparing: select * from person 
    ==> Parameters: 
    <==      Total: 4
    Person [id=1, name1=null, age1=0, addr=北京]
    Person [id=2, name1=null, age1=0, addr=上海]
    Person [id=3, name1=null, age1=0, addr=广州]
    Person [id=4, name1=null, age1=0, addr=深圳]
    

      可以看到,上面的name1属性和age1属性,并没有被赋值。

      这里有一点很重要:mybatis在为对象属性赋值的时候,其实并不是将查出来的字段值,直接赋值给对象的同名属性,而是调用setter方法进行赋值。假设name属性会调用setName来将name字段值赋值给对象中与name字段对应的属性,这个属性可能是name,也可能是name1,上面这个Person中的name1,利用IDE生成的setter方法名称是setName1,可以调用setName1()对name1属性进行赋值,但是因为name字段没有找到对应的setName方法,所以对象中的name1属性就没有赋值。

      示例:

    package lixin.gan.pojo;
    
    public class Person {
    	private int id;
    	private String name1;
    	private int age1;
    	private String addr;
    	
    	//省略了构造方法,setter、getter、toString
    
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getName() {
    		return name1;
    	}
    	public void setName(String name1) {
    		this.name1 = name1;
    	}
    	public int getAge() {
    		return age1;
    	}
    	public void setAge(int age1) {
    		this.age1 = age1;
    	}
    }
    

      注意上面的name1属性,使用setName()为name1进行赋值,使用setAge()为age1属性进行赋值。所以,运行测试的时候,输出的内容如下;

    ==>  Preparing: select * from person 
    ==> Parameters: 
    <==      Total: 4
    Person [id=1, name1=张三, age1=30, addr=北京]
    Person [id=2, name1=李四, age1=40, addr=上海]
    Person [id=3, name1=王五, age1=20, addr=广州]
    Person [id=4, name1=赵六, age1=35, addr=深圳]
    

      

      同样的,在mapper.xml中,如果传入的参数是一个对象,可以使用#{field}获取对象的field属性值,调用的是getter方法,而不是直接使用的属性值。

      

    类间的包含的auto mapping

      举个例子,有两个表,husband表和wife表。

      表结构如下:

    mysql> desc wife;
    +-------+-------------+------+-----+---------+----------------+
    | Field | Type        | Null | Key | Default | Extra          |
    +-------+-------------+------+-----+---------+----------------+
    | id    | int(11)     | NO   | PRI | NULL    | auto_increment |
    | name  | varchar(30) | NO   |     | NULL    |                |
    +-------+-------------+------+-----+---------+----------------+
    
    mysql> desc husband;
    +-------+-------------+------+-----+---------+----------------+
    | Field | Type        | Null | Key | Default | Extra          |
    +-------+-------------+------+-----+---------+----------------+
    | id    | int(11)     | NO   | PRI | NULL    | auto_increment |
    | name  | varchar(30) | NO   |     | NULL    |                |
    | wid   | int(11)     | NO   |     | NULL    |                |
    +-------+-------------+------+-----+---------+----------------+
    

      对应的Wife.java和Husband.java中是两个表中对应的实体类。

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

      

    package lixin.gan.pojo;
    
    public class Husband {
    	private int id;
    	private String name;
    	private int wid;	//wife的id
    	private Wife wife;  //包含一个Wife对象
    	
    	// 省略了构造方法,setter、getter、toStrin
    }
    

      

      如果要查出husband表中的所有数据,并且联合wife表,查出wife信息。

      现在看一下HusbandMapper.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.HusbandMapper">
    	<select id="selectAll" resultType="lixin.gan.pojo.Husband" >
    		select * from husband left join wife on husband.wid=wife.id
    	</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.Husband;
    
    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<Husband> list = session.selectList("lixin.gan.mapper.HusbandMapper.selectAll");
    		
    		for (Husband p : list) {
    			System.out.println(p);
    		}
    		
    		session.close();
    	}
    }
    

      输出内容如下(包含log4j日志):

    ==>  Preparing: select * from husband left join wife on husband.wid=wife.id 
    ==> Parameters: 
    <==      Total: 4
    Husband [id=1, name=小黄, wid=2, wife=null]
    Husband [id=2, name=小凯, wid=4, wife=null]
    Husband [id=3, name=小亮, wid=1, wife=null]
    Husband [id=4, name=小辉, wid=3, wife=null]
    

      上面的运行结果,很容易就发笑,wife属性(Wife类的对象)值为null,这是因为没有进行赋值,这是为什么呢?这个还得看一下我们的HusbandMapper.xml中写的那一条sql语句。

    select * from husband left join wife on husband.wid=wife.id 
    

      上面这个查询之后,结果集中包含这么几个字段:

    Database changed
    mysql> select * from husband left join wife on husband.wid=wife.id;
    +----+--------+-----+------+--------+
    | id | name   | wid | id   | name   |
    +----+--------+-----+------+--------+
    

      可以从查询结果中,看到,重复的id和name字段,并且,后面的那个id和name字段本应该赋值给Husband类的wife属性,而wife属性本来就是一个对象。

    使用别名来解决问题

      在mysql中,select的字段后面使用as或者空格分隔,之后跟的一个名称就是该字段的别名,在返回的时候,返回别名即可。

      上面的husband类中包含一个wife的对象属性,wife属性(对象)又包括id、name,所以,mybatis中的sql语句,使用别名时,使用wife.id和wife.name即可为wife属性赋值。

      修改HusbandMapper.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.HusbandMapper">
    	<select id="selectAll" resultType="lixin.gan.pojo.Husband" >
    		select husband.id `id`, husband.name `name`, husband.wid `wid`,
    			   wife.id `wife.id`, wife.name `wife.name` 
    			   from husband left join wife on husband.wid=wife.id
    	</select>
    </mapper>
    

      

      运行测试:

    ==>  Preparing: select husband.id `id`, husband.name `name`, 
    				husband.wid `wid`,  wife.id `wife.id`, wife.name `wife.name` from husband 
    				left join wife on husband.wid=wife.id 
    ==> Parameters: 
    <==      Total: 4
    Husband [id=1, name=小黄, wid=2, wife=Wife [id=2, name=小红]]
    Husband [id=2, name=小凯, wid=4, wife=Wife [id=4, name=小云]]
    Husband [id=3, name=小亮, wid=1, wife=Wife [id=1, name=小花]]
    Husband [id=4, name=小辉, wid=3, wife=Wife [id=3, name=小娇]]
    

       

      

    auto mapping不能解决的问题

      仍旧使用上面的例子,auto-mapping就不能解决一夫多妻的问题,一个husband对象中,有一个属性是List,每一个List的元素是wife对象。

      这个问题可以使用resultMap来解决问题。

      可以参考:mybatis 使用resultMap实现表间关联

      

  • 相关阅读:
    【Educational Codeforces Round 101 (Rated for Div. 2) C】Building a Fence
    【Codeforces Round #698 (Div. 2) C】Nezzar and Symmetric Array
    【Codeforces Round #696 (Div. 2) D】Cleaning
    【Codeforces Round #696 (Div. 2) C】Array Destruction
    【Educational Codeforces Round 102 D】Program
    【Educational Codeforces Round 102 C】No More Inversions
    【Good Bye 2020 G】Song of the Sirens
    【Good Bye 2020 F】Euclid's nightmare
    使用mobx入门
    requestAnimationFrame 控制速度模拟setinterval
  • 原文地址:https://www.cnblogs.com/-beyond/p/10134466.html
Copyright © 2011-2022 走看看