前言:
百度百科:
MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可 以使用簡單的 XML 或注解來配置和映射原生信息,將接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java對象)映射成數據庫中的記錄。
這篇文章講解如何 使用mysql數據庫,總結mybatis的一對一、一對多、多對多映射如何進行增刪改查。
准備工作:
1.打開ecplise創建一個普通的java項目。項目結構如下圖所示:
2.先看jar包,這次我們用到4個jar包,單元測試jar包junit-4.7.jar,日志包log4j-1.2.17.jar,mybatis所用的jar包以及連接mysql數據庫用到的mysql-connector-java-5.1.47.jar
【ojdbc14.jar是連接oracle數據庫用到的jar包】。
注:jar包記得build path
3.dtd約束文件:是對全局配置文件和sql映射文件的約束。在ecplise中點擊 window --> preference ,在輸入欄鍵入xml,然后選擇 XML Catalog,點擊Add。
注:-//mybatis.org//DTD Mapper 3.0//EN 、-//mybatis.org//DTD Config 3.0//EN ,key值是規定的,location是點擊workspace在項目中選擇的約束文件。
4.driver.properties配置文件是連接數據庫所用到的配置信息。在mybaits-config.xml中會用到。
#基於mysql數據庫 driver=com.mysql.jdbc.Driver #?useUnicode=true&characterEncoding=utf8為了支持中文數據的寫入
url=jdbc:mysql://188.131.246.182:3306/cnblogs?useUnicode=true&characterEncoding=utf-8
username=study
password=123456 #基於Oracle數據庫 #driver=oracle.jdbc.driver.OracleDriver #url=jdbc:oracle:thin:@127.0.0.1:1521:XE #username=briup #password=briup
5.log4j.properties是日志jar包要用到的配置文件。其中定義了輸出日志級別、輸出位置以及是否打印sql語句。
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d [%-5p] %c - %m%n
#show sql
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
6.全局配置文件:mybatis-config.xml。該文件的詳細信息可網上找資料。我這里給一個簡單能用的。
<?xml version="1.0" encoding="UTF-8"?>
<!-- dtd約束 -->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" >
<configuration>
<!-- properties必須是第一個子標簽 定義變量,定義完成后,可以在后面的標簽中使用 resource引入配置文件,優先級更高 -->
<properties resource="driver.properties">
<property name="driver" value=""/>
<property name="url" value=""/>
<property name="username" value=""/>
<property name="password" value=""/>
</properties>
<typeAliases>
<!-- 給包下的類定義別名 -->
<package name="com.cnblogs.bean"/>
</typeAliases>
<!-- 使用mysql數據庫,如果要切換到Oracle數據庫,default="oracle" -->
<environments default="mysql">
<!-- mysql -->
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
<!-- oracle -->
<environment id="oracle">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/cnblogs/OneToMany/OneToMany.xml" />
</mappers>
</configuration>
准備工作完成以后就可以開始寫sql語句了。
注:嵌套結果查詢:一次查一張表,分多次查。
嵌套結果映射:一次查多張表,分別映射。
一對一映射
1.創建bean類:Student【學生】、FoodCard【飯卡】
Student.java

package com.cnblogs.bean; /** * 和飯卡一一對應 * CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) NOT NULL, `gender` varchar(255) NOT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) * */ public class Student { private Integer id; private String name; private String gender; private int age; public Student() { super(); // TODO Auto-generated constructor stub } public Student(String name, String gender, int age) { super(); this.name = name; this.gender = gender; this.age = age; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + "]"; } }
FoodCard.java

package com.cnblogs.bean; /** * 飯卡,和學生一對一映射 * CREATE TABLE `food_card` ( `id` int(11) NOT NULL AUTO_INCREMENT, `number` varchar(255) NOT NULL, `balance` double DEFAULT NULL, `stu_id` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `stu_id` (`stu_id`), CONSTRAINT `stu_id` FOREIGN KEY (`stu_id`) REFERENCES `student` (`id`) ) * */ public class FoodCard { private Integer id; // 卡號 private String number; //余額 private Double balance; // 對應的學生 private Student stu; public FoodCard() { super(); // TODO Auto-generated constructor stub } public FoodCard(String number, Double balance) { super(); this.number = number; this.balance = balance; } public FoodCard(String number, Double balance, Student stu) { super(); this.number = number; this.balance = balance; this.stu = stu; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public Double getBalance() { return balance; } public void setBalance(Double balance) { this.balance = balance; } public Student getStu() { return stu; } public void setStu(Student stu) { this.stu = stu; } @Override public String toString() { return "FoodCard [id=" + id + ", number=" + number + ", balance=" + balance + ", stu=" + stu + "]"; } }
3.編寫sql映射文件。首先告訴mybatis那個xml文件是你的映射文件。在mybatis的<Mappers>標簽中添加一條
" <mapper resource="com/cnblogs/oneToOne/OneToOne.xml"/> " 按住Ctrl+鼠標左鍵點擊跳轉到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">
<!-- com.cnblogs.oneToOne.OneToOne是我們定義接口的全限定名字 這樣就可以使用接口調用映射的SQL語句了 這個 名字一定要和接口對應上-->
<mapper namespace="com.cnblogs.oneToOne.OneToOne">
<!-- 插入一條學生信息 -->
<insert id="insertStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="id"> insert into student(name,gender,age) values(#{name},#{gender},#{age}) </insert>
<!-- 插入一條飯卡信息 自動生成主鍵 #{number}代表調用getNumber()方法 -->
<insert id="insertFoodCard" parameterType="FoodCard" useGeneratedKeys="true" keyProperty="id"> insert into food_card(number,balance,stu_id) values(#{number},#{balance},#{stu.id}) </insert>
<!-- 刪除一條飯卡信息-->
<delete id="deleteFoodCardById" parameterType="int"> delete from food_card where id=#{id} </delete>
<!-- 根據學生id刪除一條飯卡信息 -->
<delete id="deleteFoodCardByStuId" parameterType="int"> delete from food_card where stu_id=#{id} </delete>
<!-- 刪除一條學生信息 由於主鍵被飯卡表引用,需要級聯刪除,先調用deleteFoodCardByStuId -->
<delete id="deleteStudentById" parameterType="int"> delete from student where id=#{id} </delete>
<!-- 模擬一個業務需求:假設一批學生畢業了,需要刪除關於這批學生的所有飯卡信息 -->
<delete id="deleteFoodCardByStuIds" parameterType="java.util.List"> delete from food_card where stu_id in( <foreach collection="list" item="stu" separator="," > #{stu.id} </foreach> ) </delete>
<!-- 如果方法要傳入兩個參數,#{param1}代表第一個參數,#{param2}代表第二個參數 -->
<!-- 根據名字和年齡更改一條學生記錄 -->
<update id="updateStudentByNameAndAge"> update student set age=21 where name=#{param1} and age=#{param2} </update>
<!-- 一對一映射 查詢兩張表food_card和student,如何將student查到的記錄映射到 FoodCard對象中? -->
<resultMap type="Student" id="StudentMap">
<id column="id" property="id" />
<result column="name" property="name"/>
<result column="gender" property="gender"/>
<result column="age" property="age"/>
</resultMap>
<!-- 嵌套結果映射 -->
<resultMap type="FoodCard" id="FoodCardMap">
<id column="id" property="id" />
<result column="number" property="number"/>
<result column="balance" property="balance"/>
<!-- 一對一映射,將很多列映射到stu屬性上 -->
<association property="stu" resultMap="StudentMap" />
</resultMap>
<select id="selectFoodCardWithStudent" parameterType="int" resultMap="FoodCardMap"> select * from student stu,food_card fc where fc.id=#{id} and fc.stu_id=stu.id </select>
<!-- 嵌套結果查詢 -->
<select id="selectStudentById" resultType="Student"> select * from student where id=#{id} </select>
<resultMap type="FoodCard" id="FoodCardMap2">
<id column="id" property="id" />
<result column="number" property="number"/>
<result column="balance" property="balance"/>
<!-- 一對一 嵌套結果查詢-->
<association property="stu" select="selectStudentById" column="stu_id"/>
</resultMap>
<select id="selectFoodCardWithStudent2" parameterType="int" resultMap="FoodCardMap2"> select * from food_card fc where fc.id=#{id} </select>
</mapper>
*嵌套結果映射:
<!-- 嵌套結果映射 -->
<resultMap type="FoodCard" id="FoodCardMap">
<id column="id" property="id" />
<result column="number" property="number"/>
<result column="balance" property="balance"/>
<!-- 一對一映射,將很多列映射到stu屬性上 -->
<association property="stu" resultMap="StudentMap" />
</resultMap>
<select id="selectFoodCardWithStudent" parameterType="int" resultMap="FoodCardMap">
select * from student stu,food_card fc where fc.id=#{id} and fc.stu_id=stu.id
</select>
resultMap標簽,type屬性表示和那種類型對應,id值起唯一標識作用,主鍵用id標簽,表的其它列用result標簽,column代表和數據庫表對應的列,property
表示type值對應的屬性【property指getXXX和setXXX】,column和property組合起來表示把查到的記錄對應的列映射到對應的屬性上。
嵌套結果查詢的SQL語句,返回值不能再用resultType指定了,用resultMap指定。
注:嵌套結果映射中,如果兩個表有同名的列,自然鏈接的時候只會保留一個列,上述中如果直接 'select * ' 會導致飯卡id和學生id一致。
必須顯式的指定返回的列, ' select fc.id,fc.number,fc.balance,fc.stu_id,stu.id,stu.name,stu.age,stu.gender
from student stu,food_card fc where fc.id=#{id} and fc.stu_id=stu.id'。嵌套結果查詢不需要顯式指定。
*嵌套結果查詢
<!-- 嵌套結果查詢 -->
<select id="selectStudentById" resultType="Student"> select * from student where id=#{id} </select> <resultMap type="FoodCard" id="FoodCardMap2"> <id column="id" property="id" /> <result column="number" property="number"/> <result column="balance" property="balance"/> <!-- 一對一 嵌套結果查詢--> <association property="stu" select="selectStudentById" column="stu_id"/>
</resultMap> <select id="selectFoodCardWithStudent2" parameterType="int" resultMap="FoodCardMap2"> select * from food_card fc where fc.id=#{id} </select>
一次查一張表,多次查。<association property="stu" select="selectStudentById" column="stu_id"/>
property代表映射到那個屬性,select代表調用那個方法,column指定當前查表返回的那個列作為方法的參數。如果
還需要再查一張表,按照規則再加一條<association>
所有的sql語句對應的接口中必須有該方法。

package com.cnblogs.oneToOne; import java.util.List; import com.cnblogs.bean.FoodCard; import com.cnblogs.bean.Student; public interface OneToOne { /** * 插入一條飯卡信息 */ public abstract void insertFoodCard(FoodCard foodCard); /** * 插入一條學生信息 */ public abstract void insertStudent(Student stu); /** * 刪除一條飯卡記錄 */ public abstract void deleteFoodCardById(Integer id); /** * 根據學生id刪除一條飯卡記錄 */ public abstract void deleteFoodCardByStuId(Integer id); /** * 刪除一條學生記錄根據id * 調用該方(法應該先調用deleteFoodCardByStuId(Integer) */ public abstract void deleteStudentById(Integer id); /** * 提供一批學生信息,刪除對應的飯卡 */ public abstract void deleteFoodCardByStuIds(List<Student> stus); /** * 根據年齡和姓名更改一條學生記錄 */ public abstract void updateStudentByNameAndAge(String name,Integer age); /** * 根據id查找飯卡的詳細信息[包括學生屬性] * 使用嵌套結果映射 */ public abstract FoodCard selectFoodCardWithStudent(Integer id); /** * 根據id查找學生記錄 */ public abstract Student selectStudentById(Integer id); /** * 根據id查找飯卡的詳細信息[包括學生屬性] * 使用嵌套結果查詢 */ public abstract FoodCard selectFoodCardWithStudent2(Integer id); }
單元測試類:

package com.cnblogs.jtest; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; 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 org.junit.Test; import com.cnblogs.bean.FoodCard; import com.cnblogs.bean.Student; import com.cnblogs.oneToOne.OneToOne; import com.cnblogs.utils.MySqlSessionFactory; public class OneToOneTest { @Test public void insertStudent() { Student student1 = new Student("jack","男",20); Student student2 = new Student("Tina", "女", 16); InputStream inputStream; try{ // 讀取配置文件 inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 手動提交事務 SqlSession sqlSession = sqlSessionFactory.openSession(false); OneToOne mapper = sqlSession.getMapper(OneToOne.class); mapper.insertStudent(student1); mapper.insertStudent(student2); // 提交事務 sqlSession.commit(); } catch(Exception e) { e.printStackTrace(); } } @Test public void insertFoodCard() { Student stu1 = new Student(); stu1.setId(15); Student stu2 = new Student(); stu2.setId(16); FoodCard foodCard1 = new FoodCard("123456",100.0,stu1); FoodCard foodCard2 = new FoodCard("123457",312.4,stu2); InputStream inputStream; try{ // 讀取配置文件 inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class); mapper.insertFoodCard(foodCard1); mapper.insertFoodCard(foodCard2); // 提交事務 sqlSession.commit(); } catch(Exception e) { e.printStackTrace(); } } @Test public void deleteFoodCardById() { InputStream inputStream; try{ // 讀取配置文件 inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class); mapper.deleteFoodCardById(5); // 提交事務 sqlSession.commit(); } catch(Exception e) { e.printStackTrace(); } } @Test public void deleteStudentById() { InputStream inputStream; try{ // 讀取配置文件 inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class); mapper.deleteFoodCardByStuId(6); mapper.deleteStudentById(6); // 提交事務 sqlSession.commit(); } catch(Exception e) { e.printStackTrace(); } } @Test public void deleteFoodCardByStuIds() { InputStream inputStream; try{ // 讀取配置文件 inputStream = Resources.getResourceAsStream("mybatis-config.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class); Student stu1 = new Student(); stu1.setId(5); Student stu2 = new Student(); stu2.setId(7); Student stu3 = new Student(); stu3.setId(10); ArrayList<Student> stus = new ArrayList<Student>(); stus.add(stu1); stus.add(stu2); stus.add(stu3); mapper.deleteFoodCardByStuIds(stus); // 提交事務 sqlSession.commit(); } catch(Exception e) { e.printStackTrace(); } } @SuppressWarnings("unused") @Test public void updateStudentByNameAndAge() { SqlSession sqlSession = null; try { // 手動提交事務 sqlSession = MySqlSessionFactory.opensession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class); mapper.updateStudentByNameAndAge("jack", 20); sqlSession.commit(); } catch (IOException e) { if(sqlSession != null) sqlSession.rollback(); e.printStackTrace(); } } @Test public void selectFoodCardWithStudent() { SqlSession sqlSession = null; try { sqlSession = MySqlSessionFactory.opensession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class); FoodCard foodCard = mapper.selectFoodCardWithStudent(12); System.out.println(foodCard); } catch (IOException e) { e.printStackTrace(); } } @Test public void selectFoodCardWithStudent2() { SqlSession sqlSession = null; try { sqlSession = MySqlSessionFactory.opensession(); OneToOne mapper = sqlSession.getMapper(OneToOne.class); FoodCard foodCard = mapper.selectFoodCardWithStudent2(12); System.out.println(foodCard); } catch (IOException e) { e.printStackTrace(); } } }
獲得SqlSesion對象的步驟重多,我們可以進行封裝成一個工廠類。
package com.cnblogs.utils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MySqlSessionFactory {
public static SqlSessionFactory getSqlSessionFactory() throws IOException{
// 讀取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
if(inputStream == null)
throw new IOException("配置文件路徑不對或者配置文件內容出錯");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory;
}
/**
*
* @param flag true 自動提交事務,false 手動提交事務
* @return
*/
public static SqlSession opensession(boolean flag) throws IOException{
return getSqlSessionFactory().openSession(flag);
}
/**
* 默認手動提交事務
* @return
*/
public static SqlSession opensession() throws IOException{
return opensession(false);
}
}
一對多映射
簡單模擬一下映射關系,一個人只能有一個戶籍所在地,而一個戶籍所在地可以對應許多人。把外鍵放在一的那邊。
1)pojo類:
Human.java

package com.cnblogs.bean; import java.util.Date; /** * create table human( * id int, * name varchar, * gender varchar, * age int, * dob datetime, * address_id int reference address(id) * ) * */ public class Human { private Integer id; private String name; private String gender; private Integer age; private Date dob; // 人對應的地址 private Address address; public Human() { super(); } public Human(String name, String gender, Integer age, Date dob) { super(); this.name = name; this.gender = gender; this.age = age; this.dob = dob; } public Human(String name, String gender, Integer age, Date dob, Address address) { super(); this.name = name; this.gender = gender; this.age = age; this.dob = dob; this.address = address; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getDob() { return dob; } public void setDob(Date dob) { this.dob = dob; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public String toString() { return "Human [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", dob=" + dob + ", address=" + address + "]"; } }
Address.java

package com.cnblogs.bean; import java.util.List; /** * table * address( * id int key, * province varchar, * city varchar, * street varchar * ) * */ public class Address { private Integer id; private String province; private String city; private String street; // 地址對應的人 private List<Human> humans; public Address() { super(); } public Address(String province, String city, String street) { super(); this.province = province; this.city = city; this.street = street; } public Address(String province, String city, String street, List<Human> humans) { super(); this.province = province; this.city = city; this.street = street; this.humans = humans; } public Address(Integer id, String province, String city, String street) { super(); this.id = id; this.province = province; this.city = city; this.street = street; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public List<Human> getHumans() { return humans; } public void setHumans(List<Human> humans) { this.humans = humans; } @Override public String toString() { return "Address [id=" + id + ", province=" + province + ", city=" + city + ", street=" + street + "]"; } }
2)在mybatis<Mappers>下加一條:<mapper resource="com/cnblogs/oneToMany/OneToMany.xml" />
3)編寫OneToMany.xml和OneTomany.java接口
<?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">
<!-- com.cnblogs.OneToMany.OneToMany是我們定義接口的全限定名字 這樣就可以使用接口調用映射的SQL語句了 這個 名字一定要和接口對應上-->
<mapper namespace="com.cnblogs.oneToMany.OneToMany">
<!-- 插入一條地址信息 -->
<insert id="insertAddress" parameterType="Address" useGeneratedKeys="true" keyProperty="id"> insert into address(province,city,street) values(#{province},#{city},#{street}) </insert>
<!-- 插入一條人類信息 -->
<insert id="insertHuman" parameterType="Human" useGeneratedKeys="true" keyProperty="id"> insert into human(name,gender,age,dob,address_id) values(#{name},#{gender},#{age},#{dob},#{address.id}) </insert>
<!-- 刪改類似,省略.... -->
<!-- 結果集映射 基礎結果集,說明了如何從數據庫加載對象 -->
<resultMap type="Address" id="addressBaseMap">
<id property="id" column="id" />
<result property="province" column="province"/>
<result property="city" column="city"/>
<result property="street" column="street"/>
</resultMap>
<resultMap type="Human" id="humanBaseMap">
<id property="id" column="id" />
<result property="name" column="name"/>
<result property="gender" column="gender"/>
<result property="age" column="age"/>
<result property="dob" column="dob"/>
</resultMap>
<!-- 結果集映射 一個人對應一個戶籍,所以這里還是一對一映射 繼承基礎結果集 -->
<!-- 嵌套結果映射 繼承:namespace + id 完全限定名 -->
<resultMap type="Human" id="humanMap" extends="com.cnblogs.oneToMany.OneToMany.humanBaseMap">
<!-- 避免human的id和address的id起沖突,sql語句會給列起別名,相應的這里也需要更改 -->
<id property="id" column="hid" />
<association property="address" resultMap="addressBaseMap"></association>
</resultMap>
<select id="selectHumanWithAddressById" parameterType="int" resultMap="humanMap"> select h.id hid,h.name,h.gender,h.age,h.dob,a.* from human h,address a where h.id=#{id} and h.address_id = a.id </select>
<!-- 一對多 一個戶籍地對應多個人 -->
<!-- 嵌套結果映射 -->
<resultMap type="Address" id="AddressMap" extends="com.cnblogs.oneToMany.OneToMany.addressBaseMap">
<!-- 避免human的id和address的id起沖突,sql語句會給列起別名,相應的這里也需要更改 -->
<id property="id" column="aid"/>
<!-- 一對多使用collection集合 -->
<collection property="humans" resultMap="humanBaseMap" />
</resultMap>
<!-- 嵌套結果映射sql語句 -->
<select id="selectAddressWithHumanById" parameterType="int" resultMap="AddressMap"> select a.id aid,a.province,a.city,a.street,h.* from address a,human h where a.id=#{id} and a.id=h.address_id </select>
<!-- 嵌套結果查詢 -->
<!-- 嵌套結果查詢中被用到的另一條sql語句 -->
<select id="selectHumanByAddressId" parameterType="int" resultMap="humanBaseMap"> select * from human where address_id=#{id} </select>
<!-- 結果集 -->
<resultMap type="Address" id="AddressMap2" extends="com.cnblogs.oneToMany.OneToMany.addressBaseMap">
<!-- 把id傳過去 -->
<collection property="humans" select="selectHumanByAddressId" column="id" />
</resultMap>
<!-- 嵌套結果查詢sql語句 -->
<select id="selectAddressWithHumanById2" parameterType="int" resultMap="AddressMap2"> select * from address where id=#{id} </select>
</mapper>
OneTOMany.java

package com.cnblogs.oneToMany; import java.util.List; import com.cnblogs.bean.Address; import com.cnblogs.bean.Human; public interface OneToMany { /** * 插入一條地址信息 * @param address */ public abstract void insertAddress(Address address); /** * 插入一條人類信息 * @param humam */ public abstract void insertHuman(Human humam); /** * 根據id查詢一條人類信息[包括戶籍的詳細信息] * @param id */ public abstract Human selectHumanWithAddressById(Integer id); /** * 嵌套結果映射 * 根據id查詢一條戶籍信息[包括戶籍所在地人的信息] * @param id * @return */ public abstract Address selectAddressWithHumanById(Integer id); /** * 根據戶籍地id查找人 * @param id * @return */ public abstract List<Human> selectHumanByAddressId(Integer id); /** * 嵌套結果查詢 * 根據id查詢一條戶籍信息[包括戶籍所在地人的信息] * @param id * @return */ public abstract Address selectAddressWithHumanById2(Integer id); }
4)測試類

package com.cnblogs.jtest; import java.io.IOException; import java.util.Date; import java.util.List; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import com.cnblogs.bean.Address; import com.cnblogs.bean.Human; import com.cnblogs.oneToMany.OneToMany; import com.cnblogs.utils.MySqlSessionFactory; public class OnetoManyTest { @Test public void insertHumanAndAddress() { try{ SqlSession sqlSession = MySqlSessionFactory.opensession(); OneToMany mapper = sqlSession.getMapper(OneToMany.class); // 准備數據 Address address1 = new Address("湖南", "張家界", "步行街"); Address address2 = new Address("湖南", "長沙", "步行街"); mapper.insertAddress(address1); mapper.insertAddress(address2); //提交事務 sqlSession.commit(); } catch(Exception e) { e.printStackTrace(); } } @SuppressWarnings("unused") @Test public void insertHuman() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); OneToMany mapper = session.getMapper(OneToMany.class); // 准備數據 Address address1 = new Address(); address1.setId(3); Address address2 = new Address(); address2.setId(4); Human human1 = new Human("jack","男",22,new Date(),address1); Human human2 = new Human("tom","男",20,new Date(),address2); Human human3 = new Human("tina","女",22,new Date(),address1); Human human4 = new Human("alias","女",18,new Date(),address1); // 插入數據 mapper.insertHuman(human1); mapper.insertHuman(human2); mapper.insertHuman(human3); mapper.insertHuman(human4); // 提交事務 session.commit(); } catch (IOException e) { if(session != null) session.close(); e.printStackTrace(); } } @SuppressWarnings("unused") @Test public void selectHumanWithAddressById() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); OneToMany mapper = session.getMapper(OneToMany.class); Human human1 = mapper.selectHumanWithAddressById(1); Human human2 = mapper.selectHumanWithAddressById(3); System.out.println("human: " + human1); System.out.println("human: " + human2); } catch (IOException e) { if(session != null) session.close(); e.printStackTrace(); } } @SuppressWarnings("unused") @Test public void selectAddressWithHumanById() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); OneToMany mapper = session.getMapper(OneToMany.class); Address address1 = mapper.selectAddressWithHumanById(3); Address address2 = mapper.selectAddressWithHumanById(4); System.out.println("address: " + address1); List<Human> humans1 = address1.getHumans(); System.out.println("humans : "); for(Human h : humans1) System.out.println(h); System.out.println("============================"); System.out.println("address: " + address2); List<Human> humans2 = address2.getHumans(); System.out.println("humans : "); for(Human h : humans2) System.out.println(h); } catch (IOException e) { if(session != null) session.close(); e.printStackTrace(); } } @SuppressWarnings("unused") @Test public void selectAddressWithHumanById2() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); OneToMany mapper = session.getMapper(OneToMany.class); Address address1 = mapper.selectAddressWithHumanById2(3); Address address2 = mapper.selectAddressWithHumanById2(4); System.out.println("address: " + address1); List<Human> humans1 = address1.getHumans(); System.out.println("humans : "); for(Human h : humans1) System.out.println(h); System.out.println("============================"); System.out.println("address: " + address2); List<Human> humans2 = address2.getHumans(); System.out.println("humans : "); for(Human h : humans2) System.out.println(h); } catch (IOException e) { if(session != null) session.close(); e.printStackTrace(); } } }
多對多
描述:一個老師可以講多門課,一門課可以有多個老師教。
1)pojo類
Teacher.java

package com.cnblogs.bean; import java.util.List; /** * 教師類 * 和課程對多多 */ public class Teacher { // 教師id private Long id; // 教師名稱 private String name; // 教師職稱 講師 高級講師 教授 private String title; // 教師講授的課程 private List<Course> courses; public Teacher() { super(); } public Teacher(String name, String title) { super(); this.name = name; this.title = title; } public Teacher(String name, String title, List<Course> courses) { super(); this.name = name; this.title = title; this.courses = courses; } public Teacher(Long id, String name, String title, List<Course> courses) { super(); this.id = id; this.name = name; this.title = title; this.courses = courses; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public List<Course> getCourses() { return courses; } public void setCourses(List<Course> courses) { this.courses = courses; } @Override public String toString() { return "Teacher [id=" + id + ", name=" + name + ", title=" + title + ", courses=" + courses + "]"; } }
Course.java

package com.cnblogs.bean; import java.util.List; /** * 課程類 * 和教師多對多 * */ public class Course { // 課程id private Long id; // 課程名稱 private String name; // 課程描述 private String description; // 課程對應的老師 private List<Teacher> teachers; public Course() { super(); } public Course(String name, String description) { super(); this.name = name; this.description = description; } public Course(String name, String description, List<Teacher> teachers) { super(); this.name = name; this.description = description; this.teachers = teachers; } public Course(Long id, String name, String description, List<Teacher> teachers) { super(); this.id = id; this.name = name; this.description = description; this.teachers = teachers; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public List<Teacher> getTeachers() { return teachers; } public void setTeachers(List<Teacher> teachers) { this.teachers = teachers; } @Override public String toString() { return "Course [id=" + id + ", name=" + name + ", description=" + description + "]"; } }
橋表類:TeacherCourse.java

package com.cnblogs.bean; import java.util.Date; /** * 橋表類 * 連接教師類和課程類 * */ public class TeacherCourse { // id private Long id; // 授課開始時間 private Date begin; // 授課結束時間 private Date end; // 教師 private Teacher teacher; // 課程 private Course course; public TeacherCourse() { super(); // TODO Auto-generated constructor stub } public TeacherCourse(Date begin, Date end) { super(); this.begin = begin; this.end = end; } public TeacherCourse(Date begin, Date end, Teacher teacher, Course course) { super(); this.begin = begin; this.end = end; this.teacher = teacher; this.course = course; } public TeacherCourse(Long id, Date begin, Date end, Teacher teacher, Course course) { super(); this.id = id; this.begin = begin; this.end = end; this.teacher = teacher; this.course = course; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Date getBegin() { return begin; } public void setBegin(Date begin) { this.begin = begin; } public Date getEnd() { return end; } public void setEnd(Date end) { this.end = end; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } public Course getCourse() { return course; } public void setCourse(Course course) { this.course = course; } @Override public String toString() { return "TeacherCourse [id=" + id + ", begin=" + begin + ", end=" + end + ", teacher=" + teacher + ", course=" + course + "]"; } }
2)在mybatis-config.xml的<Mappers>下加一條:<mapper resource="com/cnblogs/oneToMany/OneToMany.xml" />
3)sql映射文件
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="com.cnblogs.manyTOMany.ManyToMany">
<!-- 結果集映射關系 -->
<resultMap type="Teacher" id="TeacherBaseMap">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
<result property="title" column="t_title"/>
</resultMap>
<resultMap type="Course" id="CourseBaseMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<result property="description" column="c_des"/>
</resultMap>
<resultMap type="TeacherCourse" id="TeacherCourseBaseMap">
<id property="id" column="id"/>
<result property="begin" column="begin"/>
<result property="end" column="end"/>
</resultMap>
<!-- 插入 -->
<insert id="insertTeacher" parameterType="Teacher" useGeneratedKeys="true" keyProperty="id"> insert into teacher(t_name,t_title) values(#{name},#{title}) </insert>
<insert id="insertCourse" parameterType="Course" useGeneratedKeys="true" keyProperty="id"> insert into course(c_name,c_des) values(#{name},#{description}) </insert>
<insert id="insertTeacherCourse" parameterType="TeacherCourse" useGeneratedKeys="true" keyProperty="id"> insert into teacher_course(begin,end,t_id,c_id) values(#{begin},#{end},#{teacher.id},#{course.id}) </insert>
<!-- 嵌套結果映射 其實就是一對多查詢,因為橋表的存在 -->
<resultMap type="Teacher" id="TeacherMap1" extends="com.cnblogs.manyTOMany.ManyToMany.TeacherBaseMap">
<collection property="courses" resultMap="CourseBaseMap" column="c_id" />
</resultMap>
<!-- sql語句 -->
<select id="selectTeacherWithCourseById" parameterType="long" resultMap="TeacherMap1"> select * from teacher t,course c,teacher_course tc where t.t_id=#{id} and t.t_id=tc.t_id and tc.c_id=c.c_id </select>
<!-- 嵌套結果查詢 -->
<select id="selectCourseById" parameterType="long" resultMap="CourseBaseMap"> select * from course where c_id=#{id} </select>
<resultMap type="Teacher" id="TeacherMap2" extends="com.cnblogs.manyTOMany.ManyToMany.TeacherBaseMap">
<collection property="courses" select="selectCourseById" column="c_id" />
</resultMap>
<select id="selectTeacherWithCourseById2" parameterType="long" resultMap="TeacherMap2"> select * from teacher t,teacher_course tc where t.t_id=#{id} and t.t_id=tc.t_id </select>
</mapper>
接口:

package com.cnblogs.manyTOMany; import com.cnblogs.bean.Course; import com.cnblogs.bean.Teacher; import com.cnblogs.bean.TeacherCourse; public interface ManyToMany { /** * 插入一條教師數據 * @param teacher */ public abstract void insertTeacher(Teacher teacher); /** * 插入一條課程數據 * @param course */ public abstract void insertCourse(Course course); /** * 插入一條橋表數據 * @param tc */ public abstract void insertTeacherCourse(TeacherCourse tc); /** * 嵌套結果映射 * 教師的詳細信息 * @param id * @return */ public abstract Teacher selectTeacherWithCourseById(Long id); /** * 嵌套結果查詢 * @param id * @return */ public abstract Teacher selectTeacherWithCourseById2(Long id); }
4)測試類

package com.cnblogs.jtest; import java.io.IOException; import java.util.Date; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import com.cnblogs.bean.Course; import com.cnblogs.bean.Teacher; import com.cnblogs.bean.TeacherCourse; import com.cnblogs.manyTOMany.ManyToMany; import com.cnblogs.utils.MySqlSessionFactory; public class ManyToManyTest { @Test public void insertTeacher() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); ManyToMany mapper = session.getMapper(ManyToMany.class); // 准備數據 Teacher teacher1 = new Teacher("li","講師"); Teacher teacher2 = new Teacher("zj","高級講師"); Teacher teacher3 = new Teacher("kb","教授"); mapper.insertTeacher(teacher1); mapper.insertTeacher(teacher2); mapper.insertTeacher(teacher3); // 提交事務 session.commit(); } catch (IOException e) { e.printStackTrace(); } } @Test public void insertCourse() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); ManyToMany mapper = session.getMapper(ManyToMany.class); // 准備數據 Course course1 = new Course("core java","核心java基礎"); Course course2 = new Course("c語言","ccc"); Course course3 = new Course("c++","c++++"); mapper.insertCourse(course1); mapper.insertCourse(course2); mapper.insertCourse(course3); // 提交事務 session.commit(); } catch (IOException e) { e.printStackTrace(); } } @Test public void insertTeacherCourse() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); ManyToMany mapper = session.getMapper(ManyToMany.class); // 准備數據 Course course1 = new Course(); course1.setId(1L); Course course2 = new Course(); course2.setId(2L); Course course3 = new Course(); course3.setId(3L); Teacher teacher1 = new Teacher(); teacher1.setId(4L); Teacher teacher2 = new Teacher(); teacher2.setId(5L); Teacher teacher3 = new Teacher(); teacher3.setId(6L); TeacherCourse tc1 = new TeacherCourse(new Date(),new Date(),teacher1,course1); TeacherCourse tc2 = new TeacherCourse(new Date(),new Date(),teacher2,course2); TeacherCourse tc3 = new TeacherCourse(new Date(),new Date(),teacher3,course3); mapper.insertTeacherCourse(tc1); mapper.insertTeacherCourse(tc2); mapper.insertTeacherCourse(tc3); // 提交事務 session.commit(); } catch (IOException e) { e.printStackTrace(); } } @Test public void selectTeacherWithCourseById() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); ManyToMany mapper = session.getMapper(ManyToMany.class); // 准備數據 Teacher t1 = mapper.selectTeacherWithCourseById(4L); Teacher t2 = mapper.selectTeacherWithCourseById(6L); System.out.println("Teacher: " + t1); System.out.println("Teacher: " + t2); } catch (IOException e) { e.printStackTrace(); } } @Test public void selectTeacherWithCourseById2() { SqlSession session = null; try { session = MySqlSessionFactory.opensession(); ManyToMany mapper = session.getMapper(ManyToMany.class); // 准備數據 Teacher t1 = mapper.selectTeacherWithCourseById2(4L); Teacher t2 = mapper.selectTeacherWithCourseById2(6L); System.out.println("Teacher: " + t1); System.out.println("Teacher: " + t2); } catch (IOException e) { e.printStackTrace(); } } }
總結:
使用mybatis操作數據庫,把配置文件配置好以后,就非常簡單了,就像在sql命令行直接輸入sql語句一樣。
要分清嵌套結果映射和嵌套結果查詢的區別。
* resultMap – 是最復雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。
* 一對一:重點掌握<association>標簽在嵌套結果映射和嵌套結果查詢中的使用
* 一對多:重點掌握<collection>標簽在嵌套結果映射和嵌套結果查詢中的使用
* 多對多:其實和一對多一樣使用,不過多了一個橋接表。
mybatis還有更強大的功能:動態sql,將會在下篇使用。同時還會介紹mybatis generator軟件【一款根據數據庫的表自動生成pojo類和sql映射文件】
如何想了解更多mybatis,可以去看文檔。中文文檔網址:http://www.mybatis.org/mybatis-3。