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