• 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实现表间关联

      

  • 相关阅读:
    Linux下安装mysql(1)(CentOS)
    shell 运算符
    shell $*与$@的区别
    XMind破解
    在CentOS系统上将deb包转换为rpm包
    一次与流氓软件的斗争,浏览器主页被锁定
    dropzone上传文件
    KindEditor4.1.10,支持粘贴图片
    bootstrap paginator使用简述
    sendkeys && appactivate
  • 原文地址:https://www.cnblogs.com/-beyond/p/10134466.html
Copyright © 2020-2023  润新知