栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

MyBatis入门(九)注解开发(下)& PageHelper分页插件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

MyBatis入门(九)注解开发(下)& PageHelper分页插件

目录

一.二级缓存

二.一对一关联查询

三.一对多关联查询

四.注解开发与映射文件开发的对比

五.PageHelper分页插件


一.二级缓存 MyBatis 默认开启一级缓存,接下来我们学习如何在注解开发时使用二级缓存: 1 (1)POJO 类实现 Serializable 接口。 (2)在 MyBatis 配置文件添加如下设置: 下面的这个配置其实可以不加,因为这个配置默认就是true 在核心配置文件的的中添加如下配置
    
        
    
(3) 在持久层接口上方加注解 @CacheNamespace(blocking=true) ,该接口的 所有方法 都支持二级缓存。 (4) 测试二级缓存

TestUserMapper2.java:

import com.first.mapper.UserMapper;
import com.first.pojo.User;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestUserMapper2 {

    //前置方法:测试类里的测试方法执行之前都会先执行前置方法
    @Test
    public void testCache() throws IOException {
        //(1)读取核心配置文件
        InputStream is= Resources.getResourceAsStream("SqlMapConfig.xml");
        //(2)创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //(3)SqlSessionFactoryBuilder对象获取SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(is);
        //(4)SqlSessionFactory对象获取不同SqlSession对象
        
        SqlSession session1 = factory.openSession();
        SqlSession session2 = factory.openSession();

        //(5)SqlSession对象获取代理对象,即对应类的对象
        User user1 = session1.getMapper(UserMapper.class).findById(1);
        System.out.println(user1);
        System.out.println(user1.hashCode());
        //清空一级缓存,将数据保存到二级缓存
        session1.commit();
        User user2 = session2.getMapper(UserMapper.class).findById(1);
        System.out.println(user2);
        System.out.println(user2.hashCode());

    }
}

 输出:

[06/01 14:40:38] 1450   [           main] DEBUG rst.mapper.UserMapper.findById  - ==>  Preparing: select * from user where id=?
[06/01 14:40:38] 1540   [           main] DEBUG rst.mapper.UserMapper.findById  - ==> Parameters: 1(Integer)
[06/01 14:40:38] 1741   [           main] DEBUG rst.mapper.UserMapper.findById  - <==      Total: 1
User{id=1, username='小热', sex='男', address='北京'}
1327536153
[06/01 14:40:38] 1843   [           main] WARN  .ibatis.io.SerialFilterChecker  - As you are using functionality that deserializes object streams, it is recommended to define the JEP-290 serial filter. Please refer to https://docs.oracle.com/pls/topic/lookup?ctx=javase15&id=GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66
[06/01 14:40:38] 1862   [           main] DEBUG    com.first.mapper.UserMapper  - Cache Hit Ratio [com.first.mapper.UserMapper]: 0.5
User{id=1, username='小热', sex='男', address='北京'}

可以看见两次输出的对象内容是一样的,但是第一次是查询了数据库,第一次查询之后返回结果并将结果放到一级缓存中,然后又执行了session1.commit();用来清空一级缓存,将数据保存到二级缓存 ,而在二级缓存中,存储的是数据,而不是对象,所以第二次查询时,从二级缓存中取出数据拼接成对象,所以第一次和第二次的对象hashCode不一样!如果关掉二级缓存的话,就只能两次都查询数据库了。

二.一对一关联查询 在 MyBatis 的注解开发中对于多表查询只支持分解查询(N+1),不支持连接查询。 示例:查询所有学生,把学生对应的班级也查询出来(一个学生对应一个班级)

(1)创建实体类

上篇文章已经创建过,Classes和Student类

(2)创建分解后的查询方法

在mapper下创建接口文件StudentMapper.java和ClassesMapper.java

ClassesMapper.java:

package com.first.mapper;

import com.first.pojo.Classes;
import org.apache.ibatis.annotations.Select;

public interface ClassesMapper {
    //根据cid查询班级
    @Select("select * from classes where cid= #{cid}")
    Classes findByCid(int cid);
}

StudentMapper.java:

后面还得修改

package com.first.mapper;

import com.first.pojo.Student;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface StudentMapper {
    //查询所有学生信息
    @Select("select * from student")
    List findAll();
}

因为这个查询中student是主表,根据student表中的classId与classes表中的cid将两张表联系起来,所以classes表是从表,查询结果中除了有Student类中定义的普通属性外,还要有一个Classes的类对象!所以这就需要自定义映射关系! 

(3)主表的查询配置自定义映射关系

StudentMapper.java:

package com.first.mapper;

import com.first.pojo.Student;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.mapping.FetchType;

import java.util.List;

public interface StudentMapper {
    //查询所有学生信息,所以classId也能够被查出来,虽然Student类中没有定义classId属性
    @Select("select * from student")
    //自定义映射关系
    @Results(id = "studentMapper" ,value = {
            @Result(id = true,property = "sid",column = "sid"),
            @Result(property = "name",column = "name"),
            @Result(property = "age",column = "age"),
            @Result(property = "sex",column = "sex"),
            
            @Result(property = "classes",column = "classId",
            one = @One(select = "com.first.mapper.ClassesMapper.findByCid",
                    fetchType = FetchType.EAGER))
    })
    List findAll();
}

(4)测试

新建测试类TestManyTables

import com.first.mapper.StudentMapper;
import com.first.mapper.UserMapper;
import com.first.pojo.Student;
import com.first.pojo.User;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class TestManyTables {
    //全局变量
    InputStream is=null;
    SqlSession session =null;
    StudentMapper userMapper =null;

    //前置方法:测试类里的测试方法执行之前都会先执行前置方法
    @Before
    public void before() throws IOException {
        //(1)读取核心配置文件
        is= Resources.getResourceAsStream("SqlMapConfig.xml");
        //(2)创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //(3)SqlSessionFactoryBuilder对象获取SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(is);
        //(4)SqlSessionFactory对象获取SqlSession对象
        session = factory.openSession();
    }

    后置方法:测试类里的测试方法执行之后都会执行后置方法
    @After
    public void after() throws IOException {
        //(7)释放资源
        session.close();
        is.close();
    }

    @Test
    public void findAllStudent(){
        //(5)SqlSession对象获取代理对象,即对应类的对象
        StudentMapper studentMapper = session.getMapper(StudentMapper.class);
        List all = studentMapper.findAll();
        all.forEach(System.out::println);
    }
}

输出:

Student{sid=1, name='张三', age=10, sex='男', classes=Classes{cid=1, className='三年一班', studentList=null}}
Student{sid=2, name='李四', age=10, sex='女', classes=Classes{cid=1, className='三年一班', studentList=null}}
Student{sid=3, name='尚尚', age=10, sex='男', classes=Classes{cid=2, className='三年二班', studentList=null}}
Student{sid=4, name='百战', age=11, sex='男', classes=Classes{cid=2, className='三年二班', studentList=null}}
Student{sid=5, name='王五', age=10, sex='男', classes=Classes{cid=2, className='三年二班', studentList=null}}

三.一对多关联查询

本例是查询所有班级,每个班级又对应多个学生,所以是一对多,班级表是主表,而学生表是从表。

(1)创建分解后的查询方法

在ClassesMapper.java中增加接口函数

后面还有修改,即(3)

    //查询所有班级
    @Select("select * from classes")
    List findAll();

 在StudentMapper.java中增加接口函数

//根据班级ID查询学生
@Select("select * from student where classId = #{cid}")
List findByClassId(int classId);

(2)主表的查询配置自定义映射关系

    //查询所有班级
    @Select("select * from classes")
    @Results(id = "classMapper",value = {
            @Result(id = true,property = "cid",column = "cid"),
            @Result(property = "className",column = "className"),
            //many:表示该属性是一个集合
            @Result(property = "studentList",column = "cid",
                    many = @Many(select = "com.first.mapper.StudentMapper.findByClassId",
                    //一对多一般用延迟加载
                    fetchType = FetchType.LAZY))
    })
    List findAll();

(3)测试

//一对多
@Test
public void findAllClasses(){
    ClassesMapper classesMapper = session.getMapper(ClassesMapper.class);
    List all = classesMapper.findAll();
    all.forEach(System.out::println);
}

 输出:

[06/01 16:49:13] 867    [           main] DEBUG t.mapper.ClassesMapper.findAll  - ==>  Preparing: select * from classes
[06/01 16:49:13] 954    [           main] DEBUG t.mapper.ClassesMapper.findAll  - ==> Parameters: 
[06/01 16:49:14] 1292   [           main] DEBUG t.mapper.ClassesMapper.findAll  - <==      Total: 2
[06/01 16:49:14] 1295   [           main] DEBUG er.StudentMapper.findByClassId  - ==>  Preparing: select * from student where classId = ?
[06/01 16:49:14] 1295   [           main] DEBUG er.StudentMapper.findByClassId  - ==> Parameters: 1(Integer)
[06/01 16:49:14] 1352   [           main] DEBUG er.StudentMapper.findByClassId  - <==      Total: 2
Classes{cid=1, className='三年一班', studentList=[Student{sid=1, name='张三', age=10, sex='男', classes=null}, Student{sid=2, name='李四', age=10, sex='女', classes=null}]}
[06/01 16:49:14] 1353   [           main] DEBUG er.StudentMapper.findByClassId  - ==>  Preparing: select * from student where classId = ?
[06/01 16:49:14] 1354   [           main] DEBUG er.StudentMapper.findByClassId  - ==> Parameters: 2(Integer)
[06/01 16:49:14] 1359   [           main] DEBUG er.StudentMapper.findByClassId  - <==      Total: 3
Classes{cid=2, className='三年二班', studentList=[Student{sid=3, name='尚尚', age=10, sex='男', classes=null}, Student{sid=4, name='百战', age=11, sex='男', classes=null}, Student{sid=5, name='王五', age=10, sex='男', classes=null}]}

四.注解开发与映射文件开发的对比

注解开发更快,映射文件维护方便!

MyBatis 中更推荐使用映射文件开发, Spring 、 SpringBoot 更推荐注解方式。具体使用要视项目情况而定。它们的优点对比如下: 映射文件:
  • 代码与Sql语句是解耦的,修改时只需修改配置文件,无需修改源码。 因为注解当时修改sql语句后,java源码需要重新编译,但是映射文件方式直接修改即可!
  • Sql语句集中,利于快速了解和维护项目。
  • 级联查询支持连接查询和分解查询两种方式,注解开发只支持分解查询。
注解:
  • 配置简单,开发效率高。
  • 类型安全,在编译期即可进行校验,不用等到运行时才发现错误。

五.PageHelper分页插件

如果你也在用MyBatis,建议尝试该分页插件,这一定是最方便使用的分页插件。分页插件支持任何复杂的单表、多表分页。

开发过程中如果要进行分页查询,需要传入页数和每页条数。返回页面数据,总条数,总页数,当前页面,每页条数等数据。此时使用PageHelper插件可以快速帮助我们获取这些数据。

PageHelper是一款非常好用的开源免费的Mybatis第三方分页插件。使用该插件时,只要传入分页参数,即可自动生成页面对象。 我们使用该插件分页查询所有用户:

(1)引入依赖

在pom.xml文件中配置,配置完成后,刷新maven

        
        
            com.github.pagehelper
            pagehelper
            5.3.0
        

(2)Mybatis配置文件中配置PageHelper插件

在SqlMapConfig.xml的中添加如下代码

    
        
            
            
        
    

(3)使用PageHelper插件

在TestUserMapper.java中测试

    //测试分页插件
    @Test
    public void testFindPage(){
        //1.设置分页参数 参数一:起始页(此插件从1开始,而不是0);参数二:每页条数
        PageHelper.startPage(1,3);
        //2.正常查询
        List all = userMapper.findAll();
        //3.封装查询结果,生成页面对象
        PageInfo pageInfo = new PageInfo(all);
        //4.打印页面对象的属性
        //是每页的结果集,而不是所有数据
        System.out.println("结果集:"+pageInfo.getList());
        System.out.println("总条数:"+pageInfo.getTotal());
        System.out.println("总页数:"+pageInfo.getPages());
        System.out.println("当前页:"+pageInfo.getPageNum());
        System.out.println("每页条数:"+pageInfo.getSize());
    }

输出:

[06/01 21:20:18] 2491   [           main] DEBUG apper.UserMapper.findAll_COUNT  - ==>  Preparing: SELECt count(0) FROM user
[06/01 21:20:18] 2576   [           main] DEBUG apper.UserMapper.findAll_COUNT  - ==> Parameters: 
[06/01 21:20:19] 2827   [           main] DEBUG apper.UserMapper.findAll_COUNT  - <==      Total: 1
[06/01 21:20:19] 2828   [           main] DEBUG    com.first.mapper.UserMapper  - Cache Hit Ratio [com.first.mapper.UserMapper]: 0.0
[06/01 21:20:19] 2828   [           main] DEBUG irst.mapper.UserMapper.findAll  - ==>  Preparing: select * from user LIMIT ?
[06/01 21:20:19] 2828   [           main] DEBUG irst.mapper.UserMapper.findAll  - ==> Parameters: 3(Integer)
[06/01 21:20:19] 2843   [           main] DEBUG irst.mapper.UserMapper.findAll  - <==      Total: 3
结果集:Page{count=true, pageNum=1, pageSize=3, startRow=0, endRow=3, total=9, pages=3, reasonable=false, pageSizeZero=false}[User{id=1, username='小热', sex='男', address='北京'}, User{id=2, username='小巴', sex='男', address='上海'}, User{id=3, username='小赵', sex='女', address='广州'}]
总条数:9
总页数:3
当前页:1
每页条数:3

可以自己调整起始页参数和每页条数来测试一下!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/946136.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号