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

  

原文地址:https://www.cnblogs.com/-beyond/p/10134466.html