首页 > 其他分享 >Mybatis

Mybatis

时间:2024-09-20 22:34:41浏览次数:10  
标签:缓存 name mybatis sqlSession user Mybatis id

环境:jdk mysql maven diea

需要掌握:java基础 jdbc mysql junit(单元测试)

1,简介

1.1什么是MyBatis

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

如何获得MyBatis:

maven仓库:

<!--        Mybatis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>

MyBatis中文网

1.2持久化

  • 数据库持久化:就是把程序的数据持久状态和瞬间状态转换的过程
  •  内存:断电即失
  • 数据库(jdbc):io文件持久化

 为什么需要持久化:

  1. 有些数据不能删除
  2. 内存太贵了

1.3持久层

Dao层 Service层 Controller层

  • 持久层就是完成持久化代码的
  • 层级线十分明显

 1.4为什么要用mybatis

  • 方便
  • 帮助程序员把数据存入数据库中
  • 传统的jdbc代码太麻烦 简化 框架 自动化
  • 基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响。
  • SQL写在 XML 里,解除 sql 与程序代码的耦合,便于统一管理。
  • 提供 XML 标签,支持编写动态 SQL 语句,并可重用与 JDBC 相比,减少了 50%以上的代码量,消除了 JDBC 大量冗余的代码,
  • 不需要手动开关连接很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数据库 MyBatis 都支持)
  • 使用的人多技术应用广 搭配spring springboot springmvc 这些框架使用

2,第一个MyBatis程序

思路:搭建环境--->导入MyBatis--->编写代码---->测试

2.1环境搭建

搭建数据库

create database 'mybatis';

use 'mybatis';

create table 'user'(
    id int(20) not null comment'主键id' primary key,
   'name' varchar(30) not null default null comment '姓名',
   'pwd' varchar(30) comment'密码'default null
)engine =innodb default  char set =utf8;

insert into 'user'(id, name, pwd) values
 (1,'赵可','123456'),
 (2,'李四','123456'),
 (3,'王五','123456');

创建一个maven项目

然后导入依赖在pom.xml文件中

<?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.zhao</groupId>
    <artifactId>mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>mybatis-01</module>
    </modules>

    <dependencies>

        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <!--junit单元测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
    </dependencies>


    <properties>
<!--        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>-->
        <maven.compiler.source>22</maven.compiler.source>
        <maven.compiler.target>22</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!--把所有的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>false</filtering>
            </resource>
        </resources>
    </build>

</project>

 

 2.2创建一个模块

  • 编写mybatis核心配置文件  mybatis-config.xml
  • <?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>
        <!--default选择配置-->
        <environments default="development">
            <!--配置可以有多个-->
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <!--驱动-->
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <!--url-->
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=ture&amp;useUnicode=tuer&amp;characterEncoding=UTF-8"/>
                    <!--账号-->
                    <property name="username" value="root"/>
                    <!--密码-->
                    <property name="password" value="zhao"/>
                </dataSource>
            </environment>
    
            <environment id="test">
                <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>
        <!--XML映射集-->
        <mappers>
            <mapper resource="org/mybatis/example/BlogMapper.xml"/>
        </mappers>
    </configuration>
  • 编写mybatis工具类 MybatisUtils类
  • package com.zhao.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 {
        //使用mybatis第一步获取SqlSessionFactory对象
        String resource = "mybatis-config.xml";
        InputStream inputStream;
        public static   SqlSessionFactory sqlSessionFactory;
        {
            try {
                inputStream = Resources.getResourceAsStream(resource);
                 sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    
    
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
        // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
        // 你可以通过 SqlSession 实例来直接执行已映射的
        public static SqlSession getSqlSession(){
            return  sqlSessionFactory.openSession();
        };
    
    }

2.3编写代码

  • 实体类
  • package com.zhao.pojo;
    
    public class User  {
    
        private int id;
        private String name;
        private int age;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        public User() {
        }
    
        public User(int id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    }
  • Dao接口
  • package com.zhao.dao;
    
    import com.zhao.pojo.User;
    
    import java.util.List;
    
    public interface UserMapper {
        //基本方法
        List<User> select();
    }
  • 接口的实现对应的是每个Dao/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">
    
    <!--namespace对应Mapper-->
    <mapper namespace="com.zhao.dao.UserMapper">
        <!--id是对应你mapper接口里面的方法 resultType为返回值-->
        <select id="getUserList" resultType="com.zhao.pojo.User">
            select * from mybatis.user
        </select>
    
    </mapper>

2.4测试代码

在核心配置文件mybaotis-comfig.xml中注册mappers

  • junit测试
  • package com.zhao.dao;
    
    import com.zhao.pojo.User;
    import com.zhao.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    
    import java.util.List;
    
    public class UserMapperTest {
        @Test
        public void test(){
            //获取sqlSession
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            //执行sql
            //方法一getMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> userList = mapper.getUserList();
            for (User user:userList){
                System.out.println(user);
            }
    //        //第二种方法
    // List<User> userList = sqlSession.selectList("com.zhao.dao.getUserList");
    //关闭sqlSession
            sqlSession.close();
        }
    }
  • 结果
  • User{id=1, name='赵可名', age=15}
    User{id=2, name='李四', age=45}
    User{id=3, name='王五', age=95}

3CRUD 

  • 在对应的Mapper接口中创建crud方法
  • 指定的xml文件里面编写sql语句

3.1 namespace

  • namespace中的包名要和Dao或Mapper中的对应

3.2select语句

  • id:就是对应Mapper中的方法名
  • resultType:sql语句执行的返回值
  • 代码:
        <!--id是对应你mapper接口里面的方法 resultType为返回值-->
        <select id="getUserList" resultType="com.zhao.pojo.User">
            select * from mybatis.user
        </select>
注意除了select语句其他的语句都需要sqlSession.commit提交事务

3.3update语句

  • id:就是对应Mapper中的方法名
  • resultType:sql语句执行的返回值
  • parameterType:参数类型
  • 代码:
        <update id="updateUserById"  parameterType="com.zhao.pojo.User" >
            update mybatis.user set name =#{name},age=#{age} where id=#{id};
        </update>

     

3.4delect语句

  • id:就是对应Mapper中的方法名
  • resultType:sql语句执行的返回值
  • 代码:
        <delete id="deleteUserById" parameterType="int">
            delete from mybatis.user where id=#{id};
        </delete>

3.5insert语句

  • id:就是对应Mapper中的方法名
  • 代码:
        <insert id="insertUser"  parameterType="com.zhao.pojo.User">
            insert into mybatis.user (id, name, age) values (#{id},#{name},#{age})
        </insert>

3.6 Map

  • 当我们实体类中的字段过多应该考虑map
  •      //map添加数据
        int addUser(Map<String, Object> map);
  •     <insert id="addUser"  parameterType="map">
            insert into mybatis.user (id, name, age) values (#{userId},#{userName},#{userAge})
        </insert>
       @Test
       public void   addUser(){
            Map<String,Object> map=new HashMap<>();
           SqlSession sqlSession = MybatisUtils.getSqlSession();
           UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           map.put("userId",7);
           map.put("userName","曹12华");
           map.put("userAge",15);
           mapper.addUser(map);
           sqlSession.commit();
           sqlSession.close();
       }
  • 例2
  •    List<User> UserByIdName(Map<String,Object> map);
  •     <select id="UserByIdName" parameterType="map" resultType="com.zhao.pojo.User">
            select * from mybatis.user where id=#{userId} and name=#{userName};
        </select>
       @Test
       public void userByIdName(){
            Map<String,Object> map =new HashMap<>();
           SqlSession sqlSession = MybatisUtils.getSqlSession();
           UserMapper mapper = sqlSession.getMapper(UserMapper.class);
           map.put("userId",1);
           map.put("userName","赵似1");
           List<User> users = mapper.UserByIdName(map);
           System.out.println(users);
           sqlSession.close();
       }
  • map传递参数,直接在sql中取出key即可  [parameterType=”map“ ]
  • 对象传参数,直接在sql中去对象的属性即可   [parameterType=”Object“ ]
  • 只有一个基本数据类型,可以之间在sql中取到

3.7 模糊查询

  1. 在java代码中 用通配符%%
     List<User> users = mapper.UserListLike("%李%"); 
  2. 在sqp拼接中用通配符
       select * from mybatis.user where name like "%"#{value}"%"

4配置解析

1核心配置文件

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

 

2环境变量(environments)

  • MyBatis 可以配置成适应多种环境
  • 尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境
        <!--default选择环境-->
        <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/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC&amp;allowPublicKeyRetrieval=true"/>
                    <property name="username" value="root"/>
                    <property name="password" value="zhao"/>
                </dataSource>
            </environment>
            <!--测试环境-->
            <environment id="test">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC&amp;allowPublicKeyRetrieval=true"/>
                    <property name="username" value="root"/>
                    <property name="password" value="zhao"/>
                </dataSource>
            </environment>
        </environments>
  • mybatis默认 事务管理是:jdbc   连接池:pooled

3属性(properties)

我们可以用properties属性来实现引用数据文件

  • 设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值
  • 这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置 db.properties

编写一个配置文件db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&allowPublicKeyRetrieval=true
username=root
password=zhao

 

在核心配置文件中引入:

    <!--引入外部配置文件-->
    <properties resource="db.properties">
        <!--也可自己写属性-->
<!--        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!--        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC&amp;allowPublicKeyRetrieval=true"/>-->
<!--        <property name="username" value="root"/>-->
<!--        <property name="password" value="zhao"/>-->
    </properties>

 

注意db.properties中url地址用&分割xml中用&amp;

  • 可以之间引用外部配置文件
  • 可以在其中添加一些属性配置
  • 如果两个文件有同一个字段的配置,优先使用外部的

4类型别名(typeAliases)

  • 类型别名可为 Java 类型设置一个缩写名字。
  • 它仅用于 XML 配置,意在降低冗余的全限定类名书写
        <!--给实体类起别名-->
        <typeAliases>
           <typeAlias type="com.zhao.pojo.User" alias="User"/>
        </typeAliases>

     

  •  也可以指定一个包,mybatis会在包下面自己搜索所需要java Bean

  • 比如扫描实体类的包 他默认别名为这个类的类名,首字母小写 比如 domain.blog.Author 的别名为 author

         <!--给包起别名-->
        <typeAliases>
           <package name="com.zhao.pojo"/>
        </typeAliases>

     

实体类少用第一种多的话用第二种

第一张可以diy第二种不行如果非要该可以在实体类上面加上注解

@Alias("User")
public class User {

 

5设置(settings)

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

设置名描述有效值默认值
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 true | false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false false
aggressiveLazyLoading 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。 true | false false (在 3.4.1 及之前的版本中默认为 true)
multipleResultSetsEnabled 是否允许单个语句返回多结果集(需要数据库驱动支持)。 true | false true
useColumnLabel 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 true | false true
useGeneratedKeys 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 true | false False
autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 NONE, PARTIAL, FULL PARTIAL
autoMappingUnknownColumnBehavior 指定发现自动映射目标未知列(或未知属性类型)的行为。
  • NONE: 不做任何反应
  • WARNING: 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN
  • FAILING: 映射失败 (抛出 SqlSessionException)
NONE, WARNING, FAILING NONE
defaultExecutorType 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 SIMPLE REUSE BATCH SIMPLE
defaultStatementTimeout 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 任意正整数 未设置 (null)
defaultFetchSize 为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。 任意正整数 未设置 (null)
defaultResultSetType 指定语句默认的滚动策略。(新增于 3.5.2) FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置) 未设置 (null)
safeRowBoundsEnabled 是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 true | false False
safeResultHandlerEnabled 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 true | false True
mapUnderscoreToCamelCase 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 true | false False
localCacheScope MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 SESSION | STATEMENT SESSION
jdbcTypeForNull 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。 OTHER
lazyLoadTriggerMethods 指定对象的哪些方法触发一次延迟加载。 用逗号分隔的方法列表。 equals,clone,hashCode,toString
defaultScriptingLanguage 指定动态 SQL 生成使用的默认脚本语言。 一个类型别名或全限定类名。 org.apache.ibatis.scripting.xmltags.XMLLanguageDriver
defaultEnumTypeHandler 指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5) 一个类型别名或全限定类名。 org.apache.ibatis.type.EnumTypeHandler
callSettersOnNulls 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。 true | false false
returnInstanceForEmptyRow 当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2) true | false false
logPrefix 指定 MyBatis 增加到日志名称的前缀。 任何字符串 未设置
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未设置
proxyFactory 指定 Mybatis 创建可延迟加载对象所用到的代理工具。 CGLIB | JAVASSIST JAVASSIST (MyBatis 3.3 以上)
vfsImpl 指定 VFS 的实现 自定义 VFS 的实现的类全限定名,以逗号分隔。 未设置
useActualParamName 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1) true | false true
configurationFactory 指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3) 一个类型别名或完全限定类名。

一个配置完整的 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>

6其他配置

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

7映射器(mappers)

我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。

在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。

你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!--不要用 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
注意点:
接口和他的Mapper配置文件必须在同名
接口和他的Mapper配置文件必须在同一个包下
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>
注意点:
接口和他的Mapper配置文件必须在同名
接口和他的Mapper配置文件必须在同一个包下
 

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

作用域生命周期是至关重要的,因为错误的使用会导致非常严重的并发问题

 

SqlSessionFactoryBuilder:

  • 这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了

  • 局部变量

SqlSessionFactory:

  • 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
  • 可以想象成数据库的连接池
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域
  • 最简单的就是使用单例模式或者静态单例模式

SqlSession:

  •  连接到一个连接池的请求
  • 每个线程都应该有它自己的 SqlSession 实例。
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完之后赶紧关闭,否则会占用资源

 5解决属性和字段不一致

1出现字段不一致

例如你的实体类为:

 但是数据库类型为:

 就会出现字段不一致

最简单解决办法是有别名

  <select id="selectById" resultType="User" parameterType="int">
   select id,name,age as S from mybatis.user where id =#{id}
  </select>

 

2resultMap

结果集映射:

    <!--结果集映射-->
    <resultMap id="UserMap" type="User">
        <!--column数据库的字段 property实体类的属性-->
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="S"/>
    </resultMap>
    <select id="selectId" resultMap="UserMap">
        select id,name,age from mybatis.user where id =#{id}
    </select>

 

  • resultMap – 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。

6日志

6.1日志工厂

logImpl:指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

mybatis具体实现那个日志在设置设定

  •  标准日志输出
  • 在mybatis-config.xml核心配置文件中配置日志
        <!--日志配置-->
      <settings>
          <setting name="logImpl" value="STDOUT_LOGGING"/>
      </settings>
  • E:\jdk\bin\java.exe -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:E:\idea\IntelliJ IDEA 2024.2.1\lib\idea_rt.jar=52678:E:\idea\IntelliJ IDEA 2024.2.1\bin" -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath "E:\idea\IntelliJ IDEA 2024.2.1\lib\idea_rt.jar;E:\idea\IntelliJ IDEA 2024.2.1\plugins\junit\lib\junit5-rt.jar;E:\idea\IntelliJ IDEA 2024.2.1\plugins\junit\lib\junit-rt.jar;E:\code\mybatis\mybatis-04\target\test-classes;E:\code\mybatis\mybatis-04\target\classes;E:\maven-local\mysql\mysql-connector-java\8.0.30\mysql-connector-java-8.0.30.jar;E:\maven-local\com\google\protobuf\protobuf-java\3.19.4\protobuf-java-3.19.4.jar;E:\maven-local\junit\junit\4.12\junit-4.12.jar;E:\maven-local\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar;E:\maven-local\org\mybatis\mybatis\3.5.2\mybatis-3.5.2.jar;E:\maven-local\log4j\log4j\1.2.17\log4j-1.2.17.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 com.zhao.dao.UserMapperTest,getUserList
    [org.apache.ibatis.logging.LogFactory]-Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
    Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    Opening JDBC Connection
    Created connection 573958827.
    Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2235eaab]
    ==>  Preparing: select id,name,age from mybatis.user where id =? 
    ==> Parameters: 3(Integer)
    <==    Columns: id, name, age
    <==        Row: 3, 王五, 95
    <==      Total: 1
    User{id=3, name='王五', S=95}
    Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2235eaab]
    Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2235eaab]
    Returned connection 573958827 to pool.

     直接打印出结果

6.LOG4J 

 

  • 导入log4j maven jar包
    <dependencies>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
        </dependencies>
  • 在resources包下创建配置文件 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/zhao.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
  • 在mybatis-config.xml核心配置文件中配置日志
    <!--配置LOG4J-->
        <settings>
            <setting name="logImpl" value="log4j"/>
        </settings>
  • 简单使用:
  1. 要在Log4j类中导入包 import org.apache.log4j.Logger;
  2. 日志对象参数为class
      static Logger logger=Logger.getLogger( UserMapperTest.class);
  3. 日志级别
        public void log4jTest(){
            logger.info("info:进入log4jTest");
            logger.debug("debug:进入log4jTest");
            logger.error("error:进入log4jTest");
        }

7分页查询limit

减少数据处理量 减少资源使用

使用limit分页

//sql语法
select 字段列表 from 表名 limit 起始索引, 查询记录数 ;

 

7.1使用mybatis分页:核心也是sql

  • 接口
       List<User> selectLimit(Map<String,Integer> map);
  • Mapper.xml
    <select id="selectLimit" parameterType="map" resultType="User">
         select * from mybatis.user limit #{startIndex},#{page}
    </select>
  • 测试
        @Test
        public void selectLimitTest(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            Map<String,Integer> map =new HashMap<>();
            map.put("startIndex",2);
            map.put("page",2);
            List<User> users = mapper.selectLimit(map);
            System.out.println(users);
            sqlSession.close();
        }

7.2RowBounds分页

  • 接口
       //分页RowBounds
       List<User> selectByRowBounds();
  • xml
        <select id="selectByRowBounds"  resultType="User">
            select * from mybatis.user
        </select>
  • 测试
        @Test
        public void selectByRowBounds(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            //RowBounds实现
            RowBounds rowBounds = new RowBounds(2,2);
            //通过java底层代码实现分页
            List<User> listUser = sqlSession.selectList("com.zhao.dao.UserMapper.selectByRowBounds",null,rowBounds);
            for (User user:listUser){
                System.out.println(user);
            }
            sqlSession.close();
        }

     全部查询出来在java底层代码进行分页

7.3mybatis分页插件 了解即可

 官网:MyBatis 分页插件 PageHelper

8使用注解开发

8.1面向接口编程:

面向接口编程是开发程序的功能先定义接口,接口中定义约定好的功能方法声明,通过实现该接口进行功能的实现,完成软件或项目的要求.软件或项目随着时间的不断变化,软件的功能要进行升级或完善,开发人员只需要创建不同的新类重新实现该接口中所有方法,就可以达到系统升级和扩展的目的.

面向接口编程的好处

  • 降低了程序的耦合性.其能够最大限度的解耦,所谓解耦既是解耦合的意思,它和耦合相对。耦合就是联系,耦合越强,联系越紧密。
  • 在程序中紧密的联系并不是一件好的事情,因为两种事物之间联系越紧密,你更换其中之一的难度就越大,扩展功能和debug的难度也就越大。
  • 易扩展. 我们知道程序设计的原则是对修改关闭,对新增开放.面向接口编程扩展功能只需要创建新实现类重写接口方法进行升级扩展就可以,达到了在不修改源码的基础上扩展的目的.
  • 易维护

8.2使用注解开发

  • 接口Mapper 
      @Select("select * from user")
      List<User> selectUser();
  • 绑定接口 (需要在核心文件中绑定接口)
        <!--绑定接口-->
        <mappers>
            <mapper class="com.zhao.dao.UserMapper"/>
        </mappers>
  • 实现
        @Test
        public void selectUserTest(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> users = mapper.selectUser();
            for (User user:users){
                System.out.println(user);
            }
            sqlSession.close();
        }
  • 原理:利用Java中反射机制底层是动态代理实现的
  • 动态代理:

mybatis详细执行流程:

 8.3实现crud

  • select
    //多个参数要在参数前面@Param()注解
      @Select("select * from user where id=#{id} and name=#{name}")
      User selectUserByIdName(@Param("id") int id, @Param("name")String name);
  • insert
      @Insert("insert into user(id,name,age) values (#{id},#{name},#{age})")
      int insert(User user);
  • update
      @Update("update user set name=#{name},age=#{age} where id=#{id}")
      int updateById(User user);
  • delete
      @Delete("delete from user where id=#{id}")
      int deleteById(int id) 
  • 注意 绑定接口 (需要在核心文件中绑定接口)
  • 关于@Param()注解
  1. 基本类型和String类型需要加
  2. 引用类型不需要加
  3. 只有一个类型不需要加 但是建议加上
  4. 在sql中引用的就是注解中的属性名

#{}和${}的区别 #{}可以防止sql注入 而${}是直接拼接的

注意:MyBatis排序时使用order by动态参数时需要注意使用${}而不是#{}

9lombok

Lombok是一个Java库,能自动插入编辑器并构建工具,简化Java开发。通过添加注解的方式,不需要为类编写getter或eques方法,同时可以自动化日志变量

简而言之:Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。

1.Lombok使用

使用Lombok需要的开发环境Java+Maven+IntelliJ IDEA或者Eclipse(安装Lombok Plugin)

1.1添加maven依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.4</version>
    <scope>provided</scope>
</dependency>

 

1.2安装插件

打开idea的设置,点击Plugins,点击Browse repositories,在弹出的窗口中搜索lombok,然后安装即可。

1.3使用Lombok

2常用注解

下面介绍一下常用的几个注解:

@Setter 注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
@Getter 使用方法同上,区别在于生成的是getter方法。
@ToString 注解在类,添加toString方法。
@EqualsAndHashCode 注解在类,生成hashCode和equals方法。
@NoArgsConstructor 注解在类,生成无参的构造方法。
@RequiredArgsConstructor 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
@AllArgsConstructor 注解在类,生成包含类中所有字段的构造方法。
@Data 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
@Slf4j 注解在类,生成log变量,严格意义来说是常量。private static final Logger log = LoggerFactory.getLogger(UserController.class);

3.Lombok的优缺点

  • 优点:

能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法,提高了一定的开发效率
让代码变得简洁,不用过多的去关注相应的方法
属性做修改时,也简化了维护为这些属性所生成的getter/setter方法等

  • 缺点:

不支持多种参数构造器的重载

4.Lombok工作原理 了解即可

在Lombok使用的过程中,只需要添加相应的注解,无需再为此写任何代码。自动生成的代码到底是如何产生的呢?

核心之处就是对于注解的解析上。JDK5引入了注解的同时,也提供了两种解析方式。

  • 运行时解析

运行时能够解析的注解,必须将@Retention设置为RUNTIME,这样就可以通过反射拿到该注解

java.lang.reflect反射包中提供了一个接口AnnotatedElement,该接口定义了获取注解信息的几个方法,

Class、Constructor、Field、Method、Package等都实现了该接口,对反射熟悉的朋友应该都会很熟悉这种解析方式。

  • 编译时解析

编译时解析有两种机制,分别简单描述下:

1)Annotation Processing Tool

apt自JDK5产生,JDK7已标记为过期,不推荐使用,JDK8中已彻底删除,自JDK6开始,可以使用Pluggable Annotation Processing API来替换它,

apt被替换主要有2点原因:

api都在com.sun.mirror非标准包下
没有集成到javac中,需要额外运行

2)Pluggable Annotation Processing API

JSR 269自JDK6加入,作为apt的替代方案,它解决了apt的两个问题,javac在执行的时候会调用实现了该API的程序,这样我们就可以对编译器做一些增强,javac执行的过程如下:

Lombok本质上就是一个实现了“JSR 269 API”的程序。在使用javac的过程中,它产生作用的具体流程如下:

javac对源代码进行分析,生成了一棵抽象语法树(AST)
运行过程中调用实现了“JSR 269 API”的Lombok程序
此时Lombok就对第一步骤得到的AST进行处理,找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
javac使用修改后的抽象语法树(AST)生成字节码文件,即给class增加新的节点(代码块)
通过读Lombok源码,发现对应注解的实现都在HandleXXX中,比如@Getter注解的实现在HandleGetter.handle()。还有一些其它类库使用这种方式实现,比如Google Auto、Dagger等等。

 

10复杂查询环境搭建

一对多或者多对一

数据库创建两张表

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. 导入lombok
  2. 创建实体类 Teacher 和 Student 
  3. 创建对应的Mapper接口
  4. 建立对应Mapper接口的xml文件
  5. 在核心配置文件中绑定我们对于的Mapper接口或者文件
  6. 测试查询是否成功

多对一  题:查询出对应学生和老师的信息:

   //第一种方法的实体
private int id; private String name; private String Teacher;
    //后面两种方法的实体
private int id; private String name; private Teacher teacher;

 

 

方法一:用as去别名对应你创建的实体类 

    <!--方法一用as去别名对应你创建的实体类-->
   <select id="selectById" resultType="com.zhao.pojo.Student" parameterType="int">
       select s.id, s.name ,t.name as Teacher from student as s , teacher as t where s.tid=t.id and s.id=#{id};
   </select>

 

方法二:按照查询嵌套处理

    <!--方法二
     1.查询出所有的学生信息
     2.根据查询出来的学生的tid。寻找对应的老师 子查询
    -->
    <select id="getStudent" resultMap="StudentTeacher">
        select *from student;
    </select>

    <!--结果集映射-->
    <resultMap id="StudentTeacher" type="Student">
        <!--column数据库的字段 property实体类的属性-->
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--集合的形式储存信息-->
        <association property="teacher" column="tid" javaType="Teacher" select="getStudent"/>
    </resultMap>

    <select id="getTeacher" resultType="Teacher">
        select  * from teacher where id =#{id}
    </select>

 

方法三:按照结果嵌套处理

    <!--方法三用按照结果嵌套处理-->
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id as sid,
               s.name as sname,
               t.name as Teacher
        from student as s , teacher as t where s.tid=t.id;
    </select>

    <resultMap id="StudentTeacher2" type="com.zhao.pojo.Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="com.zhao.pojo.Teacher">
            <result property="name" column="Teacher"/>
        </association>
    </resultMap>

一对多 题:查询出对应学生和老师的信息:

  • 实体类
    public class Student{
     private int id;
     private String name;
     private int tid;
    }
    
    public class Teacher{
     private int id;
     private String name;
     //一个老师对应多个学生
     private List<Student> student;
    }

方法一:按照查询嵌套处理

    <!--按查询嵌套查询-->
<select id="getTeacher2" resultMap="TeacherStudent2">
    select *from  teacher where id =#{id}
</select>

    <resultMap id="TeacherStudent2" type="com.zhao.pojo.Teacher">
        <collection property="students" javaType="ArrayList" ofType="com.zhao.pojo.Student" select="getTeacherById" column="id"/>
    </resultMap>
    <select id="getTeacherById" resultType="com.zhao.pojo.Student">
    select *from student WHERE tid=#{tid}
    </select>

方法二:按照结果嵌套

    <!--按结果嵌套查询-->
 <select id="getTeacher" resultMap="TeacherStudent">
     select s.di as sid,
            s.nanme as sname,
            t,name as tanme
            t,id as tid from student as s  teacher as t
           where s,tid =t,id and t,id =#{tid}
 </select>

    <resultMap id="TeacherStudent" type="com.zhao.pojo.Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
<!--复杂属性我们需要单独处理 对象:association 集合: collection
    javaType="" 指定属性的类型  集合中的泛型信息,我们使用ofType获取-->
        <collection property="student" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

 

小结:

  1. 关联:asscoiation (多对一)
  2. 集合:collection (一对多)
  3. javaType:用来指定实体类中属性的类型
  4. ofType:用来指定映射到list或者集合中的pojo类型,泛型中的约束类型

 

11动态sql

根据不同条件生成出的不同sql

  • if:判断标签
    <select id="findActiveBlogWithTitleLike"  resultType="Blog">
      SELECT * FROM BLOG  WHERE state = ‘ACTIVE’ 
      <if test="title != null">
        AND title like #{title}
      </if>
    </select>
  • choose (when, otherwise) :有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
        <select id="findActiveBlogLike" resultType="Blog">
            SELECT * FROM BLOG WHERE state = ‘ACTIVE’
            <choose>
                <when test="title != null">
                    AND title like #{title}
                </when>
                <when test="author != null and author.name != null">
                    AND author_name like #{author.name}
                </when>
                <otherwise>
                    AND featured = 1
                </otherwise>
            </choose>
        </select>
  • trim (where, set)
    where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句
      <select id="findActiveBlogLike" resultType="Blog">
            SELECT * FROM BLOG
            <where>
                <if test="state != null">
                    state = #{state}
                </if>
                <if test="title != null">
                    AND title like #{title}
                </if>
                <if test="author != null and author.name != null">
                    AND author_name like #{author.name}
                </if>
            </where>
        </select>
  • foreach:动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
        <select id="selectPostIn" resultType="domain.blog.Post">
            SELECT * FROM POST as P
            WHERE ID in
            <foreach item="item" index="index" collection="list"
                     open="(" separator="," close=")">
                #{item}
            </foreach>
        </select> 
  • sql片段 在你写sql中可以把共同的sql提取出来写成一个片段在你写的sql中直接引用
    使用sql标签提取公共部分
    <sql id="ifTest"> <if test="name != null"> name =#{name} </if> <if test="age != null"> age =#{age} </if> <if test="pwa != null"> pwa =#{pwa} </if> </sql>
    使用inciude引用公共sql
    <select id="select" parameterType="map" resultType="User"> select * from user <where> <include refid="ifTest"/> </where> </select>

     

12缓存

MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。 为了使它更加强大而且易于配置,我们对 MyBatis 3 中的缓存实现进行了许多改进。

  • mybatis默认为一级缓存(本地的会话缓存它仅仅对一个会话中的数据进行缓存(sqlsession级别缓存)。
        @Test
        public void select(){
            //sqlSession 创建
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            List<Teacher> select = mapper.select();
            for (Teacher teacher :select){
                System.out.println(teacher);
            }
          //到sqlSession 关闭 这个时间段本地缓存有效
            sqlSession.close();
    
        }

     

  •  需要手动开启 要启用全局的二级缓存(namespac级别缓存),只需要在你的 SQL 映射文件中添加一行:
    <cache/>//可以自定义二级缓存
    • 映射语句文件中的所有 select 语句的结果将会被缓存。
    • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。   
    • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
    • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。

 

二级缓存可用的清除策略有:

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

默认的清除策略是 LRU。

例子:

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

flushInterval:(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。

                             默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。

                              默认值是 1024。

readOnly(只读)属性可以被设置为 true 或 false。

                              只读的缓存会给所有调用者返回缓存对象的相同实例。

                              因此这些对象不能被修改。这就提供了可观的性能提升。

                              而可读写的缓存会(通过序列化)返回缓存对象的拷贝。

                              速度上会慢一些,但是更安全,因此默认值是 false。

提示 二级缓存是事务性的。这意味着,当 SqlSession 完成并提交时,或是完成并回滚,但没有执行 flushCache=true 的 insert/delete/update 语句时,缓存会获得更新。

需要提交事务

一级缓存

在一个sqlSession进行两次查询 

    @Test
    public void getUserList(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.selectId(3);
        System.out.println(user);
        User user1 = mapper.selectId(3);
        System.out.println(user1);
        sqlSession.close();
    }

 

 但是数据库只查询一次数据库 :第二次查询的是缓存

缓存失效:

  1. 增删改会操作原有的数据 所以缓存会刷新
  2. 查询不同的Mapper
  3. 查询不同的东西
  4. 手动清理缓存
            //手动清理缓存
            sqlSession.clearCache();

     

小结:一级缓存默认是开启的,只在一次sqlSeesion中有效,也就是拿到连接到关闭链接这个阶段 

       一个一级缓存就是一个map

二级缓存:

  • 二级缓存也叫全局缓存。
  • 基于nameapce级别的缓存,一个名称空间,对应一个缓存
  • 工作机制 
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    • 如果当前缓存关闭了,对应一级缓存没了。但是我们想要的是,会话关闭了,一级缓存中的数据被保存在二级缓存中
    • 新的会话查询信息,就可以从二级缓存中获取
    • 不同的mapper查询数据会放在自己对应的缓存(map)中

步骤:

  1.    开启全局缓存
        <!--配置-->
        <settings>
            <!--日志配置-->
            <setting name="logImpl" value="STDOUT_LOGGING"/>
            <!--显示开启全局缓存二级缓存-->
            <setting name="cacheEnabled" value="true"/>
        </settings>
  2. 在Mapper.xml中设置开启二级缓存
        <!--在当前Mapper.xml中开启二级缓存-->
        <cache/> 
  3. 也可以自己设置属性
    <cache
      eviction="FIFO"
      flushInterval="60000"
      size="512"
      readOnly="true"/>
  4. 注意需要把对应Mapper的实体类序列化

小结:

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

缓存原理:

 缓存顺序:

  1. 先看二级缓存中有没有
  2. 再看一级缓存
  3. 查询数据库

自定义缓存-ehache:知道就好

注意一点:在mybatis如果你要使用自定义缓存就要指定使用chcache缓存

 

标签:缓存,name,mybatis,sqlSession,user,Mybatis,id
From: https://www.cnblogs.com/zhao-ke-ming/p/18357913

相关文章

  • SpringBoot整合Mybatis-flex
    第1步:创建数据库表CREATETABLEIFNOTEXISTS`tb_account`(`id`INTEGERPRIMARYKEYauto_increment,`user_name`VARCHAR(100),`age`INTEGER,`birthday`DATETIME);INSERTINTOtb_account(id,user_name,age,birthday)VALUE......
  • mybatis一级缓存机制
    在mybatis中一级缓存是默认打开的,二级缓存没有默认打开,需要主动配置。今天我们主要来说一级缓存的执行机制。 首先,我们应该了解为什么有缓存如果没有缓存,那么java程序每次去数据库取数据的时候,都会直接去数据库取,如果取的是相同的数据,会大大影响效率,因为与数据库的链接本质......
  • Mybatis-plus复习篇--加油
    文章目录1.MyBatis-plus基础1.1.mybatis-plus简介1.2.基本使用1.3.注解映射主键生成策略1.4.命名转换问题1.5.关闭命名转换功能2.BaseMapper核心接口1.MyBatis-plus基础1.1.mybatis-plus简介MyBatis-Plus(简称MP)是一个 MyBatis的增强工具,在MyBatis的基础上只做增强不......
  • Mybatis续
    步骤爆红点了右上角还是爆红不要着急,右下角正在下载new如果new的是package,用com.zhang,能事项分级如果new的是文件夹,用com/zhang,就能实现分级。如果用com.zhang,则创建的文件夹名是com.zhang,而不是分级的形式步骤修改为自己的记不住就把之前jdbc的复制过来问题......
  • MyBatis中一对多关系的两种处理方法
    目录1.多表联查(通过collection标签的ofType属性)1)mapper2)mapper.xml3)测试代码4)测试结果2.分布查询(通过collection标签的select属性)1)mapper2)mapper.xml3)测试代码4)测试结果附录1.Classes实体类2.student类3.OneToManyMapper4.OneToManyMapper.xml5.OneToManyM......
  • Spring Boot 整合 MyBatis 的详细步骤(两种方式)
    1.SpringBoot配置MyBatis的详细步骤1、首先,我们创建相关测试的数据库,数据表。如下:CREATEDATABASE`springboot_mybatis`USE`springboot_mybatis`CREATETABLE`monster`(`id`intnotnullauto_increment,`age`intnotnull,`birthday`DATEDEFAULTN......
  • mybatis的代理技术
    在MyBatis中,代理对象是通过动态代理技术生成的对象,用于拦截对接口方法的调用并将这些调用转发给相应的SQL映射文件中的SQL语句执行。具体来说,代理对象是一个实现了某个接口的类实例,但这个实例的实际行为是在运行时动态生成的,而不是在编译时固定的。###动态代理在Java中......
  • mybatis-plus 条件参数说明
     //条件构造器1@TestpublicvoidtestFindWrapper1(){//查询年龄小于25或年龄大于30的人QueryWrapper<Student>queryWrapper=newQueryWrapper<>();queryWrapper.lt("age",25).or().gt("age",30);List<Student>students=studentMapp......
  • mybatis 通过工厂模式将mapper接口的代理对象注入spring容器中
    MapperFactoryBean是MyBatis框架中用于创建Mapper对象的一个工厂类。getObject方法是该工厂类中的一个关键方法,用于返回实际的Mapper对象。具体来说,MapperFactoryBean通过getObject方法来创建和初始化Mapper接口的实现,从而可以在Spring容器中注入和使用这些Mappe......
  • MyBatis基础
    MyBatis基础1.什么是mybatisMyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和POJO(PlainOrdinaryJava......