Mybatis应用

数据库建表是时

create table abc(*****)后面跟的sql代码含义:
enging=innodb (引擎)
Default charset=utf-8(字符集)

需要的依赖:mysql、mybatis

编写mybatis的核心配置文件mybatis-config.xm:

<?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>

    <!--mybatis提供了一个logImpl日志工厂-->
    <settings>
        <!--默认有一个 STDOUT_LOGGING ,不用引入任何东西,直接配置一下就好-->
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->

        <!--LOG4J需要映入包-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <!--实体类起别名-->
    <typeAliases>
        <!--1 给一个类起一个固定的别名-->
        <!--<typeAlias type="com.tt.pojo.Books" alias="Book"/>-->

        <!--2 扫描实体类的包,将每个实体类首字母小写作为动态的别名-->
        <package name="com.tt.pojo"/>
       <!-- 实体类上加注解@Ailas("bookss")来定义别名 , 但还是要用 <package name="com.tt.pojo"/> 扫描实体类的包-->
    </typeAliases>


    <environments default="development">
        <environment id="development">
           <!-- mybatis的事务管理器,有两个jdbc managed,(常用jdbc)-->
            <transactionManager type="JDBC"/>
            <!--mybatis数据源类型的控制 现有三个-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/tyd?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>


    <!--  每一个Mapper.xml都需要在Mybatis核心配置文件中注册 !-->
   <!-- mappers 标签就是用来配置 需要加载的 sql 映射配置文件路径的。-->
    <mappers>

        <!--1.相对资源路径配置-->
        <!-- mapper标签,通过resource属性引入classpath路径的相对资源-->
        <mapper resource="com/tt/dao/model/BookMapper.xml"/>


        <!--2.使用映射器接口类注册引入-->
        <!--mapper标签,通过class属性指定mapper接口名称,
        此时对应的映射文件
        必须与接口位于同一路径下,并且名称相同  -->
        <!--<mapper class="com.tt.dao.mapper.BookMapper"/>-->


        <!--3.接口所在包-->
        <!--mapper接口所在的包名 . package标签,通过name属性指定mapper接口所在的包名 ,
        此时对应的映射文件
        必须与接口位于同一路径下,并且名称相同-->
        <!--<package name="com.tt.dao.mapperr."/>-->

    </mappers>

</configuration>

编写MyBatis工具类

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.IOException;
import java.io.InputStream;

/**
 * @author TT
 */
public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            /* SqlSessionFactoryBuilder就是建造者,通过获取配置文件信息,建造sqlSessionFactory工厂模式 */
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession连接
     * 获取SqlSession连接,也就是创建了能执行sql数据库的所有方法
     */
    public static SqlSession getSession(){
        /* 工厂里面生产SqlSession */
        return sqlSessionFactory.openSession();
    }
}

编写代码

实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.ibatis.type.Alias;

/**
 * @author TT
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias("bookss")
public class Books {
    private int bookID;
    private String bookName;
    private int bookCounts;
    private String detail;
}

Dao接口

import java.util.List;

/**
 * @author TT
 */
public interface BookMapper {

    List<Books> selectUser();

    List<Books> selectUser1(int id);
}

编写Mapper.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.tt.dao.mapper.BookMapper">

    <!--select 中 resultType="bookss" 是返回了一个实际类型,
    这里还可以用resultMap 来给 实体类和数据库查出的字段名做一个对应,也就是映射-->
    <!--type 用的也是起的别名,不起别名写的就是源路径-->
    <resultMap id="aaa" type="bookss">
        <!--column 是数据库字段  property 是实体类的字段-->
        <result column="bookID" property="bookID"/>
        <result column="bookName" property="bookName"/>
        <result column="bookCounts" property="bookCounts"/>
        <result column="detail" property="detail"/>
    </resultMap>

    <select id="selectUser" resultMap="aaa">
        select * from books;
    </select>

    <select id="selectUser1" parameterType="int" resultType="bookss">
        select * from books where bookID = #{id};
    </select>

</mapper>

log4j (log4j.properties)配置文件

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/rizhi.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

测试

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class myTest {

    @Test
    public void selectUser() {
        //调用工具类中getSession方法
        SqlSession sqlsession = MybatisUtils.getSession();
        //方法一:
        //List users=session.selectList("com.kuang.mapper.UserMapper.selectUser");
        //方法二:
        BookMapper mapper=sqlsession.getMapper(BookMapper.class);
        List<Books> users=mapper.selectUser();
        System.out.println("==================");
        for(Books books:users){
	        System.out.println(books);
        }
        System.out.println("==================");
        List<Books> users1=mapper.selectUser1(1001);
        for(Books books:users1){
            System.out.println(books);
        }
        System.out.println("==================");
        //提交事务
        sqlsession.commit();
        //建议写在finall里面
        sqlsession.close();
    }
}

常见问题:

1、在mybatis配置文件中必须注册每一个Mapper.xml文件,或者直接指向这个类
2、找不到Mapper.xml文件,一般放在resources文件夹中也行
在Pom.xml文件中在build中配置resources来防止资源导出失败问题

静态资源过滤问题

<build>
  <resources>
    <resource>
      <directory>src/main/java</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>false</filtering>
    </resource>
    <resource>
      <directory>src/main/resources</directory>
      <includes>
        <include>**/*.properties</include>
        <include>**/*.xml</include>
      </includes>
      <filtering>false</filtering>
    </resource>
  </resources>
</build>

技术点总结

Mybatis传参单个参数

传入参数类型(parameterType=”int”)
返回类型(resultType=”com.tt.pojo.user”)
Mapper接口那边如果为(int id),则在xml where条件后写:where id=#{id}

增删改需要提交事务

sqlsession.commit();

Map传参(野路子)

在xml文件中使用时用#{key值},传入参数类型为:parameterType=”Map”

模糊查询like语句:

(1)第1种:在Java代码中添加sql通配符

//接口
List names = mapper.selectlike(“%李%”);
//xml文件

select * from foo where bar like #{value}

(2)在sql语句中拼接通配符,会引起sql注入

List names = mapper.selectlike(“李”);

select * from foo where bar like “%”#{value}“%”

配置解析

核心配置文件

mybatis-config.xml 系统核心配置文件

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。

能配置的内容如下:

configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器) 、
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

Properties优化:把数据库连接信息写在db.properties文件中,然后在mybatis-config.xml文件中用参数来使用db.properties文件中的数据库连接需要的信息。

第一步 ; 在资源目录下新建一个db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8
username=root
password=123456

第二步 : 将文件导入properties 配置文件

 <!--导入properties文件-->
   <properties resource="db.properties"/>


这里还可以把一部分配置文件写在properties 标签里面(这里优先使用外部配置文件)

<properties resource="db.properties">
	<property name=”username” value=”root”/>
	<property name=”password” value=”123456”/>
</properties >

第三步就可以引用了

<environments default="development">
       <environment id="development">
           <transactionManager type="JDBC"/>
           <dataSource type="POOLED">
               <property name="driver" value="${driver}"/>
               <property name="url" value="${url}"/>
               <property name="username" value="${username}"/>
               <property name="password" value="${password}"/>
           </dataSource>
       </environment>
   </environments>
   <mappers>
       <mapper resource="mapper/UserMapper.xml"/>
   </mappers>
</configuration>

属性名与字段名不一致:

起别名:在xml文件中那as 别名

例子:数据库字段pwd,实体类属性password
select id,name,pwd as password from user

结果集映射(resultMap)

id name pwd
id name password

<resultMap id="UserMap" type="User">
   <!-- id为主键 -->
   <id column="id" property="id"/>
   <!-- column是数据库表的列名 , property是对应实体类的属性名 -->
   <result column="name" property="name"/>
   <result column="pwd" property="password"/>
</resultMap>

<select id="selectUserById" resultMap="UserMap">
  select id , name , pwd from user where id = #{id}
</select>

resultMap 元素是 MyBatis 中最重要最强大的元素。
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了
ResultMap 的优秀之处——你完全可以不用显式地配置它们

分页的几种方式:

日志工厂

Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:

  1. SLF4J
  2. Log4j 【掌握】
  3. Log4j2
  4. JDK logging
  5. COMMONS_LOGGING
  6. STDOUT_LOGGING 【掌握】
  7. NO_LOGGING

STDOUT_LOGGING

指定 MyBatis 应该使用哪个日志记录实现。如果此设置不存在,则会自动发现日志记录实现。(写在mybatis核心配置文件中)

<settings>
       <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

这样就可以直接使用

Log4j

简介:

Log4j是Apache的一个开源项目
通过使用Log4j,我们可以控制日志信息输送的目的地:控制台,文本,GUI组件…
我们也可以控制每一条日志的输出格式;
通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

使用步骤:
导入log4j的包
<dependency>
   		<groupId>log4j</groupId>
   		<artifactId>log4j</artifactId>
   		<version>1.2.17</version>
	</dependency>
配置文件编写(log4j.properties)
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/rizhi.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
setting设置日志实现(在mybatis核心配置文件中配置log4j日志实现)
<settings>
   <setting name="logImpl" value="LOG4J"/>
</settings>
在程序中使用Log4j进行输出!

//注意导包:org.apache.log4j.Logger
//在哪个类(MyTest)里面使用它(log4j)就写哪个类。参数为当前类的class

static Logger logger = Logger.getLogger(MyTest.class);

@Test
public void selectUser() {
   logger.info("info:进入selectUser方法");
   logger.debug("debug:进入selectUser方法");
   logger.error("error: 进入selectUser方法");

   SqlSession session = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);
   List<User> users = mapper.selectUser();
   for (User user: users){
       System.out.println(user);
  }
   session.close();
}
测试,看控制台输出!

使用Log4j 输出日志
可以看到还生成了一个日志的文件 【需要修改file的日志级别】

分页三种方法

1 使用Limit实现分页

2 RowBounds分页

mapper接口

//选择全部用户RowBounds实现分页(不传参了)

List<User> getUserByRowBounds();

mapper文件(也不写limit或条件了)

<select id="getUserByRowBounds" resultType="user">
select * from user
</select>

测试类

在这里,我们需要使用RowBounds类

@Test
public void testUserByRowBounds() {
   SqlSession session = MybatisUtils.getSession();

   int currentPage = 2;  //第几页
   int pageSize = 2;  //每页显示几个
   RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);

   //通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了]
   List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds", null, rowBounds);

   for (User user: users){
       System.out.println(user);
  }
   session.close();
}

PageHelper

导包

com.github.pagehelper
pagehelper
5.2.0

在mybatis配置文件中配置

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--      <property name="dialect" value="mysql"/>-->
      <property name="reasonable" value="true"/>
    </plugin>
</plugins>

代码实现

	PageHelper.startPage(1, 2);
		//得到的对象结果
    List<users> user = mapper.selectUser();
		//将结果放入PageHelper
    PageInfo<users> returnLists=new PageInfo<>(user);
		//已分页后的结果
    List<users> userList=returnLists.getList();

使用注解开发:

第一步:在DAO接口类中的方法加注解@select(select * from user)

@select ()
@update ()
@Insert ()
@delete ()
例子://查询全部用户

@Select("select id,name,pwd password from user") 
public List<User> getAllUser();

第二布:在mybatis核心配置文件中加注解接口的绑定设置

例子:

<!--使用class绑定接口,绑定DAO接口类--> 
<mappers> 
<mapper class="com.kuang.mapper.UserMapper"/>
 </mappers>	

自动实现事务提交

修改工具类
改造MybatisUtils工具类的getSession( ) 方法,重载实现。

//获取SqlSession连接
  public static SqlSession getSession(){
      return getSession(true); //事务自动提交
  }
 //或
  public static SqlSession getSession(boolean flag){
      return sqlSessionFactory.openSession(flag);
  }

关于@Param

@Param注解用于给方法参数起一个名字。以下是总结的使用原则:
在方法只接受一个参数的情况下,可以不使用@Param。
在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
如果参数是 JavaBean , 则不能使用@Param。
不使用@Param注解时,参数只能有一个,并且是Javabean。
例子:

//根据id查询用户 
User selectUserById(@Param("ad") User user,@Param("id") int ids,String name);

则在xml调用时可

#{ad.password} 

注:sql语句中取得的id是@Param()中的id.

动态SQL

什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句
所谓的动态SQL,本质上还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

If

<!--需求1: 
根据作者名字和博客名字来查询博客! 
如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询 
select * from blog where title = #{title} and author = #{author} 
--> 
<select id="queryBlogIf" parameterType="map" resultType="user">
 select * from User where 1=1
<if test="title != null">
 and title = #{title} 
</if> 
<if test="author != null"> 
and author = #{author} 
</if> 
</select>

Where

修改上面的SQL语句;在where标签中如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉

<select id="queryBlogIf" parameterType="map" resultType="user">
  select * from user
   <where>
       <if test="title != null">
          title = #{title}
       </if>
       <if test="author != null">
          and author = #{author}
       </if>
   </where>
</select>

Set

在进行更新操作的时候

<!--注意set是用的逗号隔开-->
 <update id="updateBlog" parameterType="map">
 update blog 
<set> 
<if test="title != null"> 
title = #{title}, 
</if> 
<if test="author != null">
author = #{author} 
</if>
</set> 
where id = #{id}; 
</update>

choose

有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句(就是在choose中只要有一个满足就跳出来,没有一个满足走otherwise标签)

<select id="queryBlogChoose" parameterType="map" resultType="blog"> 
select * from blog 
<where> 
<choose> 
<when test="title != null"> 
title = #{title} 
</when> <when test="author != null"> 
and author = #{author}
 </when>
 <otherwise> 
and views = #{views} 
</otherwise> 
</choose> 
</where>
 </select>

Foreach

<select id="queryBlogForeach" parameterType="map" resultType="blog">
  select * from blog
   <where>
       <!--
       collection:指定输入对象中的集合属性
       item:每次遍历生成的对象
       open:开始遍历时的拼接字符串
       close:结束时拼接的字符串
       separator:遍历对象之间需要拼接的字符串
       select * from blog where 1=1 and (id=1 or id=2 or id=3)
     -->
       <foreach collection="ids"  item="id" open="and (" close=")" separator="or">
          id=#{id}
       </foreach>
   </where>
</select>

测试:

HashMap map = new HashMap(); 
List<Integer> ids = new ArrayList<Integer>(); 
ids.add(1); 
ids.add(2); 
ids.add(3); 
map.put("ids",ids);

缓存

经常查询但不经常改变的数据【可以使用缓存】

MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存

<1>默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
<2>二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
<3>为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存

一级缓存

一级缓存也叫本地缓存:
与数据库同一次会话期间查询到的数据会放在本地缓存中。
以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
例子:测试

@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);

   User user = mapper.queryUserById(1);
   System.out.println(user);
   User user2 = mapper.queryUserById(1);
   System.out.println(user2);
   System.out.println(user==user2);

   session.close();
}

一级缓存失效情况:没有使用到当前的一级缓存,效果就是,还需要再向数据库中发起一次查询请求

sqlSession不同

@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   SqlSession session2 = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);
   UserMapper mapper2 = session2.getMapper(UserMapper.class);

   User user = mapper.queryUserById(1);
   System.out.println(user);
   User user2 = mapper2.queryUserById(1);
   System.out.println(user2);
   System.out.println(user==user2);

   session.close();
   session2.close();
}

观察结果:发现发送了两条SQL语句!
结论:每个sqlSession中的缓存相互独立

sqlSession相同,查询条件不同

@Testpublic void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);
   UserMapper mapper2 = session.getMapper(UserMapper.class);

   User user = mapper.queryUserById(1);
   System.out.println(user);
   User user2 = mapper2.queryUserById(2);
   System.out.println(user2);
   System.out.println(user==user2);

   session.close();
}

观察结果:发现发送了两条SQL语句!很正常的理解
结论:当前缓存中,不存在这个数据

sqlSession相同,两次查询之间执行了增删改操作!

增加方法
//修改用户int updateUser(Map map);
编写SQL

<update id="updateUser" parameterType="map">
  update user set name = #{name} where id = #{id}</update>
测试
@Testpublic void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);

   User user = mapper.queryUserById(1);
   System.out.println(user);

   HashMap map = new HashMap();
   map.put("name","kuangshen");
   map.put("id",4);
   mapper.updateUser(map);

   User user2 = mapper.queryUserById(1);
   System.out.println(user2);

   System.out.println(user==user2);

   session.close();
}

观察结果:查询在中间执行了增删改操作后,重新执行了
结论:因为增删改操作可能会对当前数据产生影响

sqlSession相同,手动清除一级缓存

@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   UserMapper mapper = session.getMapper(UserMapper.class);

   User user = mapper.queryUserById(1);
   System.out.println(user);

   session.clearCache();//手动清除缓存

   User user2 = mapper.queryUserById(1);
   System.out.println(user2);

   System.out.println(user==user2);

   session.close();
}

一级缓存就是一个map

二级缓存

(1)二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
(2)基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
(3)工作机制

  1. 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
  2. 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
  3. 新的会话查询信息,就可以从二级缓存中获取内容;
  4. 不同的mapper查出的数据会放在自己对应的缓存(map)中;

使用步骤:

1、开启全局缓存 【mybatis-config.xml】

<setting name="cacheEnabled" value="true"/>

2、去每个mapper.xml中配置使用二级缓存,这个配置非常简单;【xxxMapper.xml】

<cache/>

官方示例=====>查看官方文档<cache
 eviction="FIFO"
 flushInterval="60000"
 size="512"
 readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
截图显示:

3、代码测试
所有的实体类先实现序列化接口
测试代码

@Test
public void testQueryUserById(){
   SqlSession session = MybatisUtils.getSession();
   SqlSession session2 = MybatisUtils.getSession();

   UserMapper mapper = session.getMapper(UserMapper.class);
   UserMapper mapper2 = session2.getMapper(UserMapper.class);

   User user = mapper.queryUserById(1);
   System.out.println(user);
   session.close();

   User user2 = mapper2.queryUserById(1);
   System.out.println(user2);
   System.out.println(user==user2);

   session2.close();
}

缓存结论

只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
查出的数据都会被默认先放在一级缓存中
只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中;

缓存原理图:

在这里插入图片描述

自定义缓存:EhCache

1 Ehcache是一种广泛使用的java分布式缓存,用于通用缓存;
要在应用程序中使用Ehcache,需要引入依赖的jar包

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --><dependency>
   <groupId>org.mybatis.caches</groupId>
   <artifactId>mybatis-ehcache</artifactId>
   <version>1.1.0</version></dependency>

2 在mapper.xml中使用对应的缓存即可

<mapper namespace = “org.acme.FooMapper” >
   <cache type = “org.mybatis.caches.ehcache.EhcacheCache” /></mapper>

图例:
在这里插入图片描述

3 编写ehcache.xml文件,如果在加载时未找到/ehcache.xml资源或出现问题,则将使用默认配置。

<?xml version="1.0" encoding="UTF-8"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
        updateCheck="false">
   <!--
      diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
      user.home – 用户主目录
      user.dir – 用户当前工作目录
      java.io.tmpdir – 默认临时文件路径
    -->
   <diskStore path="./tmpdir/Tmp_EhCache"/>
   
   <defaultCache
           eternal="false"
           maxElementsInMemory="10000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="1800"
           timeToLiveSeconds="259200"
           memoryStoreEvictionPolicy="LRU"/>

   <cache
           name="cloud_user"
           eternal="false"
           maxElementsInMemory="5000"
           overflowToDisk="false"
           diskPersistent="false"
           timeToIdleSeconds="1800"
           timeToLiveSeconds="1800"
           memoryStoreEvictionPolicy="LRU"/>
   <!--
      defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
    -->
   <!--
     name:缓存名称。
     maxElementsInMemory:缓存最大数目
     maxElementsOnDisk:硬盘最大缓存个数。
     eternal:对象是否永久有效,一但设置了,timeout将不起作用。
     overflowToDisk:是否保存到磁盘,当系统当机时
     timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
     timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
     diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
     diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
     diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
     memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
     clearOnFlush:内存数量最大时是否清除。
     memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
     FIFO,first in first out,这个是大家最熟的,先进先出。
     LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
     LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
  -->
</ehcache>

合理的使用缓存,可以让我们程序的性能大大提升!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值