Mybatis【一對多、多對一、多對多】知識要點

Java3y發表於2018-03-13

Mybatis【多表連線】

我們在學習Hibernate的時候,如果表涉及到兩張的話,那麼我們是在對映檔案中使用<set>..<many-to-one>等標籤將其的對映屬性關聯起來的...那麼在我們Mybatis中又怎麼做呢???

先來回顧一下我們SQL99的語法:


一)內連線(等值連線):查詢客戶姓名,訂單編號,訂單價格
    ---------------------------------------------------
    select c.name,o.isbn,o.price
    from customers c inner join orders o
    where c.id = o.customers_id;
    ---------------------------------------------------
    select c.name,o.isbn,o.price
    from customers c join orders o
    where c.id = o.customers_id; 
    ---------------------------------------------------
    select c.name,o.isbn,o.price
    from customers c,orders o
    where c.id = o.customers_id;
    ---------------------------------------------------
    select c.name,o.isbn,o.price
    from customers c join orders o
    on c.id = o.customers_id;
    ---------------------------------------------------
    注意:內連線(等值連線)只能查詢出多張表中,連線欄位相同的記錄




二)外連線:按客戶分組,查詢每個客戶的姓名和訂單數
    ---------------------------------------------------
    左外連線:
    select c.name,count(o.isbn)
    from  customers c left outer join orders o
    on c.id = o.customers_id
    group by c.name; 
    ---------------------------------------------------
    右外連線:
    select c.name,count(o.isbn)
    from  orders o right outer join customers c   
    on c.id = o.customers_id
    group by c.name; 
    ---------------------------------------------------
    注意:外連線既能查詢出多張表中,連線欄位相同的記錄;又能根據一方,將另一方不符合相同記錄強行查詢出來




三)自連線:求出AA的老闆是EE
    ---------------------------------------------------
    內自連線:
    select users.ename,boss.ename
    from emps users inner join emps boss 
    on users.mgr = boss.empno;
    ---------------------------------------------------
    外自連線:
    select users.ename,boss.ename
    from emps users left outer join emps boss 
    on users.mgr = boss.empno;
    ---------------------------------------------------
    注意:自連線是將一張表,通過別名的方式,看作多張表後,再進行連線。
	  這時的連線即可以採用內連線,又可以採用外連線

複製程式碼

由於我們Mybatis中並沒有像Hibernate這樣全自動化的,因此我們是沒有<set>..<many-to-one>等標籤的,我們還是使用手寫SQL語句來使我們的關聯屬性連線起來...

一對一

需求:

  • 學生和身份證

這裡寫圖片描述

設計表:



--mysql

create table cards(
	cid int(5) primary key,
	cnum varchar(10)
);

create table students(
	sid int(5) primary key,
	sname varchar(10),
	scid int(5),
	constraint scid_fk foreign key(scid) references cards(cid)
);

insert into cards(cid,cnum) values(1,'111');
insert into students(sid,sname,scid) values(1,'哈哈',1);

select * from cards;
select * from students;


複製程式碼

實體

/**
 * 身份證(單方)
 * @author AdminTC
 */
public class Card {
	private Integer id;
	private String num;
	public Card(){}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getNum() {
		return num;
	}
	public void setNum(String num) {
		this.num = num;
	}
}

複製程式碼

/**
 * 學生(單方)
 * @author AdminTC
 */
public class Student {
	private Integer id;
	private String name;
	private Card card;//關聯屬性
	public Student(){}
	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 Card getCard() {
		return card;
	}
	public void setCard(Card card) {
		this.card = card;
	}
}

複製程式碼

對映檔案

由於我們有兩個實體,因此我們會有兩個對映檔案

Student對映檔案


<?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="studentNamespace">
	
	<resultMap type="zhongfucheng2.Student" id="studentMap">
		<id property="id" column="sid"/>
		<result property="name" column="sname"/>
	</resultMap>
</mapper>

複製程式碼

Card對映檔案



<?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="cardNamespace">
	
	<resultMap type="zhongfucheng2.Card" id="cardMap">
		<id property="id" column="cid"/>
		<result property="num" column="cnum"/>
	</resultMap>	
	
</mapper>

複製程式碼

DAO層

現在我想根據學生的編號查詢學生的資訊和身份證資訊

由於該查詢著重是查詢學生的資訊,於是我們在學生的對映檔案中寫SQL語句

按照需求,我們寫出來的SQL語句是這樣子的。



select * from zhongfucheng.students s,zhongfucheng.cards c where c.cid = s.scid and sid=1;

複製程式碼

我來看一下查詢結果:

這裡寫圖片描述

我們的實體與對映表中,Student實體是沒有關聯其他的欄位的,僅僅是寫出了該實體的自帶的屬性


	<resultMap type="zhongfucheng2.Student" id="studentMap">
		<id property="id" column="sid"/>
		<result property="name" column="sname"/>
	</resultMap>

複製程式碼

明顯地,我們Student是不能封裝返回的結果,因此我們需要將關聯屬性進行關聯起來!


	<resultMap type="zhongfucheng2.Student" id="studentMap">
		<id property="id" column="sid"/>
		<result property="name" column="sname"/>

		<!--
			property寫的是在Student實體中寫關聯欄位的屬性變數名稱
			resultMap寫的是對映檔案中的名稱空間.id
		-->
		<association property="card" resultMap="cardNamespace.cardMap"/>
	</resultMap>
複製程式碼

我們關聯了以後,Student實體就能夠封裝返回的結果了


	<resultMap type="zhongfucheng2.Student" id="studentMap">
		<id property="id" column="sid"/>
		<result property="name" column="sname"/>

		<!--
			property寫的是在Student實體中寫關聯欄位的屬性變數名稱
			resultMap寫的是對映檔案中的名稱空間.id
		-->
		<association property="card" resultMap="cardNamespace.cardMap"/>
	</resultMap>

	<select id="findById" parameterType="int" resultMap="studentMap">
		select * from zhongfucheng.students s,zhongfucheng.cards c where c.cid = s.scid and sid=#{id};
	</select>
複製程式碼

查詢編號為1的學生資訊【包括身份證編號】



    public Student findById(int id) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{

            return sqlSession.selectOne("studentNamespace.findById", id);

          /*  sqlSession.commit();*/
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }

    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        Student student = studentDao.findById(1);

        System.out.println(student.getId() + "----" + student.getName() + "----" + student.getCard().getNum());

    }
複製程式碼

這裡寫圖片描述


一對多

需求:

  • 一個班級有多個學生,查詢java學科有哪些學生資訊

這裡寫圖片描述

設計資料庫表



create table grades(
  gid int(5) primary key,
  gname varchar(10)
);

create table students(
  sid int(5) primary key,
  sname varchar(10),
  sgid int(5),
  constraint sgid_fk foreign key(sgid) references grades(gid)
);

insert into grades(gid,gname) values(1,'java');

insert into students(sid,sname,sgid) values(1,'哈哈',1);
insert into students(sid,sname,sgid) values(2,'呵呵',1);


select * from grades;
select * from students;


複製程式碼

實體


package zhongfucheng2;

import java.util.ArrayList;
import java.util.List;

/**
 * 學科(單方)
 * @author AdminTC
 */
public class Grade {
	private Integer id;
	private String name;
	private List<Student> studentList = new ArrayList<Student>();//關聯屬性
	public Grade(){}
	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 List<Student> getStudentList() {
		return studentList;
	}
	public void setStudentList(List<Student> studentList) {
		this.studentList = studentList;
	}
}



複製程式碼

package zhongfucheng2;

/**
 * 學生(多方)
 * @author AdminTC
 */
public class Student {
	private Integer id;
	private String name;
	private Grade grade;//關聯屬性
	public Student(){}
	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 Grade getGrade() {
		return grade;
	}
	public void setGrade(Grade grade) {
		this.grade = grade;
	}
}

複製程式碼

對映檔案SQL語句




<mapper namespace="studentNamespace">
	
	<resultMap type="zhongfucheng2.Student" id="studentMap">
		<id property="id" column="sid"/>
		<result property="name" column="sname"/>
	</resultMap>


	<!--查詢選修的java學科有多少位學生-->

	<!--由於我們只要查詢學生的名字,而我們的實體studentMap可以封裝學生的名字,那麼我們返回studentMap即可,並不需要再關聯到學科表-->
	<select id="findByGrade" parameterType="string" resultMap="studentMap">

		select s.sname,s.sid from zhongfucheng.students s,zhongfucheng.grades g WHERE s.sgid=g.gid and g.gname=#{name};


	</select>

</mapper>



<?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="gradeNamespace">
	
	<resultMap type="zhongfucheng2.Grade" id="gradeMap">
		<id property="id" column="gid"/>
		<result property="name" column="gname"/>
	</resultMap>
</mapper>


複製程式碼

DAO


public List<Student> findByGrade(String  grade) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{

            return sqlSession.selectList("studentNamespace.findByGrade", grade);
          /*  sqlSession.commit();*/
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }

    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        List<Student> student = studentDao.findByGrade("java");

        for (Student student1 : student) {
            System.out.println(student1.getName());
        }
    }
複製程式碼

這裡寫圖片描述

多對多

需求:

  • 學生和課程

這裡寫圖片描述

資料庫表


create table students(
	sid int(5) primary key,
	sname varchar(10)
);

create table courses(
	cid int(5) primary key,
	cname varchar(10)
);

create table middles(
	msid int(5),
	mcid int(5),
	primary key(msid,mcid)
);

insert into students(sid,sname) values(1,'哈哈');
insert into students(sid,sname) values(2,'呵呵');

insert into courses(cid,cname) values(1,'java');
insert into courses(cid,cname) values(2,'android');

insert into middles(msid,mcid) values(1,1);
insert into middles(msid,mcid) values(1,2);
insert into middles(msid,mcid) values(2,1);
insert into middles(msid,mcid) values(2,2);

select * from students;
select * from courses;
select * from middles;


複製程式碼

實體

package cn.itcast.javaee.mybatis.many2many;

import java.util.ArrayList;
import java.util.List;

/**
 * 課程(多方)
 * @author AdminTC
 */
public class Course {
	private Integer id;
	private String name;
	private List<Student> studentList = new ArrayList<Student>();//關聯屬性
	public Course(){}
	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 List<Student> getStudentList() {
		return studentList;
	}
	public void setStudentList(List<Student> studentList) {
		this.studentList = studentList;
	}
}



複製程式碼

package cn.itcast.javaee.mybatis.many2many;

import java.util.ArrayList;
import java.util.List;

/**
 * 學生(多方)
 * @author AdminTC
 */
public class Student {
	private Integer id;
	private String name;
	private List<Course> courseList = new ArrayList<Course>();//關聯屬性
	public Student(){}
	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 List<Course> getCourseList() {
		return courseList;
	}
	public void setCourseList(List<Course> courseList) {
		this.courseList = courseList;
	}
}

複製程式碼

對映檔案


<?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="courseNamespace">
	
	<resultMap type="cn.itcast.javaee.mybatis.many2many.Course" id="courseMap">
		<id property="id" column="cid"/>
		<result property="name" column="cname"/>
	</resultMap>	
	
	
	
	<!-- 查詢哈哈選學了哪些課程 -->
	<select id="findAllByName" parameterType="string" resultMap="courseMap">
		select c.cid,c.cname
		from students s inner join middles m
		on s.sid = m.msid
		inner join courses c
		on m.mcid = c.cid
		and s.sname = #{name}
	</select>
	
</mapper>



複製程式碼

<?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="studentNamespace">
	
	<resultMap type="cn.itcast.javaee.mybatis.many2many.Student" id="studentMap">
		<id property="id" column="sid"/>
		<result property="name" column="sname"/>
	</resultMap>	

	
	<select id="findAllByCourseName" parameterType="string" resultMap="studentMap">
		select s.sname
		from students s inner join middles m
		on s.sid = m.msid 
		inner join courses c
		on m.mcid = c.cid
		and c.cname = #{name}
	</select>
	
</mapper>



複製程式碼

DAO



package cn.itcast.javaee.mybatis.many2many;

import java.util.List;
import org.apache.ibatis.session.SqlSession;
import cn.itcast.javaee.mybatis.util.MybatisUtil;

/**
 * 持久層
 * @author AdminTC
 */
public class StudentCourseDao {
	/**
	 * 查詢哈哈選學了哪些課程
	 * @param name 表示學生的姓名
	 */
	public List<Course> findAllByName(String name) throws Exception{
		SqlSession sqlSession = null;
		try{
			sqlSession = MybatisUtil.getSqlSession();
			return sqlSession.selectList("courseNamespace.findAllByName",name);
		}catch(Exception e){
			e.printStackTrace();
			throw e;
		}finally{
			MybatisUtil.closeSqlSession();
		}
	}
	/**
	 * 查詢java課程有哪些學生選修
	 * @param name 表示學生的課程
	 */
	public List<Student> findAllByCourseName(String name) throws Exception{
		SqlSession sqlSession = null;
		try{
			sqlSession = MybatisUtil.getSqlSession();
			return sqlSession.selectList("studentNamespace.findAllByCourseName",name);
		}catch(Exception e){
			e.printStackTrace();
			throw e;
		}finally{
			MybatisUtil.closeSqlSession();
		}
	}
	
	
	
	
	
	
	public static void main(String[] args) throws Exception{
		StudentCourseDao dao = new StudentCourseDao();
		List<Course> courseList = dao.findAllByName("哈哈");
		System.out.print("哈哈選學了" + courseList.size()+"個課程,分別是:");
		for(Course c : courseList){
			System.out.print(c.getName()+" ");
		}
		System.out.println("\n-----------------------------------------------------");
		List<Student> studentList = dao.findAllByCourseName("android");
		System.out.println("選修了android課程的學生有"+studentList.size()+"個,分別是:");
		for(Student s : studentList){
			System.out.print(s.getName()+" ");
		}
	}
}


複製程式碼

總結

對於Mybatis的多表連線就非常簡單了,由於SQL語句全是由我們自己寫,如果我們返回的資料型別在當前的實體中是不夠封裝的話,那麼我們只要再關聯對應的對映屬性就行了


如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y

相關文章