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實現表間關聯

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM