栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

狂神说 | Mybatis完整版笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

狂神说 | Mybatis完整版笔记

Mybatis

目录
  • Mybatis
    • 1.简介
      • 1.什么是Mybatis
      • 2.持久层
        • 数据持久化
        • 为什么需要持久化?
      • 3.持久层
      • 4.为什么需要Mybatis
    • 2.第一个Mybatis程序
      • 1.搭建环境
      • 2.创建一个模块
        • 编写mybatis核心配置文件
        • 编写mybatis的工具类
      • 3.编写代码
        • 实体类
        • Dao接口
        • 接口实现类
      • 4.测试
        • 第一种方式:
        • 在测试的过程中可能遇到的问题:
        • 第二种方式:
        • 三个重要的类
        • 七个步骤
    • 3.CRUD(增删改查)
      • 1.namespace
      • 2.select
      • 3.Insert
      • 4.update
      • 5.delete
      • 具体步骤
      • 6.分析错误
      • 7.万能的map
      • 8.模糊查询怎么写
    • 4.配置解析
      • 1.核心配置文件
      • 2.环境配置(environments)
        • 事务管理
        • 数据源
      • 3.属性(properties)
        • 编写一个配置文件
        • 在核心配置文件中映入
      • 4.类型别名(typeAliases)
        • 第一种方式:
        • 第二种方式:
        • 默认别名
      • 5.设置(settings)
      • 6.其他
      • 7.映射器(mappers)
        • 方式一:使用类名路径的资源引用
        • 方式二:使用映射器接口实现类的完全限定类名
        • 方式三:使用包名进行注册绑定
      • 8.生命周期和作用域
        • 流程:
        • SqlSessionFactoryBulider:
        • SqlSessionFactory
        • SqlSeesion
    • 5.解决属性名和字段名不一致的问题
      • 1.问题
      • 2.resultMap
    • 6.日志
      • 1.日志工厂
      • 2.Log4j
        • 什么是LOG4J?
        • 1.先导入log4j的包
        • 2.log4j.properties
        • 3.配置为log4j为日志的实现
        • 4.Log4j的使用
        • 简单使用
    • 7.分页
      • 思考:为什么要分页?
      • 1.使用limit分页
      • 2.RowBounds分页
      • 3.分页插件
    • 8.使用注解开发
      • 1.面向接口编程
      • 2.使用注解编程
      • Mybatis详细的执行流程!
      • 3.CRUD
      • 4.关于@param注解
    • 9.Lombok
    • 10.多对一处理
      • 测试搭建环境
      • 复杂的SQL查询
        • 按照查询嵌套处理
        • 按照结果嵌套处理
    • 11.一对多
      • 环境搭建
      • 小结
      • 面试高频问题:
    • 12.动态SQL
      • 搭建环境
        • 创建一个基础工程:
      • IF
      • choose、when、otherwise
      • trim、where、set
        • trim的用法
      • SQL片段
      • Foreach
    • 13.缓存
      • 简介
      • Mybatis缓存
      • 一级缓存
      • 二级缓存
      • 缓存原理
      • 自定义缓存-ehcache

1.简介 1.什么是Mybatis

Maven依赖:


  org.mybatis
  mybatis
  3.5.2

2.持久层 数据持久化
  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(jdbc),io文件持久化
  • 生活中的持久化:冷藏
为什么需要持久化?
  • 有一些对象不能让他丢掉。
  • 内存太贵
3.持久层

Dao层,Service层,Controller层

  • 完成持久化工作的代码块
  • 层界限十分明显
4.为什么需要Mybatis
  • 方便
  • 传统的JDBC代码太复杂,简化框架
  • 不用Mybatis也可以
  • 优点:
    • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
    • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
    • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的orm字段关系映射
    • 提供对象关系映射标签,支持对象关系组建维护
    • 提供xml标签,支持编写动态sql。

最重要的一点:使用的人多

2.第一个Mybatis程序

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

1.搭建环境

搭建数据库

CREATE DATAbase mybatis;
USE mybatis;
CREATE TABLE user(
    id INT(20) NOT NULL,
    name VARCHAr(30) DEFAULT NULL,
    pwd VARCHAr(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO user (id,name,pwd)VALUES
(1,'张三','123456'),
(2,'李四','123456'),
(3,'王五','123456')

新建项目

01.新建一个普通的Maven项目

02.删除src目录

03.导入依赖数据库,mybatis junit

    
    
        
        
            mysql
            mysql-connector-java
            5.1.46
        
        
        
            org.mybatis
            mybatis
            3.5.2
        
        
        
            junit
            junit
            4.11
            test
        
    
2.创建一个模块 编写mybatis核心配置文件




    
        
            
            
                
                
                
                
            
        
    

编写mybatis的工具类

package xiaoqi.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;

//获取sqlSessionFactory
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    
    static {
        String resources = "mybatis-config.xml";
        try {
            //使用mybatis获取SqlsessionFactory对象
            InputStream inputStream = Resources.getResourceAsStream(resources);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法
    public static SqlSession getSqlSession(){
        //SqlSession是Mybatis最重要的构建之一,可以简单的认为Mybatis一系列的配置目的是生成类似
        // JDBC生成的Connection对象的SqlSession对象,这样才能与数据库开启“沟通”,
        // 通过SqlSession可以实现增删改查(当然现在更加推荐是使用Mapper接口形式)
        //SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSessionFactory.openSession();
    }

}
3.编写代码 实体类
package xiaoqi.pojo;

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

    public User() {
    }

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

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getPwd() {
        return pwd;
    }

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

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

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}
Dao接口
public interface UserDao {
    //可以避免JDBC代码和手动设置参数
    List getUserList();
}
接口实现类

在JDBC中,如果想要实现接口必须重写方法,在这里我们把原来的接口转变为一个Mapper配置文件。





    
    
    
    
        select * from mybatis.user
    
    
    select * from mybatis.user where id = #{id}

@Test
public void getUserById2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map map = new HashMap<>();
    map.put("id",5);
    User userById2 = mapper.getUserById2(map);
    System.out.println(userById2);


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

}

Map传递参数,直接在sql中取出key即可! parameterType=“map”

对象传递参数,直接在sql中取对象的属性即可 parameterType=“Object”

只有一个参数的情况下,可以直接在sql中取到

多个参数用map或者注解

8.模糊查询怎么写

java代码执行的时候,传递通配符:%

为了避免sql注入,说一在sql拼接中使用通配符

4.配置解析 1.核心配置文件
  • mybatis-config.xml
  • Mybatis的配置文件包含了回深深影响MyBatis行为的设置和属性信息

2.环境配置(environments)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中,尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

Mybatis默认的事务管理器是:JDBC,连接池:POOLED

事务管理

数据源 3.属性(properties)

我们可以properties属性实现引用配置文件

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

编写一个配置文件
driver = com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false
username=root
password=123456

在核心配置文件中映入

    
    

可以直接映入外部配置文件不在properties中写属性

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

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

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

4.类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写

第一种方式:

    

第二种方式:

扫描实体类的包,它的默认别名就为这个类的类名首字母大/小写


    

在实体类比较少的时候,使用第一种方式。

如果实体类比较多,建议使用第二种

第一种可以自定义别名,第二种则不行【注解可以作为别名使用】

默认别名

下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

别名映射的类型
_bytebyte
_longlong
_shortshort
_intint
_integerint
_doubledouble
_floatfloat
_booleanboolean
stringString
byteByte
longLong
shortShort
intInteger
integerInteger
doubleDouble
floatFloat
booleanBoolean
dateDate
decimalBigDecimal
bigdecimalBigDecimal
objectObject
mapMap
hashmapHashMap
listList
arraylistArrayList
collectionCollection
iteratorIterator
5.设置(settings)

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

设置名描述有效值默认值
cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true | falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true | falsefalse
aggressiveLazyLoading开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。true | falsefalse (在 3.4.1 及之前的版本中默认为 true)
multipleResultSetsEnabled是否允许单个语句返回多结果集(需要数据库驱动支持)。true | falsetrue
useColumnLabel使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。true | falsetrue
useGeneratedKeys允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。true | falseFalse
autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。NONE, PARTIAL, FULLPARTIAL
autoMappingUnknownColumnBehavior指定发现自动映射目标未知列(或未知属性类型)的行为。NONE: 不做任何反应WARNING: 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN)FAILING: 映射失败 (抛出 SqlSessionException)NONE, WARNING, FAILINGNONE
defaultExecutorType配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。SIMPLE REUSE BATCHSIMPLE
defaultStatementTimeout设置超时时间,它决定数据库驱动等待数据库响应的秒数。任意正整数未设置 (null)
defaultFetchSize为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。任意正整数未设置 (null)
defaultResultSetType指定语句默认的滚动策略。(新增于 3.5.2)FORWARD_onLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置)未设置 (null)
safeRowBoundsEnabled是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。true | falseFalse
safeResultHandlerEnabled是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。true | falseTrue
mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true | falseFalse
localCacheScopeMyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。SESSION | STATEMENTSESSION
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 | falsefalse
returnInstanceForEmptyRow当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2)true | falsefalse
logPrefix指定 MyBatis 增加到日志名称的前缀。任何字符串未设置
logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING未设置
proxyFactory指定 Mybatis 创建可延迟加载对象所用到的代理工具。CGLIB | JAVASSISTJAVASSIST (MyBatis 3.3 以上)
vfsImpl指定 VFS 的实现自定义 VFS 的实现的类全限定名,以逗号分隔。未设置
useActualParamName允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1)true | falsetrue
configurationFactory指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3)一个类型别名或完全限定类名。未设置
shrinkWhitespacesInSql从SQL中删除多余的空格字符。请注意,这也会影响SQL中的文字字符串。 (新增于 3.5.5)true | falsefalse
defaultSqlProviderTypeSpecifies an sql provider class that holds provider method (Since 3.5.6). This class apply to the type(or value) attribute on sql provider annotation(e.g. @SelectProvider), when these attribute was omitted.A type alias or fully qualified class nameNot set
6.其他
  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
    • mybatis-plus
    • mybatis-generator-core
    • 通用mapper
7.映射器(mappers)

注册绑定我们的Mapper文件

方式一:使用类名路径的资源引用

    

方式二:使用映射器接口实现类的完全限定类名

  

  • 接口和mapper配置文件必须同名
  • 接口和mappper配置文件必须在同一个包下
方式三:使用包名进行注册绑定

    

  • 接口和mapper配置文件必须同名
  • 接口和mappper配置文件必须在同一个包下
8.生命周期和作用域

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

流程:

SqlSessionFactoryBulider:
  • 一旦创建SqlSessionFactory,就不需要它了
  • 局部变量
SqlSessionFactory
  • 可以想象为:数据库连接池
  • 一旦创建就一直存在,没有任何理由丢弃它或创建新的实例
  • 因为SqlSessionFactory的最佳作用域是应用作用域
  • 最简单的就是使用单例模式或者静态单例模式
SqlSeesion
  • 每个线程都应该有自己的SqlSession实例;连接到连接池的一个请求

  • 需要开始和关闭

  • SqlSession不是线程安全的,所以不能被共享,最佳的作用域是放到一个方法里,用完就关闭,否则资源被占用

这里面的每一个mapper,就代表一个具体的业务

5.解决属性名和字段名不一致的问题 1.问题

数据库中的字段

新建一个项目,拷贝之前的,测试实体类字段不一致

出现了问题

//  select * from mybatis.user where id = #{id}
//  select id,name,pwd from mybatis.uer where id  =#{id}

解决方法:

  • 起别名
2.resultMap

结果集映射

id name pwd
id name password


    
    
    
    


        select * from mybatis.user where id = #{id}

  • resultMap 元素是 MyBatis 中最重要最强大的元素
  • 对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。

  • ResultMap 最优秀的地方在于,虽然你已经对它相当了解了,但是根本就不需要显式地用到他们
  • 世界总是这么简单就好啦
6.日志 1.日志工厂

如果一个数据库操作出现了异常,我们需要排错,日志就是最好的助手!

曾经的:sout、debug

现在的日志工厂

  • SLF4J
  • LOG4J
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING
  • NO_LOGGING

在mybatis中具体使用哪一个实现,在设置中设定

STDOUT_LOGGING 标准日志输出

在Mybatis核心配置文件中,配置我们的日志!




2.Log4j 什么是LOG4J?
  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等
  • 我们也可以控制每一条日志的输出格式;
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
  • 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
1.先导入log4j的包

    log4j
    log4j
    1.2.17

2.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/kuang.log 
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
3.配置为log4j为日志的实现

    

4.Log4j的使用

简单使用
  1. .在要使用Log4j的类中导入 import org.apache.log4j.Logger;

  2. 生成一个日志对象,参数为当前类的class

    static Logger logger = Logger.getLogger(UserDaoTest.class); //UserDaoTest为相关的类

  3. 日志级别

logger.info("info:进入了log4j");//进入了log4j
logger.debug("debug:进入了log4j");
logger.error("error:进入了log4j");
7.分页 思考:为什么要分页?
  • 减少数据的处理量
1.使用limit分页
SELECT * from user limit startIndex,pagesize

使用Mybatis实现分页,核心SQL

  1. 接口

    List getUserByLimit(Map map);
    
  2. Mapper.xml

    
        select * from mybatis.user limit #{startIndex},#{pageSize}
    
    
  3. 测试

    public void getUserByLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap map = new HashMap<>();
        map.put("startIndex",1);
        map.put("pageSize",2);
        List userByLimit = mapper.getUserByLimit(map);
        for (User user : userByLimit){
            System.out.println(user);
        }
        sqlSession.close();
    }
    
2.RowBounds分页

不再使用sql语言实现分页

  1. 接口

    List getUserByRowBounds();
    
  2. Mapper.xml

    
            select * from mybatis.teacher where id = #{id}
        
    
    
    
    按照结果嵌套处理
    
        select s.id sid,s.name sname, t.name tname, t.id tid
        from mybatis.student s , mybatis.teacher t
        where s.tid = t.id and t.id = #{tid}
    
    
        
        
        
        
            
            
            
        
    
    
     
        
            select * from mybatis.student where  tid = #{tid}
        
    
  3. 在核心配置文件中绑定注册mapper

    
        
        
        
    
    
  4. 测试

    public class MyTest {
        @Test
        public void test(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            Teacher teacher = mapper.getTeacher(1);
            System.out.println(teacher);
            sqlSession.close();
        }
    }
    
Teacher(id=1, name=秦老师, students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)])
小结
  1. 关联-association【多对一】
  2. 集合-collection【一对多】
  3. javaType ofType
    1. javaType 用来指定属性实体类中的类型
    2. ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

注意点:

  • 保证sql的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性和字段的问题
  • 如果问题不好排查错误,可以使用日志,建议使用Log4J

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

面试高频问题:
  • mysql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化
12.动态SQL

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

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach
搭建环境
CREATE TABLE `blog` (
  `id` varchar(50) NOT NULL COMMENT '博客id',
  `title` varchar(100) NOT NULL COMMENT '博客标题',
  `author` varchar(30) NOT NULL COMMENT '博客作者',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `views` int(30) NOT NULL COMMENT '浏览量'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

创建一个基础工程:
  1. 导入包

  2. 编写配置文件,注册绑定mapper文件

    
        
        
        
        
    
    
       
    
    
  3. 编写实体类

    package xiaoqi.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;
    
    import java.util.Date;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @ToString
    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createtime;
        private int views;
    }
    
  4. 编写实体类对应的Mapper接口和xml

    package xiaoqi.dao;
    
    import lombok.Data;
    import xiaoqi.pojo.Blog;
    
    public interface BlogMapper {
        //插入数据
        int addBlog(Blog blog);
    }
    
    
    
    
        
            insert into mybatis.blog (id,title,author,create_time,views)
            values (#{id},#{title},#{author},#{createtime},#{views});
        
    
    
  5. 工具类,生成随机的ID

    package xiaoqi.utils;
    
    import org.junit.jupiter.api.Test;
    
    import java.util.UUID;
    
    
    public class IDutils {
        public static String getId(){
            return UUID.randomUUID().toString().replace("-","");
        }
    
        @Test
        public void test(){
            System.out.println(IDutils.getId());
        }
    }
    
  6. 测试

    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import xiaoqi.dao.BlogMapper;
    import xiaoqi.pojo.Blog;
    import xiaoqi.utils.IDutils;
    import xiaoqi.utils.MybatisUtils;
    
    import java.util.Date;
    
    public class MyTest {
        @Test
        public void addBlogTest() {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
            Blog blog = new Blog();
            blog.setId(IDutils.getId());
            blog.setTitle("Mybatis");
            blog.setAuthor("狂神说");
            blog.setCreatetime(new Date());
            blog.setViews(9999);
    
            mapper.addBlog(blog);
    
            blog.setId(IDutils.getId());
            blog.setTitle("Java");
            mapper.addBlog(blog);
    
            blog.setId(IDutils.getId());
            blog.setTitle("Spring");
            mapper.addBlog(blog);
    
            blog.setId(IDutils.getId());
            blog.setTitle("微服务");
            mapper.addBlog(blog);
    
            sqlSession.close();
        }
    
    
    }
    
IF

    select * from mybatis.blog
    
        
            
                title = #{title}
            
            
                and author = #{author}
            
            
                and views = #{views}
            
        
    


trim、where、set


    select * from mybatis.blog
    
        
    

注意事项:

  1. 最好基于单表来定义SQL片段
  2. 不要存在where标签
Foreach

select * from mybatis.user where 1 =1 and

	#{id}

(id = 1 or id =2 or id = 3)

    select *from mybatis.blog
    
        
            id = #{id}
        

    

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

    mapper.queryBlogForeach(map);

    sqlSession.close();
}

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

建议:

  • 先在Mysql中写出完整的SQL,在对一个去修改成为我们的动态SQL实现通用即可
13.缓存 简介
查询:连接数据,耗资源!
一次查询的结果,给他暂存在一个可以取到的地方! ---> 内存 : 缓存

我们再次查询相同数据的时候,直接走缓存,就不用走数据库了。

查询

1.什么是缓存[Cache]?

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

2.为什么使用缓存?

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

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

  • 经常查询并且不经常改变的数据【可以使用缓存】
Mybatis缓存

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

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

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

一级缓存

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

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

测试步骤:

  1. 开启日志

  2. 测试在一个Session中查询两次相同记录!

    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import xiaoqi.dao.UserMapper;
    import xiaoqi.pojo.User;
    import xiaoqi.utils.MybatisUtils;
    
    public class MyTest {
        @Test
        public void test(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.queryUser(1);
            System.out.println(user);
            System.out.println("=============");
            User user1 = mapper.queryUser(1);
            System.out.println(user1);
            System.out.println(user == user1);
            sqlSession.close();
        }
    }
    
  3. 查看日志输出

缓存失效的情况:

  1. 查询不同的东西

    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import xiaoqi.dao.UserMapper;
    import xiaoqi.pojo.User;
    import xiaoqi.utils.MybatisUtils;
    
    public class MyTest {
        @Test
        public void test(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.queryUser(1);
            System.out.println(user);
            System.out.println("=============");
            User user1 = mapper.queryUser(2);
            System.out.println(user1);
            System.out.println(user == user1);
            sqlSession.close();
        }
    }
    

  2. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存

    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import xiaoqi.dao.UserMapper;
    import xiaoqi.pojo.User;
    import xiaoqi.utils.MybatisUtils;
    
    public class MyTest {
        @Test
        public void test(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.queryUser(1);
            System.out.println(user);
            mapper.UpdateUser(new User(2,"asas","12345678"));
            System.out.println("=============");
            User user1 = mapper.queryUser(1);
            System.out.println(user1);
            System.out.println(user == user1);
            sqlSession.close();
        }
    }
    

  3. 查询不同的Mapper

  4. 手动清理缓存

    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import xiaoqi.dao.UserMapper;
    import xiaoqi.pojo.User;
    import xiaoqi.utils.MybatisUtils;
    
    public class MyTest {
        @Test
        public void test(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.queryUser(1);
            System.out.println(user);
            sqlSession.clearCache();
            System.out.println("=============");
            User user1 = mapper.queryUser(1);
            System.out.println(user1);
            System.out.println(user == user1);
            sqlSession.close();
        }
    }
    

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

一级缓存就是一个map

二级缓存

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

步骤:

  1. 开启全局缓存

    
    
    cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true | falsetrue
  2. 在要使用二级缓存的Mapper中开启

    
    

    也可以自定义参数

  3. 测试

    1. 我们需要将实体类序列化!否则就会报错 Cause: java.io.NotSerializableException: xiaoqi.pojo.User
    public class MyTest {
        @Test
        public void test(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            SqlSession sqlSession1 = MybatisUtils.getSqlSession();
    
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.queryUser(1);
            System.out.println(user);
            sqlSession.close();
      
            //关掉第一个sqlsession才会将一级缓存中的数据保存到二级缓存中
            UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
            User user1 = mapper1.queryUser(1);
            System.out.println(user1);
            System.out.println(user == user1);
            sqlSession1.close();
        }
    }
    

小结:

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

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import xiaoqi.dao.UserMapper;
import xiaoqi.pojo.User;
import xiaoqi.utils.MybatisUtils;

public class MyTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        SqlSession sqlSession1 = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUser(1);
        System.out.println(user);
        sqlSession.close();

        System.out.println("==============");
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        User user1 = mapper1.queryUser(1);

        User user2 = mapper1.queryUser(2);
        System.out.println(user1);
        System.out.println(user2);
        System.out.println("=======");
        User user3 = mapper1.queryUser(2);
        System.out.println(user3);
        sqlSession1.close();
    }
}

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

自定义缓存-ehcache

Ehcache是一种广泛使用的开源Java分布式缓存,主要面向通用缓存

要在程序中使用ehcache:

  • 导入包

    org.mybatis.caches
    mybatis-ehcache
    1.1.0


  • ehcache的配置文件



    

    

    
        
    
    
  • 使用ehchache

redis做缓存

https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->

org.mybatis.caches
mybatis-ehcache
1.1.0

- ehcache的配置文件

```xml



    

    

    
        
    
    
  • 使用ehchache

redis做缓存

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/351859.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号