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 type="text" id="sname"/>
教师姓名: <input type="text" id="tname"/>
<input type="button" id="btn" value="查询"/>
<hr />
<table border="1px" cellpadding="0" cellspacing="0" id="ta"></table>
<a href="javascript:void(0)" id="up">上一页</a>
<a href="javascript:void(0)" id="down">下一页</a>
</body>
</html>
源码:
链接:https://pan.baidu.com/s/1zPvko3yKRELiQIMREhXekg 密码:9om2
小结:
Mybatis的多表查询
注解
缓存
其他知识点
小案例