MyBatis学习总结(比较详细)

1.简介

什么是MyBatis?

MyBatis是一款优秀的持久层框架
MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

持久化:是将程序数据在持久状态和顺势状态间转换的机制

  • 即把数据(如内存中的对象)保存到可永久保护存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存在数据库中,或者存储在磁盘文件中,XML数据文件中等等

  • JDBC就是一种持久化机制。文件IO也是一种持久化机制。

2.第一个MyBatis程序

1、搭建实验数据库

MyBatis学习总结(比较详细)_第1张图片

2、导入MyBatis相关包

<dependencies>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
</dependencies>

3.编写MyBatis核心配置文件



<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8&characterEncoding=utf-8"/>
                <property name="username" value="ltg"/>
                <property name="password" value="991115"/>
            dataSource>
        environment>
    environments>
    
configuration>

4、编写MyBatis工具类

package com.ltg.utils;

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;

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        //使用Mybatis第一步,获取SqlSessionFactory 对象
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();

    }
}

5、创建实体类

package com.ltg.popl;

public class User {
    private Integer id;
    private String name;
    private String pwd;

    public User(){}
    public User(Integer id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

6、编写Mapper接口类

package com.ltg.dao;

import com.ltg.popl.User;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    //查询用户
    List<User> getUserList();

    //根据id查用户
    User getUserById(int id);

    //插入一个用户
    void insertUser(User user);

    //修改一个用户的信息
    void updataUser(User user);

    //删除一个用户
    void deleteUser(int id);


    /**/
    //模糊查询
    List<User> getLikeUser(String name);


    //使用map进行传递参数实例
    List<User> getUserById2(Map map);
}

7、编写Mapper.xml配置文件

  • namespace十分重要!!不能写错
<?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.ltg.dao.UserMapper">

    <select id="getUserList" resultType="com.ltg.popl.User">
    select * from mybatis.user
  </select>

    <select id="getUserById" resultType="com.ltg.popl.User">
        select * from mybatis.user where id = #{id}
    </select>

    <insert id="insertUser" parameterType="com.ltg.popl.User">
        insert into mybatis.user(id, name, pwd) values (#{id},#{name},#{pwd})
    </insert>

    <update id="updataUser" parameterType="com.ltg.popl.User">
        update mybatis.user set name = #{name} , pwd = #{pwd} where id = #{id} ;
    </update>

    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id = #{id}
    </delete>



    <select id="getLikeUser" parameterType="String" resultType="com.ltg.popl.User">
        select * from mybatis.user where name like "%"#{name}"%"
    </select>


    <select id="getUserById2" parameterType="map" resultType="com.ltg.popl.User">
        select * from mybatis.user where id = #{helloid}
    </select>
</mapper>

8、编写测试类

package com.ltg.dao;

import com.ltg.popl.User;
import com.ltg.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;

public class UserMapperTest {
    @Test
    public void test(){
        //第一步:获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<User> userList = null;
        try {
            /*方式一*/

            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            userList = userMapper.getUserList();

            /*方式二*/
//        List userList = sqlSession.selectList("com.ltg.dao.UserDao.getUserList");

            sqlSession.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            for (User user : userList) {
                System.out.println(user);
            }
        }
    }


    @Test
    public void addUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);

        sqlSession.close();
    }


    @Test
    public void insertUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.insertUser(new User(4,"小李","123456"));

        //!!!注意:增删改操作要提交事务
        sqlSession.commit();
        sqlSession.close();
    }


    @Test
    public void updataUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updataUser(new User(2 , "小花" , "99999"));

        sqlSession.commit();
        sqlSession.close();
    }


    @Test
    public void deleteUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUser(2);

        sqlSession.commit();
        sqlSession.close();
    }


    @Test
    public void getLikeUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> user = mapper.getLikeUser("小");
        for (User user1 : user) {
            System.out.println(user1);
        }

        sqlSession.close();
    }


    @Test
    public void getUserById2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("helloid",1);
        List<User> userById2 = mapper.getUserById2(map);
        for (User user : userById2) {
            System.out.println(user);
        }

        sqlSession.close();
    }
}

9、运行测试

10、万能map

1、在接口方法中,参数直接传递Map;

User selectUserByNP2(Map map);

2、编写sql语句的时候,需要传递参数类型,参数类型为map


3、在使用方法的时候,Map的 key 为 sql中取的值即可,没有顺序要求!

Map map = new HashMap();
map.put("username","小明");
map.put("pwd","123456");
User user = mapper.selectUserByNP2(map);

总结:如果参数过多,我们可以考虑直接使用Map实现,如果参数比较少,直接传递参数即可

11.可能出现的问题!!

1.Maven静态资源过滤:需要在pom.xml的中配置以下资源

<build>
    <resources>
        <resource>
            <directory>src/main/resourcesdirectory>
            <includes>
                <include>**/*.propertiesinclude>
                <include>**/*.xmlinclude>
            includes>
            <filtering>truefiltering>
        resource>
        <resource>
            <directory>src/main/javadirectory>
            <includes>
                <include>**/*.propertiesinclude>
                <include>**/*.xmlinclude>
            includes>
            <filtering>truefiltering>
        resource>
    resources>
build>

2.mapper的映射配置:在自己的mybatis-config.xml中配置mapper

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

3.配置解析

1.核心配置文件

  • mybatis-config.xml 系统核心配置文件
  • MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
  • 能配置的内容如下:
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

2.environments元素

<environments default="development">
 <environment id="development">
   <transactionManager type="JDBC">
     <property name="..." value="..."/>
   transactionManager>
   <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>
  • 配置MyBatis的运行多套环境,将SQL映射到不同的数据库上,必须指定其中一个默认运行环境(通过default指定)

  • 子元素节点:environment

    dataSource元素使用标准的JDBC数据源接口来配置JDBC连接对象的资源

    数据源是必须配置的

    有三种内建的数据源类型

    type="[UNPOOLED|POOLED|JNDI]")
    

    unpooled:这个数据源的实现只是每次被请求时打开和关闭连接。
    pooled:这种数据源的实现利用“池”的概念将JDBC连接对象组织起来,这是一种使得并发Web应用快速响应请求的流行处理方式。
    jndi:这个数据源的实现是为了能在如Spring或应用服务器这类容器中使用,容器可以集中在外部配置数据源,然后防止一个JNDI上下文应用/
    数据源也有很多第三方的实现:dbcp,druid,c3p0…

  • 子元素节点:transactionManager-[事务管理器]

    
    
    

    这两张事务管理器类型都不需要设置任何属性

3.mappers元素

  • 映射器 : 定义映射SQL语句文件
  • 既然 MyBatis 的行为其他元素已经配置完了,我们现在就要定义 SQL 映射语句了。但是首先我们需要告诉 MyBatis 到哪里去找到这些语句。Java 在自动查找这方面没有提供一个很好的方法,所以最佳的方式是告诉 MyBatis 到哪里去找映射文件。你可以使用相对于类路径的资源引用, 或完全限定资源定位符(包括 file:/// 的 URL),或类名和包名等。映射器是MyBatis中最核心的组件之一,在MyBatis 3之前,只支持xml映射器,即:所有的SQL语句都必须在xml文件中配置。而从MyBatis 3开始,还支持接口映射器,这种映射器方式允许以Java代码的方式注解定义SQL语句,非常简洁。

引入资源方式



 



 



 



 

Mapper的XML文件




   

  • namespace中文意思:命名控件,作用如下
    namespace的命名必须跟某个接口同名
    接口中的方法与映射文件中sql语句的id必须一一对应
    1. namespace的子元素的id联合保证唯一
    2. 绑定DAO接口
    3. namespace命名规则:包名+类名

MyBatis 的真正强大在于它的映射语句,和JDBC代码相比较,会减少大量的代码冗余,MyBatis为聚焦于SQL而构建,以尽可能地为你减少麻烦。

4.Properties优化

数据库这些属性都是可以外部配置且可动态替换的,既可以在典型的Java属性文件中配置,亦可以通过properties元素的子元素来传递。

我们可以优化一下我们的配置文件

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

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

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

如果外部配置文件和内部properties 有同一字段,优先使用外部配置文件


   
   

   
       
           
           
               
               
               
               
           
       
   
   
       
   

5.typeAliases

类型别名时为Java设置一个短的名字。它只和XML配置有关,存在的意义仅在于用来减少类完全限定名的冗余

1.当这样配置时,User可以用在任何使用com.kuang.pojo.User的地方。

        



2.也可以指定一个包名,MyBatis会在包名下搜索需要的JavaBean


   

每一个在包 com.kuang.pojo 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。

3.也可使用注解

@Alias("user")
public class User {
  ...
}

6.其它配置浏览

设置

  • 设置(settings)相关=>查看帮助文档

    • 懒加载
    • 日志实现
    • 缓存开启关闭
  • 一个配置完整的settings元素的示例如下

    <settings>
     <setting name="cacheEnabled" value="true"/>
     <setting name="lazyLoadingEnabled" value="true"/>
     <setting name="multipleResultSetsEnabled" value="true"/>
     <setting name="useColumnLabel" value="true"/>
     <setting name="useGeneratedKeys" value="false"/>
     <setting name="autoMappingBehavior" value="PARTIAL"/>
     <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
     <setting name="defaultExecutorType" value="SIMPLE"/>
     <setting name="defaultStatementTimeout" value="25"/>
     <setting name="defaultFetchSize" value="100"/>
     <setting name="safeRowBoundsEnabled" value="false"/>
     <setting name="mapUnderscoreToCamelCase" value="false"/>
     <setting name="localCacheScope" value="SESSION"/>
     <setting name="jdbcTypeForNull" value="OTHER"/>
     <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
    settings>
    

类型处理器

  • 无论是MyBatis在预处理语句(PrepareStatement)中设置一个参数时,还是从结果集中取出一个值时,都会用类型处理器将获取的值以合适的方式Java类型
  • 你可以重写类型处理器或你创建你自己的类型处理器来处理不支持或非标准的类型【了解即可】

对象工厂

  • MyBatis每次创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成。

  • 默认的对象工厂需要做的仅仅时实例化目标类,要么通过构造方法,要么在参数映射存在的时候通过有参构造方法来实例化。

  • 如果像覆盖对象工厂的默认行为,则可以通过创建自己的对象工厂来实现。【了解即可】

7.生命周期和作用域

作用域(scope)和生命周期

理解我们目前以及讨论过的不同作用于和生命周期类是至关重要的,因为错误的使用会导致非常严重的并发问题。

我么可以先画一个流程图,分析以下MyBatis的执行过程!
MyBatis学习总结(比较详细)_第2张图片

作用域理解

  • SqlSessionFactoryBuilder的作用在于创建SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder就会失去作用,所以它智能存在于创建SqlSessionFactory的方法中,而不是让其长期存在。因此SqlSessionFactoryBuilder实例的最佳作用域是方法作用域(也就是局部方法变量)。
  • SqlSessionFactory可以被认作是一个数据库连接池,它的作用是创建SqlSession的接口对象。因为MyBatis的本质就是Java对数据库的操作,所以SqlSessionFactory的生长周期存在于整个MyBatis的应用中,所以一旦创建了SqlSessionFactory,就要长期保存它,直至不再使用MyBatis的应用,所以可以认为SqlSessionFactory的生命周期就等同于MyBatis的应用周期。
  • 哟由于SqlSessionFactory是一个数据库的连接池,所以它占据着数据库的连接资源。如果创建多个SqlSessionFactory,那么就会存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
  • 因此在一般的应用中我们往往希望SqlSessionFactory作为一个单例,让它在应用中被共享。所以说SqlSessionFactory的最佳作用域是应用作用域。
  • 如果说SqlSessionFactory相当于数据库连接池,那么SqlSession就相当于一个数据库连接(Connection对象),你可以在一个事务里执行多条SQL,然后通过它的commit、rollback等方法,提交或者回滚事务。所以他应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给SqlSessionFactory,否则数据库资源很快就会被消耗光,系统就会瘫痪,所以用try–catch–finally–语句来保持其正确关闭。
  • 所以SqlSession的最佳作用域是请求或方法作用域

MyBatis学习总结(比较详细)_第3张图片

4.ResultMap以及分页

1.ResultMap

要解决的问题:属性名和字段名不一致

  • user表中的列名为pwd,现在将JavaBean中改成password,会出现查询到password=null的情况。

分析:

  • select*from user where id = #{id} 可以看做

    select id , name , pwd , form user where id = #{id}

  • mybatis会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写),去对应的实体类中查找相应列名的set方法设值,由于找不到setPwd(),所以password返回null;

    【自动映射】

解决方案

方案一:为列名指定别名,别名和Java实体类的属性名一致。

<select id="selectUserById" resultType="User">
  select id , name , pwd as password from user where id = #{id}
</select>

方案二:使用结果集映射->ResultMap【推荐】

   

        

        
        
    

    

ResultMap

自动映射

  • resultMap元素是MyBatis中最重要最强大的元素,它可以让你从90%的JDBC resultSets数据提起代码中解放出来。
  • 实际上,在为一些比如连接的复杂语句编写映射代码块的时候,一份resultMap能够实现同等功能的长达数千行的代码。
  • ResultMap的设计思想是,对于简单的语句根本不需要配置显示的结果映射,而对于复杂一点的语句只需要描述他们的关系就行了。

你已经见过简单映射语句的示例了,但并没有显式指定 resultMap。比如:


上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 不是一个很好的模型。你的程序更可能会使用 JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)作为模型。

ResultMap 最优秀的地方在于,虽然你已经对它相当了解了,但是根本就不需要显式地用到他们。

手动映射

  1. 返回值类型为resultMap

    
    
    1. 编写resultMap,实现手动映射!

       
      
      
      
      
              
          
      

这些是比较简单的案列,数据库中还有一对多,多对一,后面还有比较高级的结果集映射,association,collection这些。

2.日志工厂

思考:我们在测试SQL时,如果能在控制台输出SQL的画,是不是就可以有更快的排错效率?

如果一个数据库相关的操作出了问题,我们可以根据输出的SQL语句来快速排查问题。

对于以往的开发过程,我们经常会用到debug模式来调节,跟踪我们的代码执行过程。但是现在使用MyBatis是基于接口,配置文件的源代码执行过程。因此,我们必须选择日志工具来作为我们开发,调节程序的工具。

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

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK logging

具体选择哪个日志实现工具有MyBatis的内置日志工厂确定,它会使用最先找到的(按上面顺序) 。 如果一个都没找到,日志功能就会被禁用。

标准日志实现

指定MyBatis应该使用哪个日志记录实现。如果此设置不存在,则会自动发现日志记录实现。


    

这是在控制台输出日志。

image-20200803203630753

Log4j

简介:

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

使用步骤:

  1. 导入log4j的包

   log4j
   log4j
   1.2.17

  1. 配置文件的编写

    #将等级为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/kuang.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
    
  2. setting设置日志实现

    
        
    
    

    4.在程序中使用Log4j进行输出!

static Logger logger = Logger.getLogger(UserMapperTest.class);
@Test
public void testLog4j(){
    logger.info("info:进入了testLog4j");
    logger.debug("debug:进入了testLog4j");
    logger.error("error:进入了testLog4j");
}

5.控制台有输出

​ 还有一个日志生成的文件

log4j.appender.file.File=./log/ltg.log

3.limit实现分页

思考:为什么需要分页?

在学习mybatis等持久层框架时,会经常对数据进行增删改查操作,使用最多的时对数据库进行查询操作,如果查询大量数据时,我们往往使用分页进行查询,也就是每次处理小部分数据,这样对数据库压力就在可控范围内。

使用Limit实现分页

#语法
SELECT * FROM table LIMIT stratIndex,pageSize

SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15  

#为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:   
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.  

#如果只给定一个参数,它表示返回最大的记录行数目:   
SELECT * FROM table LIMIT 5; //检索前 5 个记录行  

#换句话说,LIMIT n 等价于 LIMIT 0,n。 

步骤

1、Mapper接口,参数为map

 //使用limit进行分页查询
    List getUserByLimit(Map map);

2、修改Mapper文件(limit需要的两个参数 startIndex 和 pageSize)


3、在测试类传入参数测试

@Test
public void getUserByLimit(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    HashMap map = new HashMap();
    map.put("startIndex" , 1);
    map.put("pageSize" , 3);
    List userByLimit = mapper.getUserByLimit(map);
    for (User user : userByLimit) {
        System.out.println(user);
    }
    sqlSession.close();
}

4.RowBounds实现分页

我们除了使用Limit在SQL层面实现分页,也可以使用RowBounds在Java代码层面实现分页,当然此种方式作为了解即可。

步骤:

1、mapper接口

//使用RowBounds进行分页拆线呢
List getUserByRowBounds();

2、mappe文件


3、测试类测试(需要new一个RowBounds类出来)

@Test
public void getUserByRowBounds(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    RowBounds rowBounds = new RowBounds(2, 3);

    //通过session**方法进行传递rowBounds,[!!这种方法现在以及不推荐使用了]
    List users = sqlSession.selectList("com.ltg.dao.UserMapper.getUserByRowBounds", null, rowBounds);
    for (User user : users) {
        System.out.println(user);
    }

    sqlSession.close();
}

了解即可,可以自己尝试使用

官方文档:https://pagehelper.github.io/

5.使用注解开发

1.面向接口编程

  • 大家之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程
  • 根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好
  • 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;
  • 而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

2.关于接口的理解

  • 接口从更深层次理解,应是定义(规范,约束)与实现(名实分离的原则)的分离

  • 接口本身反应了系统设计人员对系统抽象理解

  • 接口应该有两类:
    第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class)。
    第二类是对一个个体某一方面的抽象,即形成一个抽线面(interface)。

  • 一个个体可能有多个抽象面。抽象体与抽象面是有区别的。

3.三个面向的区别

  • 面向对象是指,我们考虑吧问题时,以对象为单位,考虑它的属性和方法。
  • 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现。
  • 接口设计与非接口设计时针对复用技术而言的,与面向对象(过程)不是一个问题,更多的体现就是对系统整体的架构。

4.利用注解开发

  • mybatis最初的配置信息时基于XML,映射语句(SQL)夜视定义在XML中的。而到mybatis 3 提供了新的基于注解的配置,不幸的是,Java注解的表达力和灵活性十分有限。最强大的Mybatis映射并不能通过注解来构建
  • sql类型主要分成:
    • @select()
    • @update()
    • @insert()
    • @delete()

!!注意:利用注解开发就不需要mapper.xml映射文件了

1、我们在我们的接口中添加注解

public interface UserMapper {
    //查询所有用户
    @Select("select * from user")
    List getUser();
}

2、在mybatis的核心配置文件中注入


    
        
    

3、测试

@Test
public void getUserMapper(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List user = mapper.getUser();
    for (User user1 : user) {
        System.out.println(user1);
    }


    sqlSession.close();
}

4.利用Debug查看本质
MyBatis学习总结(比较详细)_第4张图片

5、本质上利用了jvm的动态代理机制

MyBatis学习总结(比较详细)_第5张图片

5.mybatis的详细执行流程

MyBatis学习总结(比较详细)_第6张图片

6.注解实现增删改查

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

//设置事务自动提交  flag为true时为自动提交事务
public static SqlSession getSqlSession(boolean flag){
    return sqlSessionFactory.openSession(flag);
}

注意:确保实体类和数据库字段对应

查询:

1、编写接口方法注解

//按照id查询用户
@Select("select * from user where id = #{id}")
List getUserById(@Param("id") int id);

2、测试

增加

1、编写接口方法注解

//添加一个用户
@Insert("insert into user(id , name , pwd) values(#{id} , #{name} , #{password})")
int insertUser(User user);

2、测试

修改一条信息

1、编写接口方法注解

//修改一个用户信息
@Update("update user set name = #{name},pwd = #{password} where id = #{id}")
int updateUser(User user);

2、测试

删除一条信息
1、编写接口方法注解

//删除一条用户信息
@Delete("delete from user where id = #{id}")
void deleteUser(@Param("id") int id);

2、测试

关于@Param

@Param注解用于给方法参数起一个名字。以下时总结的使用原则

  • 在方法只接受一个参数情况下,可以不使用@Param
  • 在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
  • 如果参数时JavaBean,则不能使用@Param.
  • 不适用@Param时 参数只能有一个,并且是JavaBean.

#和$的区别

  • #{}的作用主要是替换预编译语句(PrepareStatement)中的占位符 ?【推荐】

    INSERT INTO user (name) VALUES (#{name});
    INSERT INTO user (name) VALUES (?);
    
  • ${}的作用是直接进行字符串的替换(sql注入问题)

    INSERT INTO user (name) VALUES ('${name}');
    INSERT INTO user (name) VALUES ('kuangshen');
    

使用注解和配置文件协同开发,才是Mybatis的最佳实战

6、一对多和多对一处理

1、多对一处理

多对一的理解:

  • 多个学生对应一个老师
  • 如果对于学生这边,就是一个多对一的现象,即从学生这边关联一个老师 !

数据库设计

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '李老师');

CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8


INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

搭建测试环境

1、IDEA安装Lombok插件

2、引入Maven依赖



 org.projectlombok
 lombok
 1.16.10

注意!!我没用上面这个插件

3、编写实体类Teacher和Student

4、编写实体类对应的Mapper接口【两个】

  • 无论有没有需求,都应该写上,以备后来之需
public interface StudentMapper {
}
public interface TeacherMapper {
}

5、编写Mapper接口对应的mapper.xml配置文件【两个】

  • 无论有没有需求,都应该写上,以备后来之需










第一种:按查询嵌套处理(子查询)

1、给StudentMapper接口增加方法

public interface StudentMapper {
    List getStudent();
}

2、编写对应的Mapper文件

第一种:按照查询嵌套处理


    


3、去mybatis-config核心配置文件注册一个Mapper!!


    
    

4、注意点说明


   
   



5、测试

第二种:按结果嵌套处理(联表查询)(本人推荐使用)

1、就用上面那个接口

2、编写对应的mapper文件


    

    
        
        
           
        
            
            
        
    

3、测试

public void test2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List student = mapper.getStudent();
    for (Student student1 : student) {
        System.out.println(student1);
    }

2、一对多处理

一对多的理解:

  • 一个老师拥有多个学生
  • 对于老师这边,就有一堆学生(集合),这就是一对多现象

1、实体类和上面不同要修改

public class Student {
    private int id;
    private String name;
    private int tid;
public class Teacher {
    private int id;
    private String name;
    private List student;

第一种:按结果嵌套处理

1、TeacherMapper接口方法编写

public interface TeacherMapper {
    //获取指定老师,以及老师下的学生
    List getTeacher(int id);
}

2、编写接口对应的Mapper配置文件


   


    
    
    
        
        
        
    

3、注意注册Mapper文件到mybatis-config核心配置文件中

4、测试

@Test
public void test1(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
    List teacher = mapper.getTeacher(1);
    for (Teacher teacher1 : teacher) {
        System.out.println(teacher1);
    }

    sqlSession.close();
}

第二种:按查询嵌套查询

1、直接用上一个接口方法

2、编写接口对应的Mapper配置文件

第二种:按照查询嵌套处理



    


3、还是注意把Mapper注册到mybatis-config核心配置文件中

4、测试

小结

1、关联-association(多对一)

2、集合-collection(一对多)

4、JavaType和ofType都是用来指定对象类型的

  • Javatype是用来指定poko属性的类型
  • ofType指定的是映射到List集合中的pojo类型,集合约束的泛型

注意点

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多,多对一中,属性名和字段的问题!!
  • 排错用Log4j

面试必考

  • MySQL引擎
  • InnoDB的底层原理
  • 索引
  • 索引优化

7、动态SQL

介绍

什么是动态SQL:动态SQL指的是根据不同的查询条件,生成不同的SQL语句

官网描述:
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

  -------------------------------
  - if
  - choose (when, otherwise)
  - trim (where, set)
  - foreach
  -------------------------------

我们之前写的 SQL 语句都比较简单,如果有比较复杂的业务,我们需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。

那么怎么去解决这个问题呢?这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。

搭建环境

新建一个数据库表:blog

字段:id,title,author,create_time,views

CREATE TABLE `blog` (
`id` varchar(50) NOT NULL COMMENT '博客id',
`title` varchar(100) NOT NULL COMMENT '博客标题',
`author` varchar(30) NOT NULL COMMENT '博客作者',
`create_time` datetime NOT NULL COMMENT '创建时间',
`views` int(30) NOT NULL COMMENT '浏览量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8

1、创建Mybatis基础工程

这里就不截图了

2、IdUtil工具类(目的是为了产生随机的id)

public class IdUtil {
    public static String genId(){
        return UUID.randomUUID().toString().replaceAll("-","");
    }
}

3、实体类编写

public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;

4、编写Mpper接口以及对应的xml文件

public interface BlogMapper {
}





5、mybatis核心配置文件,设置下划线驼峰自动转换


6、插入原始数据

  • 编写接口
//新增一个博客
int addBlog(Blog blog);
  • mapper配置文件

     insert into blog (id, title, author, create_time, views)
    values (#{id},#{title},#{author},#{createTime},#{views});

  • 初始化博客信息
@Test
public void addInitBlog(){
   SqlSession session = MybatisUtils.getSession();
   BlogMapper mapper = session.getMapper(BlogMapper.class);

   Blog blog = new Blog();
   blog.setId(IDUtil.genId());
   blog.setTitle("Mybatis如此简单");
   blog.setAuthor("狂神说");
   blog.setCreateTime(new Date());
   blog.setViews(9999);

   mapper.addBlog(blog);

   blog.setId(IDUtil.genId());
   blog.setTitle("Java如此简单");
   mapper.addBlog(blog);

   blog.setId(IDUtil.genId());
   blog.setTitle("Spring如此简单");
   mapper.addBlog(blog);

   blog.setId(IDUtil.genId());
   blog.setTitle("微服务如此简单");
   mapper.addBlog(blog);
   
   blog.setId(IdUtil.genId());
   blog.setTitle("HTML如此简单");
   blog.setAuthor("李刚");
   blog.setCreateTime(new Date());
   blog.setViews(1000);
   mapper.addBlog(blog);
   
   session.commit();
   session.close();
}

初始化数据完毕!

一、if语句

1、编写接口

/根据作者名字和博客名字来查询博客!
//如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
List querryBlogIf(Map map);

2、编写对应mapper文件

 
 

3、测试

@Test
public void testQuerryForIf(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("title" , "HTML如此简单");
    map.put("author" , "李刚");
    List blogs = mapper.querryBlogIf(map);

    for (Blog blog : blogs) {
        System.out.println(blog);
    }


    sqlSession.close();
}

这样写我们可以看到,如果 author 等于 null,那么查询语句为 select * from user where title=#{title},但是如果title为空呢?那么查询语句为 select * from user where and author=#{author},这是错误的 SQL 语句,如何解决呢?请看下面的 where 语句!

二、where

1、修改上面的sql后的


这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。

三、Set

同理,上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词,我们怎么处理呢?

1、编写接口方法

//更新博客
int updateBlog(Map map);

2、编写对应的mapper文件


    
        update blog
        
        
            
                title = #{title},
            
            
                author = #{author},
            
        
        where id = #{id}
    

3、测试

@Test
public void updateBlog(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    //map.put("title" , "Mybatis如此简单");
    map.put("author" , "李刚");
    map.put("id" ,"cf83426b6ea24c18881c5735f3a89f20");

    mapper.updateBlog(map);


    sqlSession.commit();
    sqlSession.close();
}

四、choose

有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句

1、编写接口方法

List querryBlogChoose(Map map);

2、编写对应的mapper配置文件


    

3、测试

@Test
public void testQuerryBlogChoose(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("title" , "Java如此简单");
    map.put("author" , "李刚");
    map.put("views" , "1000");

    List blogs = mapper.querryBlogChoose(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }


    sqlSession.close();
}

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

!!提示:上面的测试可以更改参数来测试各个语句的真正功能(比如少传一个参数,多传一个)

五、SQL片段

有时候可能某个sql语句我们用的特别多,为了增强代码重用性,简化代码,我们学要将这些代码抽取出来,然后使用时直接调用。

提取SQL片段


        
            title = #{title}
        
        
            and author = #{author}
        

引用SQL片段


注意

  • 最好基于单表来定义sql片段,提高片段的可重用性
  • 再定义的sql片段中,不要包括where

六、Foreach

将数据库中前三个数据的id修改为1、2、3

需求:我们需要查询blog表中id分为别为1、2、3的博客信息

1、编写接口

//foreach查询
List querryBlogForeach(Map map);

2、编写对应mapper配置文件



    

3、测试

@Test
public void testQuerryForeach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    ArrayList ids = new ArrayList();
    ids.add(1);
    ids.add(2);
    ids.add(3);
    map.put("ids" , ids);

    List blogs = mapper.querryBlogForeach(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }


    sqlSession.close();
}

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议

  • 先在MySQL中写出完整的SQL,再去对应的修改成为我们的动态SQL实现通用即可

8、缓存

简介

1、什么是缓存 [ Cache ]?

  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

2、为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率。

3、什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据

一、Mybatis缓存

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

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

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

二、一级缓存

一级缓存也叫本地缓存:

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

测试:1、在mybatis中加入日志,方便测试结果

2、编写接口方法

//根据id查询用户
User queryUserById(@Param("id") int id);

3、接口对应的Mapper文件


4、测试

@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();
}

结果分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JSdoTZ6Y-1596965436661)(C:\Users\litiangang\AppData\Roaming\Typora\typora-user-images\image-20200808193847046.png)]

一级缓存失效的四种情况

一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它;

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

1、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中的缓存相互独立

2、sqlSession相同,查询条件不同

@Test
public 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语句!很正常的理解

结论:当前缓存中,不存在这个数据

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

增加方法

//修改用户
int updateUser(Map map);

编写SQL


  update user set name = #{name} where id = #{id}

测试

@Test
public 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();
}

观察结果:查询在中间执行了增删改操作后,重新执行了

结论:因为增删改操作可能会对当前数据产生影响

4、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

三、二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;

  • 工作机制

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

使用步骤

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


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



官方示例=====>查看官方文档

这个更高级的配置创建了一个 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中的查询,可以在二级缓存中拿到数据
  • 查出的数据都会被默认先放在一级缓存中
  • 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中

缓存原理图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8nFoDMpK-1596965436666)(D:\DeskTop\缓存.png)]

四、Ehcache

第三方缓存实现–EhCache: 查看百度百科

Ehcache是一种广泛使用的java分布式缓存,用于通用缓存;

要在应用程序中使用Ehcache,需要引入依赖的jar包



   org.mybatis.caches
   mybatis-ehcache
   1.1.0

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

 
    

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



   
   
   
   

   
   
   


ybatis.caches
   mybatis-ehcache
   1.1.0

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

 
    

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



   
   
   
   

   
   
   


你可能感兴趣的:(ssm,mysql,java)