Day67.缓存机制(Cache)、日志、缓存源码(装饰模式)、MBatis底层源码分析、逆向工程(QBC)、总结

目录

一、缓存 Cache

1.MyBatis缓存分类

2.一级缓存

3.二级缓存

二级缓存分开关的设置

4.第三方自定义缓存:整合Ehcache 

Ehcache的配置项(了解)

二、日志框架

三、缓存源码 (装饰模式)

1.Cache相关的API

2.一级Cache的源码

3.二级Cache的源码

四、逆向工程(了解)

QBC(了解)

五、其他

1.Mapper映射、实体类别名

2.插件机制(了解)

3.类型处理器typeHandler(了解)

六、MBatis底层对JDBC的封装

1.Mbatis底层四大对象:

2.Mybatis底层四大步骤:

七、Mybatis大总结


一、缓存 Cache

缓存:存在内存中的临时数据

使用缓存可以减少对硬盘(数据库)的访问次数(IO操作)提高查询效率,减少系统开销,解决了高并发系统的性能问题。

1.MyBatis缓存分类

一级缓存:自动开启,默认开启,针对同一个SqlSessio (不同的SqlSession有不同的一级缓存)

二级缓存:手动开启,默认关闭,针对同一个SqlSessioinFactory (由这一个SqlSessionFactory) 创建的所有SqlSession可以共享二级缓存中的数据)

缓存命中率 = 命中缓存的次数/查询的总次数 

查询的顺序是:

  • 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
  • 如果二级缓存没有命中,再查询一级缓存
  • 如果一级缓存也没有命中,则查询数据库
  • 查询数据库的结果,会立刻放入一级缓存 (不会立刻放入二级缓存)
  • SqlSession关闭之前一级缓存中的数据会写入二级缓存

2.一级缓存

一级缓存失效的情况

  • 不是同一个SqlSession
  • 同一个SqlSession但是查询条件发生了变化
  • 同一个SqlSession两次查询期间执行了任何一次增删改操作 (清空、刷新一级缓存)
  • 同一个SqlSession两次查询期间手动清空了缓存
  • 同一个SqlSession两次查询期间提交了事务

3.二级缓存

结论:SqlSession关闭的时候一级缓存中的内容会被存入二级缓存

1.全局开关:默认开启

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

2.局部开关:二级缓存以namespace为单位。

<mapper namespace="com.atguigu.mapper.EmployeeMapper">
    <!--二级缓存的分开关,针对该命名空间下的查询操作-->
    <cache/>
    <select id="findById" resultType="employee">
        SELECT emp_id empId ,emp_name empName,emp_salary empSalary
        FROM t_emp
        WHERE emp_id = #{empId}
    </select>

</mapper>

3.实体类要序列化

什么时候需要序列化:在在内存中存储不需要序列化,如果内存的数据要存入硬盘,或者在网络上传输,就要序列化(其实是变成字节数组)

一级缓存肯定在内存中,二级缓存可能在内存中,但是二级缓存数据多,也可以存储到外存中,所以存在二级缓存中的数据必须序列化

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee implements Serializable {
    private Integer empId;
    private String empName;
    private Double empSalary;
}

4.测试

运行之前访问一级缓存的代码,发现已经查询二级缓存,但是在二级缓存中一次也没有发现数据

一级缓存的数据,何时放入二级缓存:

SqlSession关闭的时候,一级缓存中的内容会被存入二级缓存

    //二级缓存
    @Test
    public void testCache2(){
        //创建SqlSession1
        SqlSession sqlSession1 = factory.openSession();
        EmployeeMapper mapper1 = sqlSession1.getMapper(EmployeeMapper.class);
        Employee emp1 = mapper1.findById(21);
        System.out.println(emp1);
        sqlSession1.close();    //关闭了sqlSession,存入二级缓存

        //创建SqlSession2
        SqlSession sqlSession2 = factory.openSession();
        EmployeeMapper mapper2 = sqlSession2.getMapper(EmployeeMapper.class);
        Employee emp2 = mapper2.findById(2);
        System.out.println(emp2);
    }

二级缓存分开关的设置

<cache  type=""  size="" blocking=""  eviction=""  flushInterval="" readOnly=""/>

  • Type:指定具体的二级缓存类型。如果不指定,就使用MyBatis自带的二级缓存。
  • Size:代表缓存最多可以存储多少个对象,太大容易导致内存溢出
  • flushInterval:刷新(清空缓存)间隔。默认情况是不设置,也就是没有刷新间隔
  • readOnly:只读。True:性能高  false,性能低,安全性高
  • Eviction:缓存清除策略。比如二级缓存中最多放100个缓存内容,第101来了,怎么办?
    1. LRU – 最近最少使用(默认):移除最长时间不被使用的对象  (Least Recently Used )
    2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。(First in First out)
  • Blocking 阻塞:访问某个缓存数据,在访问过程中对key(sql语句)加锁,其他的请求同一个SQL语句,要等待。保证了只有一个请求来访问缓存中的一份数据。

4.第三方自定义缓存:整合Ehcache 

Ehcache是一种开源的、缓存的技术。整合Ehcache,就是使用Ehcache做MyBatis的二级缓存

①添加依赖

<!-- Mybatis EHCache整合包 -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>

②整合EHCache 

在resources下创建配置文件:ehcache.xml。文件内容:

<?xml version="1.0" encoding="utf-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <!-- 磁盘保存路径 -->
    <diskStore path="D:\atguigu\ehcache"/>
    
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="true"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>

③加入log4j适配器依赖

存在SLF4J时,是无法直接访问log4j的,需要加入一个适配器类:slf4j-log4j12。

因为log4j不是slf4j的直接实现

<!-- SLF4j和log4j的适配器类 -->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.30</version>
    <scope>test</scope>
</dependency>

④mapper.xml 指明二级缓存使用Ehcache

<mapper namespace="com.atguigu.mapper.EmployeeMapper">
    <!--二级缓存的分开关,针对该命名空间下的查询操作-->
    <!--type:使用了ehcache二级缓存-->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

⑤测试查看结果
使用了Ehcache的效果:

Ehcache的配置项(了解)

属性名是否必须作用
maxElementsInMemory在内存中缓存的element的最大数目
maxElementsOnDisk在磁盘上缓存的element的最大数目,若是0表示无穷大
eternal设定缓存的elements是否永远不过期
如果为true,则缓存的数据始终有效,
如果为false那么还要根据timeToIdleSeconds、timeToLiveSeconds判断
overflowToDisk设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
timeToIdleSeconds当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,
这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMBDiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
diskPersistent在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
diskExpiryThreadIntervalSeconds磁盘缓存的清理线程运行间隔默认是120秒。每个120s,
相应的线程会进行一次EhCache中数据的清理工作
memoryStoreEvictionPolicy当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。
默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)

二、日志框架

① 日志框架选择

情况1:如果开发项目中已经确定采用哪种具体日志系统直接使用即可(不引入SLF4J等抽象的日志门面)。

  • log4j:日志框架的鼻祖,作者Ceki Gülcü将其捐献给Apache开源,吸引了无数的人无偿帮助测试它,扩展它,改进它,很快就成了最流行的日志工具。
  • JDK logging:从JDK1.4开始,JDK中提供了java.util.logging包,也来记录日志。这可是官网日志包,而不是第三方日志包,但是已经无法撼动log4j了。
  • log4j2:2015年9月,Apache软件基金业宣布,Log4j不在维护,建议所有相关项目升级到Log4j2。log4j2性能优异。但内部实现和log4j完全不同

情况2:如果开发项目中无法确定采用哪种具体的日志系统使用SLF4J等日志门面也要引入一种具体的日志框架引入一个抽象的日志框架:SLF4j

  • SLF4j:由log4j的作者设计完成的,简单日志门面(Simple Logging Facade for Java),不是具体的日志解决方案,而是通过Facade Pattern提供一些Java logging API,它只服务于各种各样的日志系统。按照官方的说法,SLF4J是一个用于日志系统的简单Facade,允许最终用户在部署其应用时使用其所希望的日志系统。作者创建SLF4J的目的是为了替代Jakarta Commons-Logging。
  • Jakarta Commons-Logging,现在叫Apache Commons-Logging,也是一个日志门面,希望解决的问题和Slf4j类似。common-logging通过动态查找的机制,在程序运行时自动找出真正使用的日志库; slf4j在编译时静态绑定真正的Log库。
  • logback同样是由log4j的作者设计完成的,拥有更好的特性,用来取代log4j的一个日志框架,并给出了slf4j的原生实现(即直接实现了slf4j的接口,而log4j因为出现早于slf4j,并没有直接实现,就需要一个适配器slf4j-log4j12.jar)。

② 日志框架类型

门面:

名称说明
JCL(Jakarta Commons Logging)陈旧
SLF4J(Simple Logging Facade for Java)★适合
jboss-logging特殊专业领域使用

实现:★表示同一个作者

名称说明
log4j★最初版
JUL(java.util.logging)JDK自带
log4j2Apache收购log4j后全面重构,内部实现和log4j完全不同
logback优雅、强大

③ logback的使用

[1] 依赖信息

<!-- slf4j日志门面的一个具体实现:logback -->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
</dependency>

[2] 配置信息

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true">
    <!-- 指定日志输出的位置 -->
    <appender name="STDOUT"
        class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <!-- 日志输出的格式 -->
            <!-- 按照顺序分别是:时间、日志级别、线程名称、打印日志的类、日志主体内容、换行 -->
            <pattern>[%d{HH:mm:ss.SSS}] [%-5level] [%thread] [%logger] [%msg]%n</pattern>
        </encoder>
    </appender>
    
    <!-- 设置全局日志级别。日志级别按顺序分别是:DEBUG、INFO、WARN、ERROR -->
    <!-- 指定任何一个日志级别都只打印当前级别和后面级别的日志。 -->
    <root level="DEBUG">
        <!-- 指定打印日志的appender,这里通过“STDOUT”引用了前面配置的appender -->
        <appender-ref ref="STDOUT" />
    </root>
    
    <!-- 根据特殊需求指定局部日志级别 -->
    <logger name="com.atguigu.crowd.mapper" level="DEBUG"/>
    
</configuration>

如果有过个日志框架,哪个依赖在前,就启用哪个。

 logback:时间在前

三、缓存源码 (装饰模式)

设计模式:装饰模式动态组装

蛋糕接口:(Cache接口)

蛋糕实现类:奶油蛋糕   冰激凌蛋糕(PerpetualCache  EhcacheCache)

蛋糕的装饰:卡片、干果、蜡烛(FifoCache、LruCache是添加了装饰的蛋糕)

如果采用继承,就会数不清的实现类。采用装饰模式,可以减少子类的数量,是继承的一种替代方案。现场组装

蛋糕接口:(InputStream抽象类)

蛋糕实现类:奶油蛋糕   冰激凌蛋糕(FileInputStream ByteArrayInputStream)

蛋糕的装饰:卡片、干果、蜡烛(BufferedInputStream DataInputStream)

1.Cache相关的API

 

 Cache内部有一个Map,存储缓存的信息

 

 所有的装饰类中必须有一个Cache的引用,说明对谁进行装饰。(类似包装流内的节点流)

 PerpetualCache 是Mybatis的默认缓存,也是Cache接口的默认实现。Mybatis一级缓存和自带的二级缓存都是通过 PerpetualCache 来操作缓存数据的。

PerpetualCache 如何区分不同级别的缓存:根据调用者不同

  • 一级缓存:由BaseExecutor调用PerpetualCache
  • 二级缓存:由CachingExecutor调用PerpetualCache,而CachingExecutor可以看做是对BaseExecutor的装饰

2.一级Cache的源码

3.二级Cache的源码

底层使用Ehcache

底层使用自带的二级缓存 
 

 底层不使用二级缓存:会调用一级缓存

四、逆向工程(了解)

正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。

逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成Java实体、\Mapper接口、Mapper配置文件

添加插件

<!-- 控制Maven在构建过程中相关配置 -->
<build>

    <!-- 构建过程中用到的插件 -->
    <plugins>

        <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.0</version>

            <!-- 插件的依赖 -->
            <dependencies>

                <!-- 逆向工程的核心依赖 -->
                <dependency>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-core</artifactId>
                    <version>1.3.2</version>
                </dependency>

                <!-- 数据库连接池 -->
                <dependency>
                    <groupId>com.mchange</groupId>
                    <artifactId>c3p0</artifactId>
                    <version>0.9.2</version>
                </dependency>

                <!-- MySQL驱动 -->
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>8.0.26</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>

2.添加、修改配置文件 generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
            targetRuntime: 执行生成的逆向工程的版本
                    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
                    MyBatis3: 生成带条件的CRUD(奢华尊享版)
     -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mybatis-example?useSSL=false&amp;useUnicode=true&amp;characterEncoding=utf8&amp;serverTimezone=Asia/Shanghai"
                        userId="root"
                        password="*******">
        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.atguigu.pojo" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="mapper"  targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mapper"  targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Employee"/>
        <table tableName="t_customer" domainObjectName="Customer"/>
        <table tableName="t_order" domainObjectName="Order"/>
    </context>
</generatorConfiguration>

 

进行测试

QBC(了解)

QBC:Query By Criteria 查询标准

QBC查询最大的特点就是将SQL语句中的WHERE子句进行了组件化的封装,让我们可以通过调用Criteria对象的方法自由的拼装查询条件。


        // 1.创建EmployeeExample对象
        EmployeeExample example = new EmployeeExample();
​
        // 2.通过example对象创建Criteria对象
        EmployeeExample.Criteria criteria01 = example.createCriteria();
        EmployeeExample.Criteria criteria02 = example.or();
​
        // 3.在Criteria对象中封装查询条件
        criteria01
            .andEmpAgeBetween(9, 99)
            .andEmpNameLike("%o%")
            .andEmpGenderEqualTo("male")
            .andEmpSalaryGreaterThan(500.55);
​
        criteria02
                .andEmpAgeBetween(9, 99)
                .andEmpNameLike("%o%")
                .andEmpGenderEqualTo("male")
                .andEmpSalaryGreaterThan(500.55);
​
        SqlSession session = factory.openSession();
​
        EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
​
        // 4.基于Criteria对象进行查询
        List<Employee> employeeList = mapper.selectByExample(example);
​
        for (Employee employee : employeeList) {
            System.out.println("employee = " + employee);
        }
​
        session.close();
​
        // 最终SQL的效果:
        // WHERE ( emp_age between ? and ? and emp_name like ? and emp_gender = ? and emp_salary > ? ) or( emp_age between ? and ? and emp_name like ? and emp_gender = ? and emp_salary > ? )

五、其他

1.Mapper映射、实体类别名

  • Mapper映射

注意:Mapper配置文件夹名称 需要和 mapper接口保持一致
Mapper配置文件放在Mapper接口所在的包内

  • 实体类别名
    <typeAliases>
        <!--给一个包下所有类起别名,别名是类名首字母小写-->
        <package name="com.atguigu.pojo"/>

        <!--给单个实体类起别名 不推荐-->
        <!--<typeAlias type="com.atguigu.pojo.Employee" alias="employee"></typeAlias>-->
    </typeAliases>

2.插件机制(了解)

插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行

著名的Mybatis插件包括 PageHelper(分页插件)、通用 Mapper(SQL生成插件)等。

如果想编写自己的Mybatis插件可以通过实现org.apache.ibatis.plugin.Interceptor接口来完成

但是由于插件涉及到Mybatis底层工作机制,在没有足够把握时不要轻易尝试。

3.类型处理器typeHandler(了解)

Mybatis内置类型处理器

Mybatis自定义类型处理器

1.开发自定义类型转换器:AddressTypeHandler

//自定义类型转换器
public class AddressTypeHandler extends BaseTypeHandler<Address> {
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Address address, JdbcType jdbcType) throws SQLException {

    }

    @Override
    public Address getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
        String name = resultSet.getString(columnName);
        System.out.println(name);
        String[] adds = name.split(",");
        Address address = new Address(adds[0],adds[1],adds[2]);
        return address;
    }

    @Override
    public Address getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return null;
    }

    @Override
    public Address getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return null;
    }
}

2.在配置文件中进行注册 

    mybatis-config.xml
    <!--注册类型转换器-->
    <typeHandlers>
        <typeHandler
                jdbcType="VARCHAR"
                javaType="com.atguigu.pojo.Address"
                handler="com.atguigu.handlers.AddressTypeHandler"/>
    </typeHandlers>

3.修改实体类、数据库表,测试
 

六、MBatis底层对JDBC的封装

SqlSession是一个接口,这里返回的是其实现类DefaultSqlSession的一个实例。其中有一个Executor类型的成员变量。其实进行数据库操作时SqlSession就是一个门面真正干活的却是Executor

1.Mbatis底层四大对象

你以为的四大对象:SqlSessionFactory,SqlSession,Mapper, 

JDBC四大对象DriverManager   Connection  Statement  ResultSet 

真正的四大对象ExecutorStatementHandlerParameterHandlerResultSetHandler 

①Executor

执行器,由它来调度 StatementHandler

②StatementHandler

使用数据库的 Statement 、PreparedStatement 执行操作

③ParameterHandler

处理SQL参数;比如查询的where条件、和insert、update的字段值的占位符绑定

 ④ResultSetHandler(只针对查询操作)

处理结果集ResultSet的封装返回。将数据库字段的值赋给实体类对象的成员变量。 

2.Mybatis底层四大步骤:

BaseExecutor 父类

SimpleExecutor 子类

Statement JDBC

查询

query()

doQuery()

executeQuery()

DML

update()

doUpdate()

executeUpdate()

第一步:获取数据库连接

        Connection connection = getConnection(statementLog);

第二步:获取Statement、PreparedStatement

        Statement stmt = handler.prepare(connection, transaction.getTimeout());

第三步:处理参数 (SELECT和DML),给SQL语句中的占位符赋值 ParameterHanlder

        handler.parameterize(stmt);

第四步:执行操作

        return handler.update(stmt);//insert update delete

        return handler.query(stmt, resultHandler); //select 会涉及到结果集ResultHandler


handler是StatementHandler,果真是常务副总经理

七、Mybatis大总结

  • 一、简介

    1. 理解框架

      • 生活案例:毛坯房;技术理解:jar+配置文件。

      • 好处:提供开发效率 统一了开发风格。

    2. ORM

      • Object-Relational Mapping 对象关系映射。

      • 数据库表---类 数据库表字段---类的成员变量 数据库表记录--对象。

      • 开发者对对象进行操作,结果反应到数据库表,避免了手动的转换。

    3. 和Hibernate对比

      • 都是持久层框架,都是对JDBC进行了封装。

      • 半自动化的MyBatis战胜了全自动化的Hibernate。

      • MyBatis将手写SQL语句的工作丢给开发者,可以更加精确的定义SQL,更加灵活,也便于优化性能。

      • 符合互联网高并发、大数据、高性能、高响应的要求,使它取代Hibernate成为了Java互联网中首选的持久框架.

  • 二、单表操作(基础)

    1. 项目构成

      • 配置文件:数据库连接参数、别名、开启二级缓存、指定映射文件的位置.

      • 映射文件:指定SQL语句(select、insert、update、delete)

      • 测试类:SqlSessionFactory、SqlSession、Mapper

    2. 两种方式

      • 无接口方式,直接调用SqlSession的方法(selectList、selectOne、update...)

      • Mapper接口方式:需提供接口,但是实现使用动态代理动态生成。(推荐)

    3. 数据输入:#{} ${}

    4. 数据输出:resultType resultMap

  • 三、多表操作(重点难点)

    1. 多表连接查询

      • 优点:一条SQL语句,速度快。

      • 缺点:不灵活,只有立即加载没有延迟加载。

    2. 分步查询

      • 缺点:多条SQL语句,速度慢。

      • 优点:灵活,不仅有立即加载还有延迟加载。

    3. Java类中添加属性

      • Customer:List<Order> orderList = new ArrayList()

      • Order:Customer customer;

    4. XML映射文件中配置

      • association

      • collection

    5. 重点掌握一对多操作基础上能够完成一对一、多对多的操作。

  • 四、动态SQL(开发中有应用

    1. 使用场合:避免了多条件查询下StringBuilder和append的字符串拼接,还可以应用insert、update操作

    2. if where trim 处理多条件查询,有几个条件就执行几个

    3. choose/when/otherwise 只执行第一个满足条件的条件

    4. foreach:循环

    5. set:update

    6. sql :提取SQL片段,避免重复修改

  • 五、缓存

    1. 作用:减少数据库访问次数,提高查询速度

    2. 分类:一级缓存(SqlSession)、二级缓存(SqlSessionFactory)

    3. 先查询二级缓存,再查询一级缓存、最后是查询数据库

    4. 一级缓存自动开启,二级缓存需要手动开启,可以引入第三方的二级缓存,比如Ehcache

    5. 日志框架体系,建议slf4j门面+logback/log4j2具体日志框架

  • 六、底层源码原理(面试中使用)

    1. 四大对象:Executor、StatementHandler、ParameterHandler、ResultSetHandler

    2. 四大步骤:获取数据库连接获取Statement|PreparedStatement处理参数 (SELECT和DML),给SQL语句中的占位符赋值 ParameterHanlder、执行操作

    3. 缓存的源码

    4. 读取属性文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值