1.Mybatis 接口代理方式实现Dao层
2.Mybatis 映射配置文件-动态SQL
3.Mybatis 核心配置文件-分页插件
4.Mybatis 多表操作
1.Mybatis 接口代理方式实现Dao层
- 传统方式实现Dao层,我们即要写接口,还要写实现类,而MyBatis框架可以帮助我们省略编写Dao层接口实现类的步骤,程序员只需要编写接口,由MyBatis框架根据接口定义的来创建该接口的动态代理对象
- 实现规则
1.映射配置文件中的名称空间必须和Dao层接口的全类名相同
2.映射配置文件中的增删改查标签的id属性必须和Dao层接口的方法名相同
3.映射配置文件中的增删改查标签的 parameterType属性必须和Dao层接口方法的参数相同
4.映射配置文件中的增删改查标签的 resultType属性必须和Dao层接口方法的返回值相同- 接口代理方式-(代码实现)
1.删除mapper层接口的实现类
2.修改映射配置文件,其他配置不变
<mapper namespace="com.itheima.mapper.StudentMapper">
3.修改service层接口的实现类,采用接口代理方式实现功能
package com.itheima.service.Impl;
import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
import com.itheima.service.StudentService;
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 java.io.InputStream;
import java.util.List;
/*
业务层实现类
*/
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selectAll() {
List<Student> list = null;
SqlSession sqlSession = null;
InputStream is = null;
try {
//加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过实现类对象调用方法,接受结果
list = mapper.selectAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//返回结果
return list;
}
@Override
public Student selectById(Integer id) {
SqlSession sqlSession = null;
InputStream is = null;
Student student = null;
try {
//加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过实现类对象调用方法,接受结果
student = mapper.selectById(id);
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//返回结果
return student;
}
@Override
public Integer insert(Student stu) {
SqlSession sqlSession = null;
InputStream is = null;
Integer result = null;
try {
//加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过实现类对象调用方法,接受结果
result = mapper.insert(stu);
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//返回结果
return result;
}
@Override
public Integer update(Student stu) {
SqlSession sqlSession = null;
InputStream is = null;
Integer result = null;
try {
//加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过实现类对象调用方法,接受结果
result = mapper.update(stu);
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//返回结果
return result;
}
@Override
public Integer delete(Integer id) {
SqlSession sqlSession = null;
InputStream is = null;
Integer result = null;
try {
//加载核心配置文件
is = Resources.getResourceAsStream("MyBatisConfig.xml");
//获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//通过工厂对象获取SqlSession对象
sqlSession = sqlSessionFactory.openSession(true);
//获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过实现类对象调用方法,接受结果
result = mapper.delete(id);
} catch (Exception e) {
e.printStackTrace();
} finally {
//释放资源
if (sqlSession != null) {
sqlSession.close();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//返回结果
return result;
}
}
- 分析动态代理对象如何生成的?
通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过getMapper()方法最终获取到org.apache.ibatis.binding.MapperProxy代理对象,然后执行功能,而这个代理对象正是MyBatis使用了JDK的动态代理技术,帮助我们生成了代理实现类对象,从而可以进行相关持久化操作- 分析方法是如果执行的?
动态代理实现类对象执行方法的时候最终调用mapperMethod.execute()方法,这个方法中通过switch语句根据操作类型来判断是新增,修改,删除,查询操作,最后一步回到了MyBatis最原生的SqlSession方式执行增删改查
2.Mybatis 映射配置文件-动态SQL
- 动态SQL指的就是SQL语句可以根据条件或者参数的不同进行动态的变化
- 动态SQL标签
1.<if>: 条件判断标签
2.<where>: 条件标签,如果有动态条件,则使用该标签代替where关键字
<if test= "判断条件">
查询条件
</if>
<select id="selectCondition" resultType="student" parameterType="student">
<!--Select * from student WHERE id=#{id} and name =#{name} and age =#{age}-->
<!-- <where>标签就是替换sql语句中的where关键字的-->
Select * from student
<where>
<if test="id != null">
id =#{id}
</if>
<if test="name != null">
and name =#{name}
</if>
<if test="age != null">
and age =#{age}
</if>
</where>
</select>
3.<foreach>: 循环遍历标签,适用于多个参数或者的关系
<foreach collection="" open="" item="" separator="">
获取参数
</foreach>
属性
conllection: 参数容器类型,(list-集合,array-数组)
open: 开始的SQL语句
close: 结束的SQL语句
item: 参数变量名
separator: 分隔符
<!-- 查询多个id-->
<select id="forEach" resultType="student" parameterType="list">
<!-- Select * from student where id in (1,2,3)-->
Select * from student
<where>
<foreach collection="list" open="id in ( " close=")" item="id" separator=",">
#{id}
</foreach>
</where>
</select>
SQL 片段抽取>
- 将重复性的SQL语句进行抽取,以达到复用的效果
- <sql>: 抽取SQL语句标签
<sql id="片段唯一标识"> 抽取的SQL语句 </sql>
- <include>: 引入SQL片段标签
<sql refid="片段唯一标识"/>
- 映射配置文件中的抽取与引用
<sql id="select">Select * from student</sql>
<!-- 查询功能-->
<select id="selectAll" resultType="student">
<include refid="select"/>
</select>
3.Mybatis 核心配置文件-分页插件
- PageHelper: 第三方分页助手,将复杂的分页操作进行封装,从而让分页功能变得非常简单
- <plugins>: 集成插件标签
- 分页相关API
PageHelper: 分页助手功能类
startPage(): 设置分页参数 参数1:当前页 参数2:当前页显示的条数- 分页插件实现步骤
1.导入jar包
pagehelper-5.1.10.jar
jsqlparser-3.1.jar
2.在核心配置文件中集成分页助手插件
<!--集成分页助手插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3.在测试类中使用分页助手相关API实现分类功能
//通过分页助手实现分页功能
//第一页: 显示三条
//PageHelper.startPage(1,3);
//第二页:显示三条,以此类推
PageHelper.startPage(2,3);
List<Student> list = mapper.selectAll();
for (Student student : list) {
System.out.println(student);
}
//分页相关的参数
PageInfo<Student> info = new PageInfo<>(list);
System.out.println("总条数:"+info.getTotal());
System.out.println("总页数:"+info.getPages());
System.out.println("当前页:"+info.getPageNum());
System.out.println("每页显示的条数:"+info.getPageSize());
System.out.println("上一页:"+info.getPrePage());
System.out.println("下一页:"+info.getNextPage());
System.out.println("是否是第一页:"+info.isIsFirstPage());
System.out.println("是否是最后页:"+info.isIsLastPage());
分页插件相关参数
PageInfo: 封装分页相关参数的功能类
核心方法:
4.Mybatis 多表操作
多表模型分类
一对一: 在任意一方建立外键,关联对方主键
一对多: 在多的一方建立外键,关联一的一方主键
多对多: 借助中间表,中间表至少两个字段,分别关联两张表的主键
一对一
- <resultMap>: 配置字段和对象属性的映射关系标签
id属性: 唯一标识
type属性: 实体类对象类型- <id>: 配置主键映射关系标签
- <result>: 配置非主键映射关系标签
column属性: 表中字段名称
property属性: 实体对象变量名称- <association>: 配置被包含对象的映射关系标签
property属性: 被包含对象的变量名
javaType属性: 被包含对象的数据类型
- 封装类
// 空参有构造方法,get和set和toString()方法省略,
public class Card {
private Integer id;
private String number;
private Person P;
}
// 空参有参构造方法,get和set和toString()方法省略
public class Person {
private Integer id;
private String name;
private Integer age;
}
- 数据准备
CREATE DATABASE db12;
USE db12;
CREATE TABLE person(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20),
age INT
);
INSERT INTO person VALUES(NULL,'张三',23);
INSERT INTO person VALUES(NULL,'李四',24);
INSERT INTO person VALUES(NULL,'王五',25);
CREATE TABLE card (
id INT PRIMARY KEY AUTO_INCREMENT,
number VARCHAR(30),
pid INT,
CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id)
);
INSERT INTO card VALUES(NULL,'123123',1);
INSERT INTO card VALUES(NULL,'456456',2);
INSERT INTO card VALUES(NULL,'789789',3);
- 核心配置文件
<?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>
<!--引入数据库连接的配置文件-->
<properties resource="JDBC.properties"/>
<!--继承LOG4J日志信息-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--起别名-->
<typeAliases>
<!--<typeAlias type="com.itheima.bean" alias="***"/>-->
<!--给bean这个包下所有的包起一个别名,作为了解-->
<package name="com.itheima.bean"/>
</typeAliases>
<!--集成分页助手插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
<!--environments配置数据库环境,环境可以有多个,default属性指定使用的是哪个-->
<environments default="mysql">
<!--environment配置数据库环境 id属性代表唯一的标识-->
<environment id="mysql">
<!-- transactionManager事务的管理 type属性,采用JDBC默认的事务-->
<transactionManager type="JDBC"></transactionManager>
<!--dataSource数据源信息 type属性 连接池-->
<dataSource type="POOLED">
<!--property获取数据库连接的数据信息-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!--mappers引入映射文件-->
<mappers>
<!--mapper 引入指定的映射配置文件 resource属性: 指定映射配置文件的名称-->
<mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"></mapper>
</mappers>
</configuration>
- 映射配置文件
<?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.itheima.table01.OneToOneMapper">
<!--配置字段和实体对象属性的映射关系-->
<resultMap id="OneToOne" type="card">
<!--id标签是专门对主键进行配置的-->
<id column="cid" property="id"/>
<!--其他属性用result标签-->
<result column="number" property="number"/>
<!--
association: 配置被包含对象的映射关系
property: 被包含对象的变量名
javaType: 被包含对象的实际的数据类型
-->
<association property="P" javaType="person">
<id column="pid" property="id"/>
<result column="name" property="name"/>
<result column="age" property="age"/>
</association>
</resultMap>
<select id="selectAll" resultMap="OneToOne">
SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id
</select>
</mapper>
- 测试单元
public class Test01 {
@Test
public void selectAll() throws IOException {
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
OneToOneMapper mapper = sqlSession.getMapper(OneToOneMapper.class);
List<Card> cards = mapper.selectAll();
for (Card cs : cards) {
System.out.println(cs);
}
sqlSession.close();
is.close();
}
}
打印结果
一对多
- <collection>: 配置被包含集合对象的映射关系标签
property属性: 被包含集合对象的变量名
ofType属性: 集合中保存的对象数据类型
- 封装类
// 空参有构造方法,get和set和toString()方法省略,
public class Classes {
private Integer id; //主键id
private String name; //班级名称
private List<Student> students; //班级中所有学生对象
}
// 空参有构造方法,get和set和toString()方法省略,
public class Student {
private Integer id; //主键id
private String name; //学生新明
private Integer age; //学生年龄
}
- 数据准备
CREATE TABLE classes(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);
INSERT INTO classes VALUES(NULL,'一班');
INSERT INTO classes VALUES(NULL,'二班');
CREATE TABLE student(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(30),
age INT,
cid INT,
CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id)
);
INSERT INTO student VALUES(NULL,'张三',23,1);
INSERT INTO student VALUES(NULL,'李四',24,1);
INSERT INTO student VALUES(NULL,'王五',25,2);
INSERT INTO student VALUES(NULL,'赵六',26,2);
- 核心配置文件,只需添加映射文件路径
<mappers>
<!--mapper 引入指定的映射配置文件 resource属性: 指定映射配置文件的名称-->
<mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"></mapper>
<mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"></mapper>
</mappers>
- 映射配置文件
<?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.itheima.table02.OneToManyMapper">
<resultMap id="OnToMany" type="classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<!--
collection: 配置被包含的集合对象映射关系
property: 被包含对象的变量名
ofType: 被包含对象的实际数据类型
-->
<!--这里的ofType: 指的是list集合中保存的实际数据类型-->
<collection property="students" ofType="Student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
</collection>
</resultMap>
<select id="selectAll" resultMap="OnToMany">
SELECT c.id cid,c.name cname, s.id sid,s.name sname,s.age sage FROM classes c,student s WHERE c.id=s.cid;
</select>
</mapper>
- 接口类代码
package com.itheima.table02;
import com.itheima.bean.Classes;
import java.util.List;
public interface OneToManyMapper {
//查询全部的功能
public abstract List<Classes> selectAll();
}
- 测试单元代码
public class Test01 {
@Test
public void selectAll() throws IOException {
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class);
List<Classes> classes = mapper.selectAll();
for (Classes cs : classes) {
System.out.println(cs.getId()+","+cs.getName());
List<Student> students = cs.getStudents();
for (Student student : students) {
System.out.println(student);
}
}
sqlSession.close();
is.close();
}
}
- 测试结果
多对多
- 封装类
public class Student {
private Integer id; //主键id
private String name; //学生新明
private Integer age; //学生年龄
private List<Course> courses; //指当前学生所选择的课程集合
}
public class Course {
private Integer id; //主键id
private String name; //课程名称
}
- 数据准备
CREATE TABLE course(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);
INSERT INTO course VALUES(NULL,'语文');
INSERT INTO course VALUES(NULL,'数学');
CREATE TABLE stu_cr(
id INT PRIMARY KEY AUTO_INCREMENT,
sid INT,
cid INT,
CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id),
CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)
);
INSERT INTO stu_cr VALUES(NULL,1,1);
INSERT INTO stu_cr VALUES(NULL,1,2);
INSERT INTO stu_cr VALUES(NULL,2,1);
INSERT INTO stu_cr VALUES(NULL,2,2);
- 接口
public interface ManyToManyMapper {
//查询全部的功能
public abstract List<Student> selectAll();
}
- 映射配置文件
<?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.itheima.table03.ManyToManyMapper">
<resultMap id="manyToMany" type="student">
<id column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="sage" property="age"/>
<collection property="courses" ofType="course">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
</collection>
</resultMap>
<select id="selectAll" resultMap="manyToMany">
SELECT sc.sid ,s.name sname ,s.age sage,sc.cid ,c.name cname FROM student s,course c, stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id;
</select>
</mapper>
- 核心配置文件只需添加,映射配置文件路径
<!--mappers引入映射文件-->
<mappers>
<!--mapper 引入指定的映射配置文件 resource属性: 指定映射配置文件的名称-->
<mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"></mapper>
<mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"></mapper>
<mapper resource="com/itheima/many_to_many/ManyToManyMapper.xml"></mapper>
</mappers>
- 测试单元
@Test
public void selectAll() throws IOException {
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
SqlSession sqlSession = sqlSessionFactory.openSession(true);
ManyToManyMapper mapper = sqlSession.getMapper(ManyToManyMapper.class);
List<Student> studentList = mapper.selectAll();
for (Student student : studentList) {
System.out.println(student.getId()+","+student.getName()+","+student.getAge());
List<Course> courses = student.getCourses();
for (Course cours : courses) {
System.out.println("/t"+cours);
}
}
sqlSession.close();
is.close();
}
}
- 测试结果