05.mybatis优化和分页

Mybatis03-优化和分页

第一节:性能优化

1.1 延迟加载

所谓的延迟加载也是就是说关系属性加载的延迟。不用不查,用的时候再查

1.1.1 什么是延迟加载
resultMap中的association和collection标签具有延迟加载的功能。
延迟加载的意思是说,在关联查询时,利用延迟加载,先加载主信息。需要关联信息时再去按需加载关联信息。这样会大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
1.1.2 设置延迟加载
Mybatis默认是不开启延迟加载功能的,我们需要手动开启。需要在SqlMapConfig.xml文件中,在标签中开启延迟加载功能。
<settings>
    
    <setting name="lazyLoadingEnabled" value="true"/>
    
    <setting name="aggressiveLazyLoading" value="false"/>
settings>
设置项 描述 允许值 默认值
lazyLoadingEnabled 全局性设置懒加载。如果设为false,则所有相关联的都会被初始化加载。 true | false false
aggressiveLazyLoading 当设置为true的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 true | false true
1.1.3 使用association进行延迟加载
(1) 需求
查询订单并且关联查询用户信息(对用户信息的加载要求是按需加载)
(2) 编写映射文件
需要定义两个mapper的方法对应的statement。

1、只查询订单信息

SELECT * FROM orders

在查询订单的statement中使用association去延迟加载(执行)下边的satatement(关联查询用户信息)


<resultMap type="com.qf.mybatis.po.Orders" id="OrdersUserLazyLoadingRstMap">
    <id column="id" property="id" />
    <result column="user_id" property="userId" />
    <result column="number" property="number" />
    <result column="createtime" property="createtime" />
    <result column="note" property="note" />
    
    
    
    <association property="user" select="com.qf.mybatis.mapper.UserMapper.findUserById" column="user_id">association>
resultMap>

<select id="findOrdersUserLazyLoading" resultMap="OrdersUserLazyLoadingRstMap">
    SELECT * FROM orders
select>

2、关联查询用户信息

通过上边查询到的订单信息中user_id去关联查询用户信息

使用UserMapper.xml中的findUserById

<select id="findUserById" parameterType="int"
       resultType="com.qf.mybatis.po.User">
    SELECT * FROM user WHERE id = #{id}
select>

上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来。
(3) 加载映射文件

@Test public void testFindOrdersUserLazyLoading() { // 创建sqlSession SqlSession sqlSession = sqlSessionFactory.openSession(); // 通过SqlSession构造usermapper的代理对象 OrdersMapper ordersMapper = sqlSession.getMapper(OrdersMapper.class); // 调用usermapper的方法 List<Orders> list = ordersMapper.findOrdersUserLazyLoading(); for(Orders orders : list){ System.out.println(orders.getId()); System.out.println(orders.getUser()); } // 释放SqlSession sqlSession.close(); }

1.4、延迟加载思考
不使用mybatis提供的association及collection中的延迟加载功能,如何实现延迟加载?
实现方法如下:

定义两个mapper方法:

1、查询订单列表

2、根据用户id查询用户信息

实现思路:

先去查询第一个mapper方法,获取订单信息列表

在程序中(service),按需去调用第二个mapper方法去查询用户信息。

 总之:

使用延迟加载方法,先去查询单表数据,再去按需要加载关联查询的其它信息。

1.2 MyBatis缓存

Mybatis的缓存,包括一级缓存和二级缓存:

	一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
	
	级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
 	一级缓存是默认使用的。二级缓存需要手动开启。

1.2.1 一级缓存
1.2.1 mybatis缓存原理

mybatis提供查询缓存,如果缓存中有数据就不用从数据库中获取,用于减轻数据压力,提高系统性能。

05.mybatis优化和分页_第1张图片

第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。

测试1:

 @Test
    public void testOneLevelCache() {
       SqlSession sqlSession = sqlSessionFactory.openSession();
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       // 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
       User user1 = mapper.findUserById(1);
       System.out.println(user1);
       // 第二次查询ID为1的用户
       User user2 = mapper.findUserById(1);
       System.out.println(user2);
       sqlSession.close();
    }

如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

05.mybatis优化和分页_第2张图片
测试2:

 @Test
    public void testOneLevelCache() {
       SqlSession sqlSession = sqlSessionFactory.openSession();
       UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       // 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
       User user1 = mapper.findUserById(1);
       System.out.println(user1); 
       User user = new User();
       user.setUsername("tom");
       user.setAddress("北京");
       //执行增删改操作,清空缓存
       mapper.insertUser(user);
       // 第二次查询ID为1的用户
       User user2 = mapper.findUserById(1);
       System.out.println(user2);
       sqlSession.close();
    }

1.2.2 应用

正式开发,是将mybatis和spring进行整合开发,事务控制在service中。

一个service方法中包括 很多mapper方法调用。

service方法{
 //开始执行时,开启事务,创建SqlSession对象
 //第一次调用mapper的方法findUserById(1)
 //第二次调用mapper的方法findUserById(1),从一级缓存中取数据
 //方法结束,sqlSession关闭
}

如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。

第二节:分页查询

Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。

2.1 环境准备

第一步:创建项目添加依赖

创建web项目名称:day05_web01
依赖信息如下:

<dependencies>
  		<dependency>
           <groupId>mysqlgroupId>
           <artifactId>mysql-connector-javaartifactId>
           <version>5.1.45version>
       dependency>
       
       <dependency>
           <groupId>org.mybatisgroupId>
           <artifactId>mybatisartifactId>
           <version>3.4.6version>
       dependency>
   
       <dependency>
           <groupId>log4jgroupId>
           <artifactId>log4jartifactId>
           <version>1.2.17version>
       dependency>
dependencies>

第二步:加入配置文件

Mybatis的核心配置mybatis-config.xml、log4j日志文件log4j.properties



<configuration>
	
	<environments default="development">
		<environment id="development">
			
			<transactionManager type="JDBC" />
			
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url"
					value="jdbc:mysql://localhost:3306/mybatis_01?characterEncoding=utf-8" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			dataSource>
		environment>
	environments>
configuration>

### set log levels - for more verbose logging change 'info' to 'debug' , 'off' ###
log4j.rootLogger=info, stdout,file

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=d:\\mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

第三步:创建POJO

User.java

public class User {
	private int id;
	private String username;// 用户姓名
	private String sex;// 性别
	private Date birthday;// 生日
	private String address;// 地址
	//getter和setter
}

第四步:加入sql映射文件

在resources目录下创建com.qf.mapper文件夹,然后创建UserMapper.xml文件




<mapper namespace="">
  

第五步:加载映射文件

MyBatis框架需要加载UserMapper.xml映射文件,将UserMapper.xml添加在mybatis-config.xml,如下:

<mappers>
        <mapper resource="com/qf/mapper/UserMapper.xml"/>
mappers>

2.2 编写PageBean

package com.qf.domain;

import java.util.List;

/**
 * @author wgy 2018/12/5 11:55
 * @version 1.0
 */
public class PageBean<T> {
    //页吗
    private int pageNum;
    //页大小
    private int pageSize;
    //总共数据个数
    private long totalCount;
    //总页数
    private int totalPage;

    //数据
    private List<T> data;

    //开始页码
    private int startPage;

    //结束页码
    private int endPage;

    public PageBean() {
    }

    public PageBean(int pageNum, int pageSize, long totalCount, List<T> data) {
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        this.totalCount = totalCount;
        this.data = data;


        //计算总页数
        this.totalPage= (int) (totalCount%pageSize==0?totalCount/pageSize:totalCount/pageSize+1);
        //开始页码
        this.startPage=pageNum-4;
        this.endPage=pageNum+5;

        //特殊1
        if(pageNum<5){
            this.startPage=1;
            this.endPage=10;
        }
        //特殊2
        if(pageNum>totalPage-5){
            this.startPage=totalPage-9;
            this.endPage=totalPage;
        }
        //特殊3
        if(totalPage<10){
            this.startPage=1;
            this.endPage=totalPage;
        }

    }

    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 long getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(long totalCount) {
        this.totalCount = totalCount;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public int getStartPage() {
        return startPage;
    }

    public void setStartPage(int startPage) {
        this.startPage = startPage;
    }

    public int getEndPage() {
        return endPage;
    }

    public void setEndPage(int endPage) {
        this.endPage = endPage;
    }
}

2.3 编写QueryVo

package com.qf.mybatis.pojo;

/**
 * @author wgy 2018/12/14 21:43
 * @version 1.0
 */
public class QueryVo<T> {
    private T con;
    private int pageNum;
    private int pageSize;
    private int offset;
    private String orderBy;

    public QueryVo(T con, int pageNum, int pageSize,String orderBy) {
        this.con = con;
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        if(pageNum>0&&pageSize>0) {
            this.offset = (pageNum - 1) * pageSize;
        }
        this.orderBy=orderBy;
    }

    public T getCon() {
        return con;
    }

    public void setCon(T con) {
        this.con = con;
    }

    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 int getOffset() {
        return offset;
    }

    public void setOffset(int offset) {
        this.offset = offset;
    }

    public String getOrderBy() {
        return orderBy;
    }

    public void setOrderBy(String orderBy) {
        this.orderBy = orderBy;
    }
}


2.4 添加Mapper方法

UserMapper接口中添加

List<User> findByPage(QueryVo queryVo)

UserMapper.xml文件中

<select id="findUserByPage" parameterType="QueryVo" resultType="com.qf.mybatis.pojo.User">
      select * from user
      <if test="orderBy !=null orderBy !=''">
          order by=${orderBy}
      if>
      limit #{offset},#{pageSize}
select>

2.5 添加Service

UserService接口中添加

PageBean findByPage(QueryVo queryVo)

UserServiceImpl实现:


2.6 编写Servlet

2.7 编写jsp页面

第三节:PageHelper的使用

下载地址https://github.com/pagehelper/Mybatis-PageHelper/releases

在实际开发中,更多的是使用分页插件来减少代码冗杂,使编码更加清晰。
思路:分页控制的代码写在拦截器中,从而不影响本来的业务逻辑代码

使用步骤:

第一步:添加依赖



<dependency>
      <groupId>com.github.pagehelpergroupId>
      <artifactId>pagehelperartifactId>
      <version>4.2.1version>
dependency>


<dependency>
  <groupId>com.github.pagehelpergroupId>
  <artifactId>pagehelperartifactId>
  <version>5.1.6version>
dependency>

第二步:配置pageHelper插件

配置pageHelper插件有两种方式:(1)在mybatis-config.xml文件中(2)在Spring的配置文件中(后面学习)

在mybatis-config.xml文件中

<plugins>
		
		<plugin interceptor="com.github.pagehelper.PageHelper">
			
			<property name="dialect" value="mysql"/>
			
			<property name="pageSizeZero" value="true"/>
			
			<property name="reasonable" value="true"/>

		plugin>
		
		<plugin interceptor="com.github.pagehelper.PageInterceptor">
			
			<property name="pageSizeZero" value="true"/>
			
			<property name="reasonable" value="true"/>

		plugin>
plugins>

第三步:编写代码测试

@Test
public void queryAll(){
    PageHelper.startPage(1, 3);
    PageHelper.orderBy("id");
    List<User> list = userMapper.queryAll();
    PageInfo<User> p=new PageInfo<User>(list);
    for (User user : list) {
    System.out.println(user.toString());
    }
    System.out.println(p.getPages());
    System.out.println(p.getPageSize());
    System.out.println(p.getPageNum());
    System.out.println(p.getOrderBy());
}

第四步:实现

你可能感兴趣的:(常用企业框架)