Day64 Mybatis的多表查詢、ResultMap、註解以及快取
阿新 • • 發佈:2019-02-18
mybatis的多表查詢
AutoMapping自動注入(預設):
概念:如果資料庫表的欄位和實體類的屬性名一致,則欄位的值自動賦值給實體類的屬性。 資料庫表設計: 學生表: 學號 姓名 年齡 教師編號 教師表: 教師編號 姓名 業務裝配方式:根據業務分開查詢其需要的資料,並將查詢的資料儲存到實體類中 一對一查詢: 示例 查詢學生及其教師資訊 先查詢所有的學生資訊 根據學生資訊中的老師編號查詢其對應的教師資訊,並存儲到該學生實體類的教師屬性中 注意: 學生實體類的設計中應該包含教師屬性 一對多查詢: 示例 查詢教師及其學生資訊 先查詢教師資訊 根據教師編號查詢其學生資訊,並將學生資訊儲存到教師實體類的學生集合屬性中 注意: 教師實體類的設計中應該包含集合型別的學生屬性 特點: 效率低下。 SQL語句執行了n+1條
ResultMap n+1方式:
resultMap屬性:
如果實體類的屬性名和表的欄位不一致,這也就需要
指明的將某個欄位的值賦值給實體類的指定的屬性。
在mapper.xml中使用ResultMap屬性進行指明賦值即可。
示例:
<resultMap type="student2" id="stu">
<id column="sid" property="sid2"/>
<!-- <result column="sname" property="sname"/> -->
<result column="sage" property="sage2"/>
<result column="tid" property="tid2"/>
</resultMap>
<select id="selStuResultMap" resultMap="stu">
select * from student
</select>
注意:ResultType和ResultMap選擇其中一個使用。
一對一查詢:
示例:查詢學生及其教師資訊
在mapper.xml檔案中宣告標籤語句完成查詢
select標籤中宣告sql語句查詢所有的學生資訊
使用標籤屬性ResultMap指明Student實體類屬性的teacher屬性的值執行一次查詢
程式碼:
<resultMap type="student" id="rm">
<!-- <id column="sid" property="sid"/>
<result column="sname" property="sname"/>
<result column="sage" property="sage"/> -->
<result column="tid" property="tid"/>
<association property="teacher" column="tid" select="com.bjsxt.mapper.TeacherMapper.selTeaById"></association>
</resultMap>
<select id="selStuRm" resultMap="rm">
select * from student
</select>
一對多查詢:
示例 查詢教師及其學生資訊
在mapper.xml中宣告標籤語句完成教師查詢
然後使用ReultMap屬性進行自定義賦值,同時指明學生集合屬性的查詢。
程式碼:
<resultMap type="teacher" id="rm">
<id column="tid" property="tid"/>
<result column="tnname" property="tname"/>
<collection property="ls" column="tid" select="com.bjsxt.mapper.StudentMapper.selStuByTid"></collection>
</resultMap>
<select id="selTeaRm" resultMap="rm">
select * from teacher
</select>
總結特點:
效率低下的。SQL語句執行了n+1條。
如果實體類的屬性是一個物件則在ResultMap中使用association 標籤即可
如果實體類的屬性是一個集合物件,則使用collection 標籤即可
ResultMap 聯合查詢方式:
一對一查詢:
示例 查詢學生及其教師資訊
<resultMap type="student" id="rms">
<id column="sid" property="sid"/>
<result column="sname" property="sname"/>
<result column="sage" property="sage"/>
<result column="tid" property="tid"/>
<association property="teacher" javaType="teacher">
<result column="tid" property="tid"/>
<result column="tname" property="tname"/>
</association>
</resultMap>
<select id="selStuUn" resultMap="rms">
select * from student s
left join teacher t
on s.tid=t.tid
</select>
一對多查詢:
示例:查詢教師及其學生資訊
<resultMap type="teacher" id="rt">
<id column="tid" property="tid"/>
<result column="tname" property="tname"/>
<collection property="ls" ofType="student">
<id column="sid" property="sid"/>
<result column="sname" property="sname"/>
<result column="sage" property="sage"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
<select id="selTeaUn" resultMap="rt">
select * from teacher t
left join student s
on t.tid=s.tid
</select>
Automapping多表注入
<!-- 一對一 查詢學生及其教師資訊 autoMapping注入 -->
<select id="selStuUn2" resultType="Student">
select s.*,t.tid `teacher.tid`,t.tname `teacher.tname` from student s
left join teacher t
on s.tid=t.tid
</select>
mybatis的註解
註解學習:
註解的作用(瞭解):
替代XML檔案配置的。
特點:
註解可以節省我們的工作量,但是耦合性比較高。
注意:
mybatis的註解和mapper.xml配置文集可以同時使用
示例:
//查詢所有的學生資訊
@Select("select * from student")
List<Student> selStu();
//根據ID查詢學生資訊
@Select("select * from student where sid=#{0}")
Student selStuById(int sid);
//插入一條學生資訊
@Insert("insert into student values(default,#{0},#{1},#{2})")
int insStu(String sname,int sage,int tid);
//刪除一條學生資訊
@Delete("delete from student where sid=#{0}")
int delStu(int sid);
快取
一級快取:(SqlSession)
當SqlSession物件完成資料庫操作後,會將此次操作的資料庫命令物件(preparedStatement)放入快取中,
以後執行相同的mapper.xml中配置的標籤時,直接從快取獲取即可。
二級快取:(Factory快取)
第一步:
在mapper.xml檔案中使用標籤開啟:
<cache readOnly="true"></cache>
第二步:
SqlSession物件在Close的時候會將其快取的資料重新整理到Factory快取中
其他知識點:
其他知識點:
資料庫設計:
表關係設計:
一對多 :主外來鍵關聯 有外來鍵的是子表
多對多 :通過中間表
查詢結果集的處理:
相當於原生JDBC的while()迴圈對結果集的賦值。
實體類設計: 把一個實體類根據業務需求作為另一個實體類的屬性。
業務裝配模式: 效率低下 ,SQL語句簡單,分開查詢
使用JAVA程式碼進行邏輯判斷,在一條SQL語句查詢時候呼叫另一條查詢語句。
ResultMap n+1方式: 效率低下,但完全解耦,有關聯的列必須寫,沒關聯的列可以省略。SQL語句簡單,分開查詢
在XML檔案中用標籤進行邏輯判斷賦值
ResultMap 多表聯合查詢: SQL語句複雜。但效率高。
使用SQL多表聯合查詢語句替代邏輯判斷。
在ResultMap 裡進行一對一,和一對多的標籤操作進行對欄位進行賦值。
ResultType 和ResultMap不能同時使用
ResultMap 相關欄位解釋:
https://blog.csdn.net/wxwzy738/article/details/24742495
Type:該條資料返回值型別
id:和select 的ResultMap的值同名。
Id標籤 :一般為表的主鍵
column:資料庫欄位名
property:實體類屬性
Result標籤:一般為表字段賦值
column:資料庫欄位名
property:實體類屬性
Association標籤: 適用於一對一,也就是連線的表查詢條件是一個物件的資料,比如一個學生對應一個教師,如果是多表查詢,可以在該標籤裡面用ID和Result標籤給連線表賦值
column:資料庫欄位名 (單表查詢)
property:實體類屬性
select:需要呼叫查詢語句的全限定路徑,包名到查詢語句名 (單表查詢使用這個繼續查另一個表)
JavaType:完整java類名或別名 (聯合查詢)
Collection標籤:適用於一對多,也就是連線的表是一個集合。比如一個教師對應多個學生
可以在該標籤裡面用ID和Result標籤給連線表賦值
column:資料庫欄位名 (單表查詢)
property:實體類屬性
select:需要呼叫查詢語句的全限定路徑,包名到查詢語句名 (單表查詢使用這個繼續查另一個表)
OfType: 連線表的完整java類名或別名 (聯合查詢)
JavaType和OfType的區別:
JavaType和ofType都是用來指定物件型別的,但是JavaType是用來指定pojo中屬性的型別,而ofType指定的是對映到list集合屬性中pojo的型別。都是指定物件的型別 不同的是當使用反向查詢select從另一個maper檔案中取出資料時必須用ofType
使用註解進行單表查詢比使用XML方式簡單。但是對於多表查詢不建議用註解方式進行查詢,註解大大阻礙瞭解耦。
快取:
細節:
注意mybatis裡要掃描mapper包
select 要寫 resultType 代表的是每條語句的返回值型別
對應的接口裡的方法裡的寫的是整個結果集用什麼去存,介面方法要與xml裡的查詢方法ID同名。
小案例:
需求:
資料庫設計:
學生表:
CREATE TABLE student
(
sid
int(10) NOT NULL AUTO_INCREMENT,
sname
varchar(100) NOT NULL,
sage
int(3) NOT NULL,
tid
int(10) NOT NULL,
PRIMARY KEY (sid
)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
教師表:
CREATE TABLE teacher
(
tid
int(10) NOT NULL,
tname
varchar(100) NOT NULL,
PRIMARY KEY (tid
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
匯入Mybatis相關jar包 Gson jar包 js1.9 log4j jar包
配置XML檔案
搭建環境,建包,寫程式碼
src:
mybatis.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<typeAliases>
<package name="com.bjsxt.pojo"/>
</typeAliases>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC"></transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<mappers>
<package name="com.bjsxt.mapper"/>
</mappers>
</configuration>
log4j.properties:
log4j.rootCategory=info
log4j.logger.com.bjsxt.mapper=debug, CONSOLE
log4j.logger.com.bjsxt.serviceImpl=debug, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=- %c-%d-%m%n
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=- %c-%d-%m%n
com.bjsxt.mapper:
ShowMapper.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.bjsxt.mapper.ShowMapper">
<!--
分頁查詢學生及其教師資訊
-->
<resultMap type="student" id="rs">
<id column="sid" property="sid"/>
<result column="sname" property="sname"/>
<result column="sage" property="sage"/>
<result column="tid" property="tid"/>
<association property="teacher" javaType="teacher">
<result column="tid" property="tid"/>
<result column="tname" property="tname"/>
</association>
</resultMap>
<select id="selStu" resultMap="rs">
select * from student s
left join teacher t
on s.tid=t.tid
<where>
<if test="param1 !='' and param1 !=null">
<bind name="sa" value="'%'+param1+'%'"/>
and sname like #{sa}
</if>
<if test="param2 !='' and param2 !=null">
<bind name="ta" value="'%'+param2+'%'"/>
and tname like #{ta}
</if>
</where>
limit #{param3},#{param4}
</select>
</mapper>
ShowMapper.java:
package com.bjsxt.mapper;
import java.util.List;
import com.bjsxt.pojo.Student;
public interface ShowMapper {
/**
* 分頁查詢學生及其教師資訊
* @param tname
* @param sname
* @param pageStart
* @param pageSize
* @return
*/
List<Student> selStu(String sname, String tname, int pageStart,int pageSize);
}
com.bjsxt.pojo:
Student.java:
package com.bjsxt.pojo;
public class Student {
private int sid;
private String sname;
private int sage;
private int tid;
private Teacher teacher;
public int getSid() {
return sid;
}
public void setSid(int sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getSage() {
return sage;
}
public void setSage(int sage) {
this.sage = sage;
}
public int getTid() {
return tid;
}
public void setTid(int tid) {
this.tid = tid;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", sage=" + sage + ", tid=" + tid + ", teacher=" + teacher
+ "]";
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int sid, String sname, int sage, int tid, Teacher teacher) {
super();
this.sid = sid;
this.sname = sname;
this.sage = sage;
this.tid = tid;
this.teacher = teacher;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + sage;
result = prime * result + sid;
result = prime * result + ((sname == null) ? 0 : sname.hashCode());
result = prime * result + ((teacher == null) ? 0 : teacher.hashCode());
result = prime * result + tid;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (sage != other.sage)
return false;
if (sid != other.sid)
return false;
if (sname == null) {
if (other.sname != null)
return false;
} else if (!sname.equals(other.sname))
return false;
if (teacher == null) {
if (other.teacher != null)
return false;
} else if (!teacher.equals(other.teacher))
return false;
if (tid != other.tid)
return false;
return true;
}
}
Teacher.java:
package com.bjsxt.pojo;
public class Teacher {
private int tid;
private String tname;
public int getTid() {
return tid;
}
public void setTid(int tid) {
this.tid = tid;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
@Override
public String toString() {
return "Teacher [tid=" + tid + ", tname=" + tname + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + tid;
result = prime * result + ((tname == null) ? 0 : tname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Teacher other = (Teacher) obj;
if (tid != other.tid)
return false;
if (tname == null) {
if (other.tname != null)
return false;
} else if (!tname.equals(other.tname))
return false;
return true;
}
public Teacher() {
super();
// TODO Auto-generated constructor stub
}
public Teacher(int tid, String tname) {
super();
this.tid = tid;
this.tname = tname;
}
}
PageInfo.java:
package com.bjsxt.pojo;
import java.util.List;
public class PageInfo {
private int pageNum;
private int pageSize;
private List<Student> ls;
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public List<Student> getLs() {
return ls;
}
public void setLs(List<Student> ls) {
this.ls = ls;
}
@Override
public String toString() {
return "PageInfo [pageNum=" + pageNum + ", pageSize=" + pageSize + ", ls=" + ls + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((ls == null) ? 0 : ls.hashCode());
result = prime * result + pageNum;
result = prime * result + pageSize;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PageInfo other = (PageInfo) obj;
if (ls == null) {
if (other.ls != null)
return false;
} else if (!ls.equals(other.ls))
return false;
if (pageNum != other.pageNum)
return false;
if (pageSize != other.pageSize)
return false;
return true;
}
public PageInfo() {
super();
// TODO Auto-generated constructor stub
}
public PageInfo(int pageNum, int pageSize, List<Student> ls) {
super();
this.pageNum = pageNum;
this.pageSize = pageSize;
this.ls = ls;
}
}
com.bjsxt.service:
ShowService.java:
package com.bjsxt.service;
import java.io.IOException;
import com.bjsxt.pojo.PageInfo;
public interface ShowService {
/**
* 根據pageNum和pageSize獲取學生分頁資料
* @param pageNum
* @param pageSize
* @param tname
* @param sname
* @return
*/
PageInfo getStuInfoService(int pageNum,int pageSize, String sname, String tname)throws IOException ;
}
com.bjsxt.serviceImpl:
ShowServiceImpl.java:
package com.bjsxt.serviceImpl;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.bjsxt.mapper.ShowMapper;
import com.bjsxt.pojo.PageInfo;
import com.bjsxt.pojo.Student;
import com.bjsxt.service.ShowService;
public class ShowServiceImpl implements ShowService{
@Override
public PageInfo getStuInfoService(int pageNum,int pageSize, String sname, String tname) throws IOException {
//獲取SqlSession物件
InputStream is = Resources.getResourceAsStream("mybatis.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(is);
SqlSession ss=factory.openSession();
//獲取mapper介面物件
ShowMapper sm=ss.getMapper(ShowMapper.class);
//換算分頁查詢起始點
int pageStart=pageNum*pageSize-pageSize;
//查詢資料
List<Student> ls=sm.selStu(sname,tname,pageStart, pageSize);
//將資料儲存到pageInfo物件中
PageInfo p=new PageInfo();
p.setPageNum(pageNum);
p.setPageSize(pageSize);
p.setLs(ls);
return p;
}
}
com.bjsxt.servlet:
ShowServlet.java:
package com.bjsxt.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.bjsxt.pojo.PageInfo;
import com.bjsxt.service.ShowService;
import com.bjsxt.serviceImpl.ShowServiceImpl;
import com.google.gson.Gson;
/**
* Servlet implementation class ShowServlet
*/
@WebServlet("/show")
public class ShowServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//設定請求編碼格式
req.setCharacterEncoding("utf-8");
//設定響應編碼格式
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//獲取請求資訊
int pageNum=Integer.parseInt(req.getParameter("pageNum"));
int pageSize=Integer.parseInt(req.getParameter("pageSize"));
String sname=req.getParameter("sname");
String tname=req.getParameter("tname");
//處理請求資訊
//建立業務層物件
ShowService ss=new ShowServiceImpl();
PageInfo p=ss.getStuInfoService(pageNum, pageSize,sname,tname);
//響應處理結果
resp.getWriter().write(new Gson().toJson(p));
}
}
WebContext:
show.jsp:
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
<!--引入jQuery檔案 -->
<script type="text/javascript" src="js/j.js"></script>
<!--宣告js程式碼域 -->
<script type="text/javascript">
$(function(){
//宣告變數記錄當前頁碼數
var pn;
//頁面載入呼叫getData獲取第一個資料
getData(1,2);
//給查詢按鈕新增事件
$("#btn").click(function(){
$("input[type=radio]").each(function(){
if(this.value==2){
this.checked=true
}else{
this.checked=false;
}
})
getData(1,2);
})
//給上一頁新增事件
$("#up").click(function(){
getData(pn-1,2);
})
//給下一頁新增事件
$("#down").click(function(){
getData(pn+1,2);
})
//給radio單選按鈕新增事件
$("input[type=radio]").click(function(){
getData(1,$(this).val());
})
//封裝ajax請求
function getData(pageNum,pageSize){
//傳送ajax請求 請求第一頁的資料
$.get("show",{pageNum:pageNum,pageSize:pageSize,sname:$("#sname").val(),tname:$("#tname").val()},function(data){
//使用eval方法將資料轉換為js物件
eval("var p="+data);
pn=p.pageNum;
//獲取表格物件
var ta=$("#ta");
ta.empty();
ta.append("<tr height='35px'>"+
"<td width='100px'>編號</td>"+
"<td width='100px'>學生姓名</td>"+
"<td width='100px'>年齡</td>"+
"<td width='100px'>教師姓名</td>"+
"</tr>");
//遍歷,將資料填充到表格中
for(var i=0;i<p.ls.length;i++){
ta.append("<tr height='35px'>"+
"<td width='100px'>"+p.ls[i].sid+"</td>"+
"<td width='100px'>"+p.ls[i].sname+"</td>"+
"<td width='100px'>"+p.ls[i].sage+"</td>"+
"<td width='100px'>"+p.ls[i].teacher.tname+"</td>"+
"</tr>");
}
})
}
})
</script>
</head>
<body>
<input type="radio" id="" name="page" value="2" checked="checked"/>2
<input type="radio" id="" name="page" value="3"/>3
<input type="radio" id="" name="page" value="4"/>4
<br />
學生姓名:<input