接口代理、动态SQL、分页、多表操作
一. 接口代理方式实现Dao
1. 使用注意
(1)映射配置文件中的名称空间要和接口的全类名相同
(2)映射配置文件中标签的id属性值要和接口的方法名相同 形象比喻为namespace+id=接口全类名+方法名
(3)映射配置文件中标签的parameterType属性值要和方法的参数类型一致
(4)映射配置文件中标签的resultType属性值要和方法的返回值类型一致
2. 代码演示
2.1 删除mapper层接口实现类
/*
持久层接口
*/
public interface StudentMapper {
//查询全部
public abstract List<Student> selectAll();
//根据id查询
public abstract Student selectById(Integer id);
//新增数据
public abstract Integer insert(Student stu);
//修改数据
public abstract Integer update(Student stu);
//删除数据
public abstract Integer delete(Integer id);
//多条件查询
public abstract List<Student> selectCondition(Student stu);
//根据多个id查询
public abstract List<Student> selectByIds(List<Integer> ids);
}
2.2 修改映射配置文件(StudentMapper.xml)
只需要修改配置文件中名称空间为接口的全类名
<mapper namespace="com.itheima.mapper.StudentMapper">
<!--id必须是接口的方法名-->
<!--查询所有学生信息-->
<select id="selectAll" resultType="student">
select * from student
</select>
<!--根据id查询学生信息-->
<select id="selectById" parameterType="int" resultType="student">
select * from student where id=#{ID}
</select>
<!--添加学生-->
<insert id="insert" parameterType="student">
insert into student values(null,#{name},#{age})
</insert>
<!--修改学生信息-->
<update id="update" parameterType="student">
update student set name=#{name},age=#{age} where id=#{id}
</update>
<!--删除学生信息-->
<delete id="delete" parameterType="int">
delete from student where id=#{id}
</delete>
</mapper>
2.3 修改service层实现类
public class StudentServiceImpl implements StudentService {
@Override
public List<Student> selectAll() {
//1.获取SqlSession对象(使用自定义的工具类获取)
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//2.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//3.通过实现类对象中的方法来完成操作
List<Student> list = mapper.selectAll();
//4.释放资源
sqlSession.close();
//5.返回结果
return list;
}
@Override
public Student selectById(Integer id) {
//1.获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//2.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//3.通过实现类对象中的方法来完成操作
Student stu = mapper.selectById(id);
//4.释放资源
sqlSession.close();
//5.返回结果
return stu;
}
@Override
public Integer insert(Student stu) {
//1.获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//2.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//3.通过实现类对象中的方法来完成操作
Integer result = mapper.insert(stu);
//4.释放资源
sqlSession.close();
//5.返回结果
return result;
}
@Override
public Integer update(Student stu) {
//1.获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//2.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//3.通过实现类对象中的方法来完成操作
Integer result = mapper.update(stu);
//4.释放资源
sqlSession.close();
//5.返回结果
return result;
}
@Override
public Integer delete(Integer id) {
//1.获取SqlSession对象
SqlSession sqlSession = MyBatisUtils.getSqlSession();
//2.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//3.通过实现类对象中的方法来完成操作
Integer result = mapper.delete(id);
//4.释放资源
sqlSession.close();
//5.返回结果
return result;
}
}
二. 动态SQL(理解)
1. 使用场景
搜索、筛选…
2. if标签判断
2.1 配置SQL
<!--多条件查询-->
<select id="selectCondition" resultType="student" parameterType="student">
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>
2.2 测试
@Test
public void selectCondition() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student stu = new Student();
stu.setId(2);
//stu.setName("李四");
//stu.setAge(24);
//5.调用实现类的方法,接收结果
List<Student> list = mapper.selectCondition(stu);
//6.处理结果
for (Student student : list) {
System.out.println(student);
}
//7.释放资源
sqlSession.close();
is.close();
}
3. foreach标签遍历
3.1 配置SQL
<!--多条件查询-->
<select id="selectByIds" resultType="student">
select * from student
<where>
<!--
collection="" 遍历数组写array,遍历集合写list,遍历map集合写map
open="id in(" 以xxx开头
close=")" 以xxx结尾
item="" 遍历的每一个元素的名称,变量名随便写,写啥后面就用啥
separator="," 分隔符
index="" 如果遍历的是数组或者单列集合,就表示索引。如果遍历的是map就表示key
-->
<foreach collection="list" open="id in(" close=")" item="id" separator=",">
<!--#{id} 大括号中的名称就是item的属性值-->
#{id}
</foreach>
</where>
</select>
3.2 测试
@Test
public void selectByIds() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
//5.调用实现类的方法,接收结果
List<Student> list = mapper.selectByIds(ids);
//6.处理结果
for (Student student : list) {
System.out.println(student);
}
//7.释放资源
sqlSession.close();
is.close();
}
三. 分页插件【重要】
1. 导入开发jar包
jsqlparser-3.1.jar 和pagehelper-5.1.10.jar
2. 核心配置文件中集成分页插件
<!--集成PageHelper分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
3. 在查询所有信息之前设置查询的页数和每页展示条数
@Test
public void selectPaging() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过分页助手来实现分页功能
//参数1:当前页码,参数2:每页显示条数
// 第一页:显示3条数据
//PageHelper.startPage(1,3);//使用分页助手设置页数和每页条数
// 第二页:显示3条数据
//PageHelper.startPage(2,3);//使用分页助手设置页数和每页条数
// 第三页:显示3条数据
PageHelper.startPage(3,3);//使用分页助手设置页数和每页条数
//5.调用实现类的方法,接收结果
List<Student> list = mapper.selectAll();
//6.处理结果
for (Student student : list) {
System.out.println(student);
}
//7.释放资源
sqlSession.close();
is.close();
}
4. 在查询所有信息之后获取分页相关参数
@Test
public void selectPaging() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取StudentMapper接口的实现类对象
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
//通过分页助手来实现分页功能
//参数1:当前页码,参数2:每页显示条数
// 第一页:显示3条数据
//PageHelper.startPage(1,3);//使用分页助手设置页数和每页条数
// 第二页:显示3条数据
//PageHelper.startPage(2,3);//使用分页助手设置页数和每页条数
// 第三页:显示3条数据
PageHelper.startPage(3,3);//使用分页助手设置页数和每页条数
//5.调用实现类的方法,接收结果
List<Student> list = mapper.selectAll();
//获取分页相关参数
PageInfo<Student> info=new PageInfo<>(list);
System.out.println("当前页数:"+info.getPageNum()); //1
System.out.println("每页展示条数:"+info.getPageSize()); //3
System.out.println("总页数:"+info.getPages());
System.out.println("总条数:"+info.getTotal());
System.out.println("当前页条数:"+info.getSize());
System.out.println("上一页:"+info.getPrePage());
System.out.println("下一页:"+info.getNextPage());
System.out.println("是否是第一页:"+info.isIsFirstPage());
System.out.println("是否是最后一页:"+info.isIsLastPage());
//6.处理结果
for (Student student : list) {
System.out.println(student);
}
//7.释放资源
sqlSession.close();
is.close();
}
四. mybatis多表操作【重要】
1. 数据库准备
CREATE DATABASE db2;
USE db2;
-- 一对一
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,'12345',1);
INSERT INTO card VALUES (NULL,'23456',2);
INSERT INTO card VALUES (NULL,'34567',3);
-- 一对多
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);
-- 多对多
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);
2. 一对一关系
2.1 javabean类
public class Card {
private Integer id; //主键id
private String number; //身份证号
private Person p; //所属人的对象
}
public class Person {
private Integer id; //主键id
private String name; //人的姓名
private Integer age; //人的年龄
}
2.2 接口类
public interface OneToOneMapper {
//查询全部
public abstract List<Card> selectAll();
}
2.3 映射文件配置
resultMap标签的作用:手动定义查询结果和bean对象的映射关系,一般用来处理查询结果和bean的属性不一致情况。
<?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.mapper.OneToOneMapper">
<!--配置查询结果和bean对象的对应关系-->
<!--association:配置被包含对象的映射关系
property:被包含对象的变量名
javaType:被包含对象的数据类型-->
<resultMap id="oneToOne" type="card">
<!--封装主键信息,column="id"列名称,property="id"bean中的属性名称-->
<id column="id" property="id"/>
<!--封装非主键信息-->
<result column="number" property="number"/>
<!--配置包含的对象映射关系,配置一对一关系,javaType="person"表示bean的属性类型-->
<association property="p" javaType="person">
<!--封装主键信息-->
<id column="pid" property="id"/>
<!--封装非主键信息-->
<result column="name" property="name"/>
<result column="age" property="age"/>
</association>
</resultMap>
<!-- 测试一对一关系:查询所有card的信息,包括每个card对应的person信息-->
<select id="selectAll" resultMap="oneToOne">
select c.*,p.NAME,p.age from card c ,person p where c.pid=p.id;
</select>
</mapper>
注意:封装结果集不再使用resultType属性,而是使用resultMap属性。
2.4 测试类
/*
测试一对一关系:查询所有card的信息,包括每个card对应的person信息
*/
@Test
public void selectAll() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取OneToOneMapper接口的实现类对象
OneToOneMapper mapper = sqlSession.getMapper(OneToOneMapper.class);
//5.调用实现类的方法,接收结果
List<Card> list = mapper.selectAll();
//6.处理结果
for (Card c : list) {
System.out.println(c);
}
//7.释放资源
sqlSession.close();
is.close();
}
3. 一对多关系
3.1 javabean类
public class Classes {
private Integer id; //主键id
private String name; //班级名称
private List<Student> students; //班级中所有学生对象,一个班级中有多名学生
}
public class Student {
private Integer id; //主键id
private String name; //学生姓名
private Integer age; //学生年龄
}
3.2 接口类
public interface OneToManyMapper {
//查询全部
public abstract List<Classes> selectAll();
}
3.3 映射文件配置
<!--
collection:配置被包含的集合对象映射关系
property:被包含对象的变量名
ofType:被包含对象的实际数据类型
-->
<resultMap id="oneToMany" type="Classes">
<id column="cid" property="id"/>
<result column="cname" property="name"/>
<!--将剩下的查询结果映射到students中,映射集合中的对象,ofType=""表示集合中的对象类型-->
<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="oneToMany">
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>
3.4 测试类
/*
测试一对多关系:查询所有班级以及该班级的所有学生信息
*/
@Test
public void selectAll() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取OneToManyMapper接口的实现类对象
OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class);
//5.调用实现类的方法,接收结果
List<Classes> classes = mapper.selectAll();
//6.处理结果
for (Classes cls : classes) {
System.out.println(cls.getId() + "," + cls.getName());
List<Student> students = cls.getStudents();
for (Student student : students) {
System.out.println("\t" + student);
}
}
//7.释放资源
sqlSession.close();
is.close();
}
4. 多对多关系
4.1 javabean类
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; //课程名称
}
4.2 接口类
public interface ManyToManyMapper {
//查询全部
public abstract List<Student> selectAll();
}
4.3 映射文件配置
<!--配置字段和实体对象属性的映射关系-->
<!--
collection:配置被包含的集合对象映射关系
property:被包含对象的变量名
ofType:被包含对象的实际数据类型
-->
<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 s.id sid,s.NAME sname,s.age sage,c.id cid,c.NAME cname from student s,stu_cr sc,course c where s.id=sc.sid and c.id=sc.cid;
</select>
4.4 测试类
/*
测试多对多关系:查询所有学生及其选课信息
*/
@Test
public void selectAll() throws Exception{
//1.加载核心配置文件
InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
//2.获取SqlSession工厂对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
//3.通过工厂对象获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//4.获取ManyToManyMapper接口的实现类对象
ManyToManyMapper mapper = sqlSession.getMapper(ManyToManyMapper.class);
//5.调用实现类的方法,接收结果
List<Student> students = mapper.selectAll();
//6.处理结果
for (Student student : students) {
System.out.println(student.getId() + "," + student.getName() + "," + student.getAge());
List<Course> courses = student.getCourses();
for (Course cours : courses) {
System.out.println("\t" + cours);
}
}
//7.释放资源
sqlSession.close();
is.close();
}
注意:javaType属性和ofType属性的区别?
javaType的值用来表示bean对象的属性类型,ofType的值用来表示集合中元素的类型。