Mybatis

2023-11-08

一、Mybatis简介

1.1 简介

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

1.2 持久化

​ 持久化通俗来说就是数据持久化,就是将程序的数据在持久状态和瞬时状态转化的过程。

内存:断电即失

持久化方式:数据库、io文件持久化等。

1.3 持久层

Dao层、Service层、Controller层

  • 完成持久化工作的代码块
  • 层界限十分明显

1.4 为什么用Mybatis

​ Mybatis可以帮助我们将数据存入到数据库中。使用方便,学习成本低,相比传统的JDBC来说更简单。

​ 优点:

  • 简单易学
  • 灵活
  • sql和代码的分离,提高了可维护性,解耦
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql

二、第一个Mybatis程序

2.1 搭建环境

1.新建项目(maven),然后删除src目录,之后把这个项目当做父工程。以后通用的依赖放在父工程的pom.xml中,子工程可以直接使用。

2.导入maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.javasm</groupId>
    <artifactId>MybatisPro</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>day01</module>
    </modules>

    <dependencies>
        <!--        mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!--        mybatis框架-->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>

        <!--        junit测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>
    
</project>

3.创建Moudle,当做子工程。

4.编写mybatis的核心配置文件。

package com.javasm.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;

/**
 * @Author: huerxin
 * @version: 1.0
 * @Date: 2022/12/13-15:26
 * @Since:jdk1.8
 * @Description:
 */
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;


    static {
        try {
            //1.指定配置文件位置
            String resource = "mybatis-config.xml";
            //2.读取配置文件,转成流对象
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //3.根据流对象创建sqlSessionFactory对象
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession对象
     * @return
     */
    public static SqlSession getSqlSession() {
        //4.工厂创建SqlSession
        return sqlSessionFactory.openSession();
    }


}

5.编写properties文件,配置driver、数据库账号密码等。然后在核心配置文件中引入即可。

  • 在resources包中编写db.properties文件
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/bankingdb?useSSL=false
username=root
password=root
  • 在核心配置文件中引入db.properties文件
<!--引入外部配置文件-->
<properties resource="db.properties"/>

6.编写mybatis工具类

package com.javasm.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;

/**
 * @Author: huerxin
 * @version: 1.0
 * @Date: 2022/12/13-15:26
 * @Since:jdk1.8
 * @Description:
 */
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;


    static {
        try {
            //1.指定配置文件位置
            String resource = "mybatis-config.xml";
            //2.读取配置文件,转成流对象
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //3.根据流对象创建sqlSessionFactory对象
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession对象
     * @return
     */
    public static SqlSession getSqlSession() {
        //4.工厂创建SqlSession
        return sqlSessionFactory.openSession();
    }


}

7.在父工程的pom.xml中添加一段代码、防止资源导出失败的问题。

 <!--防止我们资源导出失败的问题-->
<!--pom.xml-->
<build>
	<resources>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
 	</resource>
  	<resource>
    <directory>src/main/java</directory>
    <includes>
      <include>**/*.properties</include>
      <include>**/*.xml</include>
    </includes>
      <filtering>true</filtering>
      
  </resource>
  </resources>
</build>

8.CRUD

  • 实体类

    package com.javasm.entity;
    
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.util.Date;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Sysuser {
    
      private long uid;
      private String uname;
      private String upwd;
      private String uemail;
      private String phone;
      private Date createTime;
      private Date updateTime;
      private String deleted;
      private long rid;
    
    
      public Sysuser(long uid, String uname, String upwd) {
        this.uid = uid;
        this.uname = uname;
        this.upwd = upwd;
      }
    
      public Sysuser(String uname, String upwd) {
        this.uname = uname;
        this.upwd = upwd;
      }
    }
    
  • SysuserMapper接口

package com.javasm.mapper;

import com.javasm.entity.Sysuser;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @Author: huerxin
 * @version: 1.0
 * @Date: 2022/12/13-15:19
 * @Since:jdk1.8
 * @Description:
 */
public interface SysuserMapper {
    /**
     * 查询所有的用户
     * @return
     */
    List<Sysuser> findList();

    /**
     * 添加
     * @param sysuser
     * @return
     */
    Boolean addUser(Sysuser sysuser);

    /**
     * 添加
     * @param uid
     * @return
     */
    Boolean deleteUser(@Param("uid") Integer uid);

    /**
     * 修改
     * @param sysuser
     * @return
     */
    Boolean updateUser(Sysuser sysuser);

    /**
     * 根据id查询用户
     * @param uid
     * @return
     */
    Sysuser findById(@Param("uid") Integer uid);
}
  • 创建SysuserMapper.xml文件,编写sql语句

    <?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.javasm.mapper.SysuserMapper">
        <insert id="addUser" >
            insert into sysuser(uname,upwd) values (#{uname},#{upwd});
        </insert>
        <update id="updateUser"  >
            update sysuser set uname=#{uname},upwd=#{upwd} where uid=#{uid}
        </update>
        <delete id="deleteUser" parameterType="int">
            delete from sysuser where uid=#{uid}
        </delete>
    
        <select id="findList" resultType="Sysuser">
            select * from sysuser;
        </select>
        <select id="findById" resultType="Sysuser">
             select * from sysuser where uid=#{uid}
        </select>
    </mapper>
    
  • junit单元测试

    package com.javasm.mapper;
    
    import com.javasm.entity.Sysuser;
    import com.javasm.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.Date;
    import java.util.List;
    
    import static org.junit.Assert.*;
    
    /**
     * @Author: huerxin
     * @version: 1.0
     * @Date: 2022/12/13-15:24
     * @Since:jdk1.8
     * @Description:
     */
    public class SysuserMapperTest {
    
        /**
         * 查询所有
         */
        @Test
        public void findList() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
            List<Sysuser> sysuserList = mapper.findList();
            sysuserList.forEach(System.out::println);
            sqlSession.close();
        }
    
        /**
         * 添加
         */
        @Test
        public void addUser() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
            Sysuser sysuser =new Sysuser("朱凯","ewrwe");
            mapper.addUser(sysuser);
            sqlSession.commit();
            sqlSession.close();
        }
    
        /**
         * 删除
         */
        @Test
        public void deleteUser() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
            mapper.deleteUser(51);
            sqlSession.commit();
            sqlSession.close();
        }
    
        /**
         * 修改
         */
        @Test
        public void updateUser() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
            Sysuser sysuser =new Sysuser(50,"朱凯1111","ewrwe");
            mapper.updateUser(sysuser);
            sqlSession.commit();
            sqlSession.close();
        }
    
        /**
         * 根据id查用户
         */
        @Test
        public void findById() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
            Sysuser sysuser = mapper.findById(1);
            System.out.println(sysuser);
            sqlSession.close();
        }
    }
    
    

2.2 总结

  • 配置文件没有注册
  • 绑定接口错误
  • 方法名不对
  • 返回类型写错了
  • Maven导出资源问题 -->在pom.xml中加入上面的代码
  • 写完后记得关闭,增删改记得提交事务

三、万能的Map

3.1 为什么使用map

  • 使用map传参,可以任意的添加参数,在参数纵多的时候,使用起来特别方便。

接口

/**
 * 用map传参
 * @param map
 * @return
 */
Boolean addUser2(Map<String,Object> map);

xml文件中

<insert id="addUser2">
    insert into sysuser (uname,upwd,phone) values (#{uname},#{upwd},#{phone});
</insert>

juint单元测试

/**
 * 用map传参添加
 */
@Test
public void addUser2() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
    Map<String,Object> map =new HashMap<>();
    map.put("uname","qwerqwe");
    map.put("upwd","werwqe");
    map.put("phone","15616846843");
    mapper.addUser2(map);
    sqlSession.commit();
    sqlSession.close();
}
  • 动态sql查询的时候,也可以动态的传入参数,方便后面修改业务。

比如之前写过的金融项目,里面的动态sql就用到了map。

<where>
    <if test="map!=null">
        <if test="map.productName!=null and map.productName!='' ">
            and b.product_name like "%"#{map.productName}"%"
        </if>
        <if test="map.product_secondary_classification!=null">
            and b.product_secondary_classification = #{map.productSecondaryClassification}
        </if>
        <if test="map.auditStatus!=null">
            and b.audit_status = #{map.auditStatus}
        </if>
    </if>
</where>

四、ORM框架

4.1 什么是ORM

ORM,==即Object-Relational Mapping(对象关系映射)==,它的作用是在关系型数据库和业务实体对象之间作一个映射,这样,我们在具体的操作业务对象的时候,就不需要再去和复杂的SQL语句打交道,只需简单的操作对象的属性和方法。

4.2 为什么会出现ORM思想

先从项目中数据流存储形式这个角度说起。简单拿MVC这种分层模式来说, Model作为数据承载实体。 在用户界面层和业务逻辑层之间数据实现面向对象OO形式传递。 当我们需要通过Control层分发请求把数据持久化时我们会发现。 内存中的面向对象的OO如何持久化成关系型数据中存储一条实际数据记录呢?

​ 面向对象是从软件工程基本原则(如耦合、聚合、封装)的基础上发展起来的,而关系数据库则是从数学理论发展而来的。两者之间是不匹配的。而ORM作为项目中间件形式实现数据在不同场景下数据关系映射。对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。ORM就是这样而来的。
在这里插入图片描述

4.3 ORM优缺点

优势

​ 第一:隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。

​ 第二:ORM使我们构造固化数据结构变得简单易行。在ORM年表的史前时代,我们需要将我们的对象模型转化为一条一条的SQL语句,通过直连或是DB helper在关系数据库构造我们的数据库体系。而现在,基本上所有的ORM框架都提供了通过对象模型构造关系数据库结构的功能。这相当不错。

缺点

​ 第一:无可避免的,自动化意味着映射和关联管理,代价是牺牲性能(早期,这是所有不喜欢ORM人的共同点)。现在的各种ORM框架都在尝试使用各种方法来减轻这块(LazyLoad,Cache),效果还是很显著的。

 第二:面向对象的查询语言(X-QL)作为一种数据库与对象之间的过渡,虽然隐藏了数据层面的业务抽象,但并不能完全的屏蔽掉数据库层的设计,并且无疑将增加学习成本。

 第三:对于复杂查询,ORM仍然力不从心。虽然可以实现,但是不值的。视图可以解决大部分calculated  column,case ,group,having,order by, exists,但是查询条件(a and b and not c and  (d or d))就解决不了。

4.4 mybatis为什么是半自动ORM框架

​ Hibernate 属于全自动 ORM 映射工具,使用 Hibernate 查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。==而 Mybatis 在查询关联对象或关联集合对象时,需要手动编写 sql 来完成,==所以,称之为半自动 ORM 映射工具。

4.5 Mybatis是否支持延迟加载

​ 支持。Mybatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载, association指的就是多对一, collection 指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载LazyLoadingEnabled=true|false。

​ 他的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送实现保存好的查询关联B对象的SQL,把B查询上来,然后调用a.setB(b),于是a的对象b熟悉就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

4.6 库和框架的区别

​ 库和框架都是一种有别于软件、面向程序开发者的产品形式。正因为如此,也有很多人误以为库就是框架,或者认为指定语言的库就是框架。

​ 库是将代码集合成的一个产品,供程序员调用。面向对象的代码组织形式而成的库也叫类库。面向过程的代码组织形式而成的库也叫函数库。在函数库中的可直接使用的函数叫库函数。开发者在使用库的时候,只需要使用库的一部分类或函数,然后继续实现自己的功能。

​ ==框架则是为解决一个(一类)问题而开发的产品,==框架用户一般只需要使用框架提供的类或函数,即可实现全部功能。可以说,框架是库的升级版。开发者在使用框架的时候,必须使用这个框架的全部代码。

五、XML配置解析

5.1 顶层结构

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

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

5.2 属性(properties)

​ 这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。

<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="root"/>
  <property name="password" value="123456"/>
</properties>

​ 编写配置文件db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/4032?useSSL=false
username=root
password=root

​ 设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

​ 注意:如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载。

  1. 首先读取在 properties 元素体内指定的属性。
  2. 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
  3. 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。

因此,通过方法参数传递的属性具有最高优先级,resource/url属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。

5.3 设置(settings)

​ 这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。下表描述了设置中各项设置的含义、默认值等。

设置名 描述
mapUnderscoreToCamelCase 是否开启驼峰命名自动映射
logImpl 开启打印日志,如log4j

其他的设置用的比较少,可以直接去官网看。https://mybatis.org/mybatis-3/zh/getting-started.html

5.4 类型别名(typeAliases)

​ 类型别名是为了Java类型设置一个短的名字。存在的意义仅用来减少类完全限定名的冗余。

  1. 给实体类起别名

    <!--可以给实体类起别名-->
        <typeAliases>
            <typeAlias type="com.javasm.entity.User" alias="user"/>
        </typeAliases>
    
    
  2. 可以扫描实体类的包,默认别名就是这个类的别名

    <!--给实体类取别名-->
    <typeAliases>
        <!--<typeAlias type="com.javasm.system.entity.AdminInfo" alias="AdminInfo"/>-->
    
        <!--扫描实体类的包,他的默认别名就为这个类的别名,首字母小写-->
        <package name="com.javasm.system.entity"/>
        <package name="com.javasm.unicorn.entity"/>
        <package name="com.javasm.product.entity"/>
    </typeAliases>
    

    第二种方法也可以diy别名,但需要在实体类上加上注解,如@Alias(“asuser”),那这个类的别名就是这个注解里面的值。

5.5 环境配置(environments)

​ MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中,现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。

不过要记住:尽管可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境。

5.6 其他

  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
    • MyBatis-plus
    • mybatis-generator-core
    • 通用mapper

5.7 映射器(mappers)

​ 既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉MyBatis 到哪里去找映射文件。

  1. 使用相对路径的资源引用 【推荐使用】

    <mappers>
    	<mapper resource="com/javasm/dao/UserMapper.xml"/>
    </mappers>
    
  2. 使用映射器接口实现类的完全限定名​

    <mppers>
    	<mpper class="com.javasm.dao.UserMapper"/>
    </mppers>
    
  3. 将包内的映射器接口全部注册为映射器

<mppers>
	<package  name="com.javasm.dao"/>
</mppers>

总结:方式二和方式三的接口和Mapper配置文件必须同名,并且在同一个包下。

5.8 作用域(Scope)和生命周期

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

1、SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了SqlSessionFactory,就不再需要它了。SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

2、SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,==没有任何理由丢弃它或重新创建另一个实例。==使用的最佳实践是在应用运行期间不要重复创建多次,最简单的就是使用单例模式或者静态单例模式。

3、SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。用完之后赶紧关闭

六、日志

6.1 日志工厂

​ 如果一个数据库操作,出现了异常,我们需要排错。日志是最好的帮手。过去我们使用sout、debug,而现在可以使用日志工厂。

  • SLF4J

  • LOG4J :需要掌握

  • LOG4J2

  • JDK_LOGGING

  • COMMONS_LOGGING

  • STDOUT_LOGGING :需要掌握

  • NO_LOGGING

    在MyBatis中具体使用那一日志实现,在设置中设定!日志工厂的实现:STDOUT_LOGGING

6.2 LOG4J

​ Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台,文件,GUI组件。

​ 我们可以空指每一条日志的输出格式,通过定义每一条日志信息的级别,哦我们可以更加细致的空指日志的生成过程。

​ 可以通过配置文件来配置,不需要修改代码。

1、导包

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

2、创建log4j.properties

### 设置###
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =D://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

3、在核心配置文件中,配置注册日志文件。

    <!--日志文件-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

七、多对一

7.1 数据库

-- 员工表
drop table if exists tb_emp;
create table tb_emp(
	id int(30) primary key auto_increment,
	e_name varchar(30),
	age int(30),
	did int(30)
);


-- 部门表
drop table if exists tb_dept;
create table tb_dept(
	id int(30) primary key auto_increment,
	d_name varchar(30)
);

insert into tb_emp values(null,"朱凯",23,1);
insert into tb_emp values(null,"刘亚国",20,1);
insert into tb_emp values(null,"吴亦凡",30,2);
insert into tb_emp values(null,"李云迪",32,2);
insert into tb_emp values(null,"蔡徐坤",26,2);
insert into tb_emp values(null,"吴京",29,3);
insert into tb_emp values(null,"王宝强",36,3);

insert into tb_dept values(null,"销售部");
insert into tb_dept values(null,"开发部");
insert into tb_dept values(null,"前端部");

7.2 实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private  Integer id;
    private String dName;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Integer id;
    private String eName;
    private Integer age;
    private Dept dept;  --多个员工属于一个部门

}

7.3 接口

public interface EmpMapper {
    /**
     * 按照结果嵌套处理
     * @return
     */
    List<Emp> selectEmp();

    /**
     * 按照查询嵌套处理
     * @return
     */
    List<Emp> selectEmp2();
}

7.4 Mapper.xml写sql语句

<?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.javasm.mapper.EmpMapper">

    <!--按照结果嵌套处理-->
    <select id="selectEmp" resultMap="EmpAndDept">
        select e.id id,e.e_name ename,e.age age,d.d_name dname
        from tb_emp e,tb_dept d where d.id=e.did ;
    </select>


    <!--字段需要一一对应-->
    <!--结果封装,将查询出来的列封装到对象属性中-->
    <resultMap id="EmpAndDept" type="Emp">
        <result column="id" property="id"/>
        <result column="ename" property="eName"/>
        <result column="age" property="age"/>
        <association property="dept" column="did" javaType="Dept">
            <result column="id" property="id"/>
            <result column="dname" property="dName"/>
        </association>

    </resultMap>





    <!--按照查询嵌套处理-->
    <select id="selectEmp2" resultMap="EmpAndDept2">
        select * from tb_emp
    </select>

    <select id="selectDept" resultType="Dept">
        select * from tb_dept where id=#{did};
    </select>

    <resultMap id="EmpAndDept2" type="Emp">
        <result column="id" property="id"/>
        <result column="e_name" property="eName"/>
        <result column="age" property="age"/>
        <!--复杂的属性,我们需要单独出来 对象:association 集合:collection-->
        <association property="dept" javaType="Dept" select="selectDept" column="did"/>
     </resultMap>
</mapper>

7.5 juint单元测试

public class EmpMapperTest {


    /**
     * 按照结果嵌套处理
     */
    @Test
    public void selectEmp() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        List<Emp> emps = mapper.selectEmp();
        for (Emp emp : emps) {
            System.out.println(emp);
        }
        sqlSession.close();
    }


    /**
     * 按照查询嵌套处理
     */
    @Test
    public void selectEmp2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        List<Emp> emps = mapper.selectEmp2();
        for (Emp emp : emps) {
            System.out.println(emp);
        }
        sqlSession.close();
    }
}

7.6 测试结果

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

7.7 总结

​ 显而易见,这两种方式都能处理多对一的问题。按照查询嵌套处理就是子查询。按照结果嵌套处理就是连表查询。

多对一 ------>【关联】 -------> 【association 】

一对多 ------> 【集合】--------> 【collection 】

八、一对多

8.1 数据库

​ 数据库和上面的一样。

8.2 实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Integer id;
    private String eName;
    private Integer age;
    private Integer did;

}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private  Integer id;
    private String dName;
    private List<Emp> emps;
}

8.3 接口

public interface DeptMapper {
   /**
    * 按照结果嵌套处理
    * @param id
    * @return
    */
   Dept findDept(int id);


   /**
    * 按照查询嵌套处理
    * @param id
    * @return
    */
   Dept findDept2(int id);

}

8.4 Mapper.xml写sql语句

<?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.javasm.mapper.DeptMapper">


    <!--按结果嵌套处理-->
    <select id="findDept" resultMap="DeptAndEmp">
        select d.id did,d.d_name dname,e.id eid,e.e_name ename,e.age age,e.did did
        from tb_dept d,tb_emp e where d.id=e.did;
    </select>

    <resultMap id="DeptAndEmp" type="Dept">
        <result column="did" property="id"/>
        <result column="dname" property="dName"/>
        <collection property="emps" ofType="Emp">
            <result column="eid" property="id"/>
            <result column="ename" property="eName"/>
            <result column="age" property="age"/>
            <result column="did" property="did"/>
        </collection>
    </resultMap>




    <!--按查询结果嵌套处理-->
    <select id="findDept2" resultMap="DeptAndEmp2">
        select * from tb_dept where id=#{id};
    </select>

    <select id="getEmp" resultType="Emp">
        select * from tb_emp where did=#{did};
    </select>


    <resultMap id="DeptAndEmp2" type="Dept">
        <result column="id" property="id"/>
        <result column="d_name" property="dName"/>
        <collection property="emps" javaType="ArrayList" ofType="Emp" select="getEmp" column="id"/>
    </resultMap>

</mapper>

7.5 juint单元测试

public class DeptMapperTest {

    /**
     * 按照结果嵌套处理
     */
    @Test
    public void findDept() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = mapper.findDept(1);
        System.out.println(dept);
        sqlSession.close();
    }

    /**
     * 按照查询嵌套处理
     */
    @Test
    public void findDept2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        Dept dept = mapper.findDept2(1);
        System.out.println(dept);
        sqlSession.close();
    }
}

7.6 测试结果

在这里插入图片描述

即员工作为一个集合存储在对象中。

7.7 总结

1、关系

​ 多对一 ------>【关联】 -------> 【association 】

​ 一对多 ------> 【集合】--------> 【collection 】

2、JavaType & ofType

​ JavaType 用来指定实体类中属性的类型。

​ ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型。

九、使用注解开发

9.1 面向接口编程

​ 根本原因:解耦,可扩展,提高复用,分层开发中,上层开发中,上层不用管具体的实现,大家都会遵守共同的标准,使得开发变得容易,规范性更好

9.2 注解CRUD

public interface SysroleMapper {

    /**
     * 查询所有的角色
     * @return
     */
    @Select("select * from sysrole")
    List<Sysrole> showAllRole();

    /**
     * 根据id查询角色
     * @param id
     * @return
     */
    @Select("select * from sysrole where rid = #{rid} ")
    Sysrole showRoleById(Integer id);

    /**
     * 添加角色
     * @param sysrole
     * @return
     */
    @Insert("insert into sysrole(rname,rdec) values (#{rname},#{rdec}) ")
    Integer addRole(Sysrole sysrole);

    /**
     * 修改角色
     * @param sysrole
     * @return
     */
    @Update("update sysrole set rname=#{rname},rdec=#{rdec} where rid=#{rid} ")
    Integer updateRole(Sysrole sysrole);

    /**
     * 删除角色
     * @param id
     * @return
     */
    @Delete("delete from sysrole where rid=#{rid}")
    Integer deleteRole(Integer id);
}

​ 使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java
注解不仅力不从心,还会让本就复杂的 SQL 语句更加混乱不堪。因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句

9.3 @param()注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
  • 我们在SQL中引用的就是我们这里的@Param()中设定的属性名

9.4 #{} 和 ${} 区别

  • #{}可以防止sql注入 安全
  • ${} 不可以防止sql注入 不安全

9.5 mybatis的详细执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V2L6EjTY-1671027643438)(E:\JAVA核心笔记\img\watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP56CBXw==,size_20,color_FFFFFF,t_70,g_se,x_16)]

十、模糊查询

10.1 接口

/**
 * 根据姓名模糊查询
 * @param name
 * @return
 */
List<Sysuser> findUserByLikeName(String name);

/**
 * 多个参数模糊查询  -->注解传参
 * @param name
 * @param pwd
 * @return
 */
List<Sysuser> findUserByLikeNameAndPwd(@Param("name") String name,@Param("pwd") String pwd);

/**
 * 多个参数模糊查询  ---->map
 * @param map
 * @return
 */
List<Sysuser> findUserByLikeMap(Map<String,Object> map);


/**
 * 多个参数模糊查询 通过QueryCriteria对象传参
 * @param queryCriteria
 * @return
 */
List<Sysuser> findUserByLikeQueryCriteria(QueryCriteria queryCriteria);

10.2 测试类

/**
 * 模糊查询
 */
@Test
public void findUserByLikeName() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
    List<Sysuser> sysuserList = mapper.findUserByLikeName("张二");
    sysuserList.forEach(sysuser -> System.out.println(sysuser));
    sqlSession.close();
}

/**
 * 多个参数模糊查询 使用注解
 */
@Test
public void findUserByLikeNameAndPwd() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
    List<Sysuser> sysuserList = mapper.findUserByLikeNameAndPwd("张", "2");
    sysuserList.forEach(sysuser -> System.out.println(sysuser));
    sqlSession.close();

}


/**
 * 多个参数模糊查询 通过map传参
 */
@Test
public void findUserByLikeMap() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
    Map<String,Object> map =new HashMap<>();
    map.put("name","张");
    map.put("pwd","2");
    List<Sysuser> sysuserList = mapper.findUserByLikeMap(map);
    sysuserList.forEach(sysuser -> System.out.println(sysuser));
    sqlSession.close();

}


/**
 * 多个参数模糊查询 通过QueryCriteria对象传参
 */
@Test
public void findUserByLikeQueryCriteria() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SysuserMapper mapper = sqlSession.getMapper(SysuserMapper.class);
    QueryCriteria queryCriteria =new QueryCriteria("张","2");
    List<Sysuser> sysuserList = mapper.findUserByLikeQueryCriteria(queryCriteria);
    sysuserList.forEach(sysuser -> System.out.println(sysuser));
    sqlSession.close();

}

10.3 mapper.xml文件

<!--<select id="findUserByLikeName" resultType="com.javasm.entity.Sysuser">-->
    <!--select * from sysuser where uname like ‘%’#{uname}‘%’;-->
<!--</select>-->


<select id="findUserByLikeName" resultType="com.javasm.entity.Sysuser">
    select * from sysuser where uname like concat(concat('%',#{uname}),'%') ;
</select>

<insert id="addUser2">
    insert into sysuser (uname,upwd,phone) values (#{uname},#{upwd},#{phone});
</insert>

<select id="findUserByLikeNameAndPwd" resultType="com.javasm.entity.Sysuser">
    select * from sysuser where uname like concat(concat('%',#{name}),'%') and upwd like concat(concat('%',#{pwd}),'%')
</select>

<select id="findUserByLikeMap" resultType="com.javasm.entity.Sysuser">
    select * from sysuser where uname like concat(concat('%',#{name}),'%') and upwd like concat(concat('%',#{pwd}),'%')
</select>


<select id="findUserByLikeQueryCriteria" resultType="com.javasm.entity.Sysuser">
    select * from sysuser where uname like concat(concat('%',#{name}),'%') and upwd like concat(concat('%',#{pwd}),'%')
</select>

10.4 总结

​ 单个参数的模糊查询直接传入参数就行。

有两种常用的方式

1、‘%’#{uname}‘%’ -->常用

2、concat(concat(‘%’,#{uname}),‘%’) -->常用

​ 多个参数的模糊查询有三种方式。

1、注解传参 --> @Param(“name”)

2、用map传参 --> Map<String,Object> map

3、通过对象传参 --> QueryCriteria queryCriteria

十一、动态sql

11.1 搭建环境

CREATE TABLE `blog`(
	`id` VARCHAR(50) NOT NULL COMMENT '博客',
	`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
	`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
	`create_time` DATETIME NOT NULL COMMENT '创建时间',
	`views` INT(30) NOT NULL COMMENT'浏览器'
)

11.2 实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private Integer views;
}

11.3 IF的使用

1、接口

/**
 * 通过IF查询
 * @param map
 * @return
 */
List<Blog> queryBlogIF(Map map);

2、BlogMapper.xml文件

<!--if语句-->
<select id="queryBlogIF" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <if test="title !=null">
            and title = #{title}
        </if>
        <if test="author !=null">
            and author = #{author}
        </if>
    </where>
</select>

3、测试

@Test
public void queryBlogIF(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();
    map.put("title","Spring");
    map.put("author","狂神说");
    List<Blog> blogs = mapper.queryBlogIF(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

4、总结

​ IF语句最好的使用方法是和WHERE一起使用,满足条件即可拼接上,可以动态的拼接上查询条件。

11.4 choose(when otherwise) 的使用

1、接口

/**
 * Choose的查询
 * @param map
 * @return
 */
List<Blog> queryBlogChoose(Map map);

2、BlogMapper.xml文件

<!--从上到下下依次匹配  类似于case加break-->
<select id="queryBlogChoose" parameterType="map" resultType="Blog">
    select * from mybatis.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>

3、测试

@Test
public void queryBlogChoose(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();
    map.put("title","Spring");
    map.put("author","狂神说");
    map.put("views",9989);
    List<Blog> blogs = mapper.queryBlogChoose(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

4、总结

​ 从多个条件中选择一个使用,类似于java中的switch语句。

11.5 set 的使用

1、接口

/**
 * 更新
 * @param map
 * @return
 */
int updateBlog(Map map);

2、BlogMapper.xml文件

<update id="updateBlog" parameterType="map">
    update mybatis.blog
    <set>
        <if test="title !=null">
            title = #{title},
        </if>
        <if test="author !=null">
            author = #{author},
        </if>
        <if test="views !=null">
            views=#{views},
        </if>
    </set>
    where id=#{id};
</update>

3.测试

@Test
public void updateBlog(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();
    map.put("id","a0552f7699214a6685d17ca850dd5563");
    map.put("title","帅哥养成记");
    map.put("author","小胡");
    map.put("views",8888);
    mapper.updateBlog(map);
    sqlSession.commit();
    sqlSession.close();
}

4、总结

​ set是满足条件则修改,可以动态的修改sql语句。

11.6 foreach的使用

1、接口

//查询1,2,3好记录的博客
List<Blog> queryBlogForEach(Map map);

2、BlogMapper.xml文件

<select id="queryBlogForEach" parameterType="map" resultType="Blog">
    select * from mybatis.blog
    <where>
        <foreach collection="ids" open="(" close=")" separator="or" item="id">
            id=#{id}
        </foreach>
    </where>
</select>

3、测试

@Test
public void queryBlogForEach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap();
    List<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(2);
    ids.add(4);
    map.put("ids",ids);
    List<Blog> blogs = mapper.queryBlogForEach(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

4、测试结果
在这里插入图片描述

5、总结

​ collection=“ids” 为要遍历的集合

​ item=“id” 为集合里的数据

​ separator=“or” 为分割符

​ open 和 close 为开头和结尾的拼接

简单的来说就是可以动态的查询语句。

十二、缓存

12.1简介

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

​ 使用缓存的原因是,==减少和数据库的交互次数,减少系统开销,提高系统效率。==经常查询并且不经常修改的数据可以使用缓存。

12.2 mybatis缓存

1、一级缓存也叫本地缓存: SqlSession

  • 与数据库同义词会话期间查询到的数据会放在本地缓存中;
  • 以后如果需要直接到本地缓存中拿,没必要再去查询数据库;

缓存失效的情况:

1、查询不同的东西。

2、执行了增删改操作,可能改变原来的数据,必定会刷新缓存。

3、查询不同的Mapper.xml。

4、手动清理缓存 : sqlSession.clearCache() 。

5、关闭缓存: sqlSession.close() 。

​ 总的来说,一级缓存就是个map。仅在一次会话中有效,即从拿到连接对象到关闭连接的这个区间中有效。

2、二级缓存

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

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

  • 工作机制

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

1、开启全局缓存

<!--显示开启全局缓存-->
<setting name="cacheEnabled" value="true"/>

2、在要使用二级缓存的Mapper中开启

<!--在当前Mapper.xml中使用二级缓存-->
<cache/>

3、参数

<cache
  eviction="FIFO"  //清除策略
  flushInterval="60000"   //刷新时间间隔
  size="512"    //最多可存储结果的对象
  readOnly="true"/>   //是否只读

​ 这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

4、总结

  • 只要开启二级缓存,在同一个Mapper下就会有效
  • 所有的数据都会先放在一级缓存中
  • 只有当会话提交后,或者关闭的时候,才会提交二级缓存中!!

(img-wx4i3JSn-1671027643438)]

5、总结

​ collection=“ids” 为要遍历的集合

​ item=“id” 为集合里的数据

​ separator=“or” 为分割符

​ open 和 close 为开头和结尾的拼接

简单的来说就是可以动态的查询语句。

十二、缓存

12.1简介

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

​ 使用缓存的原因是,==减少和数据库的交互次数,减少系统开销,提高系统效率。==经常查询并且不经常修改的数据可以使用缓存。

12.2 mybatis缓存

1、一级缓存也叫本地缓存: SqlSession

  • 与数据库同义词会话期间查询到的数据会放在本地缓存中;
  • 以后如果需要直接到本地缓存中拿,没必要再去查询数据库;

缓存失效的情况:

1、查询不同的东西。

2、执行了增删改操作,可能改变原来的数据,必定会刷新缓存。

3、查询不同的Mapper.xml。

4、手动清理缓存 : sqlSession.clearCache() 。

5、关闭缓存: sqlSession.close() 。

​ 总的来说,一级缓存就是个map。仅在一次会话中有效,即从拿到连接对象到关闭连接的这个区间中有效。

2、二级缓存

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

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

  • 工作机制

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

1、开启全局缓存

<!--显示开启全局缓存-->
<setting name="cacheEnabled" value="true"/>

2、在要使用二级缓存的Mapper中开启

<!--在当前Mapper.xml中使用二级缓存-->
<cache/>

3、参数

<cache
  eviction="FIFO"  //清除策略
  flushInterval="60000"   //刷新时间间隔
  size="512"    //最多可存储结果的对象
  readOnly="true"/>   //是否只读

​ 这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。

可用的清除策略有:

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

4、总结

  • 只要开启二级缓存,在同一个Mapper下就会有效
  • 所有的数据都会先放在一级缓存中
  • 只有当会话提交后,或者关闭的时候,才会提交二级缓存中!!

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mybatis 的相关文章

  • 如何默认将 Maven 插件附加到阶段?

    我有一个 Maven 插件应该在编译阶段运行 所以在项目中consumes我的插件 我必须做这样的事情
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • Java - 将节点添加到列表的末尾?

    这是我所拥有的 public class Node Object data Node next Node Object data Node next this data data this next next public Object g
  • 使用 Android 发送 HTTP Post 请求

    我一直在尝试从 SO 和其他网站上的大量示例中学习 但我无法弄清楚为什么我编写的示例不起作用 我正在构建一个小型概念验证应用程序 它可以识别语音并将其 文本 作为 POST 请求发送到 node js 服务器 我已确认语音识别有效 并且服务
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • Mockito when().thenReturn 不必要地调用该方法

    我正在研究继承的代码 我编写了一个应该捕获 NullPointerException 的测试 因为它试图从 null 对象调用方法 Test expected NullPointerException class public void c
  • Spring @RequestMapping 带有可选参数

    我的控制器在请求映射中存在可选参数的问题 请查看下面的控制器 GetMapping produces MediaType APPLICATION JSON VALUE public ResponseEntity
  • 无法解析插件 Java Spring

    我正在使用 IntelliJ IDEA 并且我尝试通过 maven 安装依赖项 但它给了我这些错误 Cannot resolve plugin org apache maven plugins maven clean plugin 3 0
  • 十进制到八进制的转换[重复]

    这个问题在这里已经有答案了 可能的重复 十进制转换错误 https stackoverflow com questions 13142977 decimal conversion error 我正在为一个类编写一个程序 并且在计算如何将八进
  • 禁止的软件包名称:java

    我尝试从数据库名称为 jaane 用户名 Hello 和密码 hello 获取数据 错误 java lang SecurityException Prohibited package name java at java lang Class
  • getResourceAsStream() 可以找到 jar 文件之外的文件吗?

    我正在开发一个应用程序 该应用程序使用一个加载配置文件的库 InputStream in getClass getResourceAsStream resource 然后我的应用程序打包在一个 jar文件 如果resource是在里面 ja
  • AWS 无法从 START_OBJECT 中反序列化 java.lang.String 实例

    我创建了一个 Lambda 函数 我想在 API 网关的帮助下通过 URL 访问它 我已经把一切都设置好了 我还创建了一个application jsonAPI Gateway 中的正文映射模板如下所示 input input params
  • 仅将 char[] 的一部分复制到 String 中

    我有一个数组 char ch 我的问题如下 如何将 ch 2 到 ch 7 的值合并到字符串中 我想在不循环 char 数组的情况下实现这一点 有什么建议么 感谢您花时间回答我的问题 Use new String value offset
  • 无法捆绑适用于 Mac 的 Java 应用程序 1.8

    我正在尝试将我的 Java 应用程序导出到 Mac 该应用程序基于编译器合规级别 1 7 我尝试了不同的方法来捆绑应用程序 1 日食 我可以用来在 Eclipse 上导出的最新 JVM 版本是 1 6 2 马文 看来Maven上也存在同样的
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • 声明的包“”与预期的包不匹配

    我可以编译并运行我的代码 但 VSCode 中始终显示错误 早些时候有一个弹出窗口 我不记得是什么了 我点击了 全局应用 从那以后一直是这样 Output is there but so is the error The declared
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • 使用 JMF 创建 RTP 流时出现问题

    我正处于一个项目的早期阶段 需要使用 RTP 广播DataStream创建自MediaLocation 我正在遵循一些示例代码 该代码目前在rptManager initalize localAddress 出现错误 无法打开本地数据端口
  • 如何修复 JNLP 应用程序中的“缺少代码库、权限和应用程序名称清单属性”?

    随着最近的 Java 更新 许多人都遇到了缺少 Java Web Start 应用程序的问题Codebase Permissions and Application name体现属性 尽管有资源可以帮助您完成此任务 但我找不到任何资源综合的
  • 将 List 转换为 JSON

    Hi guys 有人可以帮助我 如何将我的 HQL 查询结果转换为带有对象列表的 JSON 并通过休息服务获取它 这是我的服务方法 它返回查询结果列表 Override public List

随机推荐

  • 重排链表小结

    重排链表小结 又发现一道好玩的题目 顺带来复习一下之前学过的知识吧 Leetcode题目 143 重排链表 给定一个单链表 L 的头节点 head 单链表 L 表示为 L0 L1 Ln 1 Ln 请将其重新排列后变为 L0 Ln L1 Ln
  • Contruct 2制作的HTML5游戏的简单介绍

    游戏背景 在主宰大陆上生活着这样一群人 他们生来掌握着强大的魔法力量 然而自然界从来不允许什么生物可以一家独大 所以与之对应一群强大的魔法生物诞生了 一场人与兽的较量就此展开 伊琳娜是喀布尔山脉的守护者 负责保护阿帕丝女神的雕像 这天阳光正
  • windows配置了path系统环境变量但是不生效

    在配置path环境变量时发现配置的环境变量压根没有效果 但是环境变量内容也没写错 那多半是这个原因 正确的 C Program Files x86 NVIDIA Corporation PhysX Common SystemRoot sys
  • zabbix通过IPMI监控硬件环境(温度和风扇)

    IPMI Intelligent PlatformManagement Interface 即智能平台管理接口是使硬件管理具备 智能化 的新一代通用接口标准 用户可以利用 IPMI 监视服务器的物理特征 如温度 电压 电扇工作状态 电源供应
  • Windows通过计划任务定时执行bat文件

    首先打开Windows系统的 开始 菜单 从中依次点选 程序 附件 系统工具 任务计划程序 命令 点击 创建任务 后如图所示 填写好相应的名称和勾选好必要的条件 选择 触发器 选项 点击 新建 创建任务执行时间 重复任务间隔 这个选择后 后
  • 常见登录鉴权方案

    编者注 今天我们分享的是卢士杰同学整理的网站常用鉴权方案的实现原理与实现以及他们的适用场景 帮助大家在业务中做合适的选择 背景 说起鉴权大家应该都很熟悉 不过作为前端开发来讲 鉴权的流程大头都在后端小哥那边 本文的目的就是为了让大家了解一下
  • 360的服务器在哪个文件夹,如何卸载服务器上顽固的360

    前几天接触到一台戴尔R410的服务器 已经尘封两年 忘记密码无法进入系统 系统是经典的windows server 2003 于是直接用量化好暗组优盘系统的U盘启动 在这里要注意下 服务器的按del是没用的 需要按F12 进入后 选择u盘启
  • 服务器装win10稳定吗,win11发布了,那么电脑安装win11稳定吗?win11稳定性介绍

    近期新的win11系统出去后 绝大多数用户都很希望 但也是有许多平稳用户由于还不知道这一系统如何 因此迟疑需不需要升级 实际上 现在是预览版系统镜像系统 或多或少会出现一点bug 但整体而言或是相对稳定 下面大家一起来看看win11平稳吗的
  • 代码随想录训练营第五十九天

    1 下一个更大元素II 题503 循环数组有两种方法 一是用同一个数组拼接成两个数组 实现假循环 二是遍历两遍 用求余的方法 求余的方法更简便 class Solution public vector
  • java 变量的生命周期

    这个要从作用域开始说起 像局部变量的作用域就是他的生命周期 比如if for switch等等这些 出了这个结构就销毁了 方法里的局部变量 在方法调用完就销毁 如果是类的成员变量 在类的相应的对象销毁的时候销毁 上面说的是普通变量 如果是静
  • 卷积处理过程模拟:用Python实现OpenCV函数filter2D等效的卷积功能

    一 引言 在 OpenCV Python 图像平滑处理 卷积函数filter2D详解及均值滤波案例 介绍了filter2D相关的功能及使用 下面老猿用Python numpy矩阵运算以及OpenCV Python的图像基础操作模拟实现一个卷
  • mybatis之执行sql语句

    写在前面 通过这篇文章的分析 已经生成了可以执行的sql语句了 本文来分析SQL语句具体的执行过程 想要系统学习的 可以参考这篇文章 重要 入口 当我们执行一次数据查询的时候 mybatis会通过org apache ibatis exec
  • 4路组相连cache设计_cache基本原理

    为什么要了解cache 在学习linux kernel的过程 经常会cache的概念 从软件层面的page buffer cache 再到硬件层面中CPU的L1 L2 L3 cache TLB 磁盘内部的硬件cache 以及编程时的cach
  • 集合框架--双向链表的模拟实现

    Java中的鏈表 分為三種 1 單向鏈表 由一個節點元素 可以找到相鄰的下一個節點元素 2 雙向鏈表 由一個節點元素 可以找到其相鄰的前 后節點元素 3 循環鏈表 由一個節點元素 可以找到其相鄰的前 后節點元素 由最后一個節點元素可以找到第
  • notepad使用回车与换行

    转载于 http www pythontab com html 2017 linuxkaiyuan 0115 1116 html 一 回车与换行定义 回车 r 本义是光标重新回到本行开头 r的英文return 换行 n 本义是光标往下一行
  • 浅谈Spring中的@Controller注解

    Spring 的 Controller 是单例还是多例 怎么保证并发的安全 controller默认是单例的 不要使用非静态的成员变量 否则会发生数据逻辑混乱 正因为单例所以不是线程安全的 Controller public class S
  • buuctf-misc-小明的保险箱

    小明的保险箱 题目提示四位纯数字密码 但是附件下载下来是jpg文件 猜测是压缩包文件 winhex查看时没有找到什么信息 但是看到了存在txt文件 binwalk一下 把文件放入共享文件夹 上一个博客有提及 binwalk 存在压缩文件 f
  • Java多线程实现的四种方式

    Java多线程实现的方式有四种 1 继承Thread类 重写run方法 2 实现Runnable接口 重写run方法 实现Runnable接口的实现类的实例对象作为Thread构造函数的target 3 通过Callable和FutureT
  • ES6 扩展运算符-将伪数组转换为真正的数组-Array.from()-find()-findIndex()-includes()

    扩展运算符可以将数组拆分成以逗号分隔的参数序列 console把逗号当成console log的分隔符 输出在后台 a b c 扩展运算符的应用 1 数组合并 1 1 1 2 2 将类数组或可遍历对象转换为真正的数组 转换的目的 可以调用数
  • Mybatis

    一 Mybatis简介 1 1 简介 MyBatis 是一款优秀的持久层框架 它支持自定义 SQL 存储过程以及高级映射 MyBatis免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作 MyBatis可以通过简单的 XML 或