java web(六):mybatis之一對一、一對多、多對多映射


前言:

  百度百科:

    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 + "]";
    }
    
    
    
    
}
View Code

   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 + "]";
    }
    
}
View Code

 

 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);
}
View Code

     單元測試類:

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();
        }
    }
}
View Code

     獲得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 + "]";
    }

    
}
View Code

 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 + "]";
    }
    
}
View Code

 

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);
}
View Code

 

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();
        }
    }
}
View Code

 

 


                多對多 

描述:一個老師可以講多門課,一門課可以有多個老師教。

 

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 + "]";
    }
    
    
}
View Code

 

 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 + "]";
    }
    
    
}
View Code

 

橋表類: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 + "]";
    }
    
}
View Code

 

 

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);
}
View Code

 

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();
        }
    }
}
View Code

 


 總結:

  使用mybatis操作數據庫,把配置文件配置好以后,就非常簡單了,就像在sql命令行直接輸入sql語句一樣。

 要分清嵌套結果映射和嵌套結果查詢的區別。

  * resultMap – 是最復雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。

  * 一對一:重點掌握<association>標簽在嵌套結果映射和嵌套結果查詢中的使用

  * 一對多:重點掌握<collection>標簽在嵌套結果映射和嵌套結果查詢中的使用

  * 多對多:其實和一對多一樣使用,不過多了一個橋接表。

 mybatis還有更強大的功能:動態sql,將會在下篇使用。同時還會介紹mybatis  generator軟件【一款根據數據庫的表自動生成pojo類和sql映射文件】

 

  如何想了解更多mybatis,可以去看文檔。中文文檔網址:http://www.mybatis.org/mybatis-3。


免責聲明!

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



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