【MyBatis】一天之内快速掌握MyBatis的增删改查

2023-11-12

MyBatis

文章介绍:

一共不到8000字,一天之内可以快速学会mybatis的增删改查,
以及经常使用的操作,不讲废话,只将眼光聚焦到实操上,也可以搭配黑马的视频观看
看完之后,可以自己找个mybatis源码课继续学习
,但是一般的业务代码也只用到文章大部分内容

Mybatis是一款半ORM的持久层框架,简化JDBC的框架

一、快速入门


  1. 创建SQL表
  2. 编写MyBatis配置文件
  3. 编写SQL语句
  4. java定义POJO类
  5. SqlSessionFactory对象,获取SqlSession
  6. 执行Sql语句
  7. 释放资源

二、mapper代理开发


MyBtais使用mapper代理开发三个步骤:

  1. 定义mapper接口方法
  2. 定义SQL语句,其实就是写mapper.xml
  3. 调用者生成mapper 实例化对象,来进行操作
  • 主要记得mapper接口要和resources目录下的mapper.xml一个目录;

  • 如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载。也就是将核心配置文件的加载映射配置文件的配置修改为

<mappers>
    <!--加载sql映射文件-->
    <!-- <mapper resource="com/itheima/mapper/UserMapper.xml"/>-->
    <!--Mapper代理方式-->
    <package name="com.it.mapper"/>
</mappers>
  • 重复性高的sql语句,在mapper.xml中,使用sql标签,定义sql片段。

三、难点业务


难点1:遇到数据库表字段与实体类属性名名称不一致,如何处理


1. SQL字段起别名

使用sql标签定义statement片段,将数据库字段as成实体类属性名。在statement中include进来。
例如

<sql id="brand_column">
	id, brand_name as brandName, company_name as companyName, ordered, description, status
</sql>
<select id="selectAll" resultType="brand">
    select
    <include refid="brand_column" />
    from tb_brand;
</select>
2. ResultMap 封装结果集,实现数据库字段和实体类属性的映射关系

实现多字段数据库表只有些许字段需要对应修改,完成不一致的属性名和列名的映射

例如

<resultMap id="brandResultMap" type="brand">
     <!--
            id:完成主键字段的映射
                column:表的列名
                property:实体类的属性名
            result:完成一般字段的映射
                column:表的列名
                property:实体类的属性名
        -->
     <result column="brand_name" property="brandName"/>
     <result column="company_name" property="companyName"/>
</resultMap>

<select id="selectAll" resultMap="brandResultMap">
    select *
    from tb_brand;
</select>

难点2: where条件如何添加参数


1. sql语句参数占位符使用
  1. #{}:推荐使用,在sql语句中是 ?存在,就是jdbc的PreparedStatement
  2. ${}:拼接sql语句,存在sql注入问题,底层就是Statement
  3. 使用时机:参数传递用#{};对于可变列名、表名用${},但是实际中没什么用
2.parameterType使用

parameterType,对于有参数的mapper接口,一般在xml中可以省略,框架会自动封装。
例子

/*
* id:唯一标识符
* parameterType:传递参数类型
* resultMap:返回类型
*/
<select id="selectById" parameterType="int" resultMap="brandResultMap">
    select *
    from tb_brand where id = ${id};
</select>
3.SQL语句中特殊字段处理
  1. 使用xml的转义字符:例如&lt; 就是 < 的转义字符。
  2. <![CDATA[内容]]>,内容里面就写有歧义的内容
4. 总结例子
/*
* id:唯一标识符
* parameterType:传递参数类型,可以省略
* resultMap:返回类型
*/
<select id="selectById" parameterType="int" resultMap="brandResultMap">
    select *
    from tb_brand where id 
    <![CDATA[
    		<
    ]]>
     #{id};
</select>

难点3: 多条件查询


1. 重点:
条件需要模糊查询
2. mapper接口参数接受
  1. 散装参数接受

    使用 @Param("参数名称") 注解标记每一个参数,在映射配置文件中就需要使用 #{参数名称} 进行占位,两个名称要一致。
    代码:

List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName,@Param("brandName") String brandName);

  1. 实体类封装参数
    保证SQL语句的占位参数名称#{参数名称}跟实体类属性名一致就行了
List<Brand> selectByCondition(Brand brand);
  1. map封装参数
    保证map集合的key跟sql的占位参数名称#{参数名称}一致就行了
List<Brand> selectByCondition(Map map);
3.sql语句编写
<select id="selectByCondition" resultMap="brandResultMap">
    select *
    from tb_brand
    where status = #{status}
    and company_name like #{companyName}
    and brand_name like #{brandName}
</select>

记得占位参数名称#{"参数名称"}与三种方式要对应上。

4.调用

在调用中,要实现模糊查询,应该在调用时封装参数

// 处理参数
    companyName = "%" + companyName + "%";
    brandName = "%" + brandName + "%";

难点4: 添加数据


1.接口方法

参数使用实体类对象

void add(Object obj);
2.sql语句

正常的insert语句

<insert id="add">
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
3.提交事务
  1. SqlSession sqlSession = sqlSessionFactory.openSession(true); //设置自动提交事务,这种情况不需要手动提交事务了

  2. sqlSession.commit();//手动提交事务

4.主键返回
在业务中,可能需要主键注入到对象中,融合再读取作为其他的外键

所以,我们要修改mapper里面的代码

<insert id="add" useGeneratedKeys="true" keyProperty="id">
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
新增的两个属性
  1. useGeneratedKeys:是够获取自动增长的主键值。true表示获取
  2. keyProperty :指定将获取到的主键值封装到实体类对象哪儿个属性里,比如写的是"id",就类似于写到brand.id

难点4: 删除单条数据

1.编写接口方法
在 Mapper 接口中定义根据id删除方法。
/**
  * 根据id删除
  */
void deleteById(int id);
2 编写SQL语句
在 Mapper.xml 映射配置文件中编写删除一行数据的 statement
<delete id="deleteById">
    delete from tb_brand where id = #{id};
</delete>

四、动态sql


1.动态多条件查询


1. 描述
在业务中,用户存在只填写一个信息,进行查询的情况,
需要我们动态去拼接statement
2.if标签
  • 使用if标签,实现条件判断,逻辑表达式写在test=" condition "里面。
  • 例子:
<select id="selectByCondition" resultMap="brandResultMap">
    select *
    from tb_brand
    where
        <if test="status != null">
            and status = #{status}
        </if>
        <if test="companyName != null and companyName != '' ">
            and company_name like #{companyName}
        </if>
        <if test="brandName != null and brandName != '' ">
            and brand_name like #{brandName}
        </if>
</select>
3. where 标签

在上小节内容中,还存在一个问题,如果status条件不通过,会导致sql语句存在语法问题,有两种方法解决这个逻辑运算符问题

  1. 使用恒等式 ,例如 条件中加入1=1,每个条件都用and连接
<select ...
    where 1=1
        <if test="status != null">
            and status = #{status}
     ....
</select>
  1. MyBatis中使用where标签能帮我们解决这个问题,会自动判断语句,在这个例子中,会自动帮我消去多余的and。
    例子
<select id="selectByCondition" resultMap="brandResultMap">
    select *
    from tb_brand
    <where>
        <if test="status != null">
            and status = #{status}
        </if>
        <if test="companyName != null and companyName != '' ">
            and company_name like #{companyName}
        </if>
        <if test="brandName != null and brandName != '' ">
            and brand_name like #{brandName}
        </if>
    </where>
</select>

2.动态单条件查询


1.编写mapper接口方法
由于是可选条件,所以采用传入对象方法
/**
  * 单条件动态查询
  * @param brand
  * @return
  */
List<Brand> selectByConditionSingle(Brand brand);
2. 编写sql方法
<select id="selectByConditionSingle" resultMap="brandResultMap">
    select *
    from tb_brand
    <where>
        <choose><!--相当于switch-->
            <when test="status != null"><!--相当于case-->
                status = #{status}
            </when>
            <when test="companyName != null and companyName != '' "><!--相当于case-->
                company_name like #{companyName}
            </when>
            <when test="brandName != null and brandName != ''"><!--相当于case-->
                brand_name like #{brandName}
            </when>
        </choose>
    </where>
</select>
当然没有where标签时候是下面这样
<select id="selectByConditionSingle" resultMap="brandResultMap">
    select *
    from tb_brand
    where
        <choose><!--相当于switch-->
            <when test="status != null"><!--相当于case-->
                status = #{status}
            </when>
            <when test="companyName != null and companyName != '' "><!--相当于case-->
                company_name like #{companyName}
            </when>
            <when test="brandName != null and brandName != ''"><!--相当于case-->
                brand_name like #{brandName}
            </when>
            <otherwise><!--相当于default-->
            	1=1
            </otherwise>
        </choose>
    where
</select>

3.动态update


1. 编写接口方法
 /**
   * 修改
   */
int update(Brand brand);
上述方法参数 Brand 就是封装了需要修改的数据,而id肯定是有数据的,
这也是和添加方法的区别,而且update会返回受影响行数
2.动态sql语句
<update id="update">
    update tb_brand
    <set>
        <if test="brandName != null and brandName != ''">
            brand_name = #{brandName},
        </if>
        <if test="companyName != null and companyName != ''">
            company_name = #{companyName},
        </if>
        <if test="ordered != null">
            ordered = #{ordered},
        </if>
        <if test="description != null and description != ''">
            description = #{description},
        </if>
        <if test="status != null">
            status = #{status}
        </if>
    </set>
    where id = #{id};
</update>
set标签的作用
  1. 解决逗号的问题
  2. 解决防止条件都不成立的问题

4.批量删除(使用动态SQL)


用到的sql:delete from table where id in (?,?,?);,其中的?是可变的

1.编写接口方法
在 Mapper 接口中定义删除多行数据的方法。
/**
  * 批量删除
  */
void deleteByIds(int[] ids);

/**
  * 使用@param注解,来重新定义map的key的名字
  */
void deleteByIds(@param("ids")int[] ids)

参数是一个数组,数组中存储的是多条数据的id

2.编写SQL语句
在 Mapper.xml 映射配置文件中编写删除多条数据的 statement。

编写SQL时需要遍历数组来拼接SQL语句。Mybatis 提供了 foreach 标签供我们使用
foreach 标签

用来迭代任何可迭代的对象(如数组,集合)。

  • collection 属性:
    1. mybatis会将数组参数,封装为一个Map集合。
    2. 默认:array = 数组
    3. 使用@Param注解改变map集合的默认key的名称,"自定义名称"取代"array"
  • item 属性:本次迭代获取到的元素。
  • separator 属性:集合项迭代之间的分隔符。foreach 标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。
  • open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次
  • close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次
<delete id="deleteByIds">
    delete from tb_brand where id
    in
    <foreach collection="array" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
    ;
</delete>

五、参数传递


总结以上,我们可以发现,接口方法编写的时候,为什么有的地方要加@param注解,有的地方不加,而且为什么加@param注解后,就可以使用其值,如果不加@param注解,能否表示占位参数呢?我们根据 MyBatis底层的类,可以总结以下规律

1.多个参数

Mybatis 会将这些参数封装成 Map 集合对象,值就是参数值,不加@param注解时,每个参数会加两个key,例如参数1,会加

map.put(“arg0”,参数值1);
map.put(“param1”,参数值1);

使用 @Param 注解后,Mybatis 会将 arg 开头的键名替换为对应注解的属性值。

add(@Param("name")String name,...)
map.put(“name”,参数值1);
map.put(“param1”,参数值1);

2.单个参数

  1. POJO 类型

    直接使用。要求 属性名 和 参数占位符名称 一致

  2. Map 集合类型

    直接使用。要求 map集合的键名 和 参数占位符名称 一致

  3. Collection 集合类型

    Mybatis 会将集合封装到 map 集合中,如下:

	map.put(“arg0”,collection集合);
	map.put(“collection”,collection集合;
可以使用 @Param 注解替换map集合中默认的 arg 键名。
  1. List 集合类型

    Mybatis 会将List集合封装到 map 集合中,如下:

map.put(“arg0”,list集合);
map.put(“collection”,list集合);
map.put(“list”,list集合);

可以使用 @Param 注解替换map集合中默认的 arg 键名。

  1. Array 类型

Mybatis 会将集合封装到 map 集合中,如下:

map.put(“arg0”,数组);
map.put(“array”,数组);
可以使用 @Param 注解替换map集合中默认的 arg 键名。
  1. 其他类型

    比如int类型,参数占位符名称 叫什么都可以。尽量做到见名知意

六、注解开发

查询 :@Select
添加 :@Insert
修改 :@Update
删除 :@Delete

注解完成简单功能,配置文件完成复杂功能。

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

【MyBatis】一天之内快速掌握MyBatis的增删改查 的相关文章

  • Hibernate 可以使用 MySQL 的“ON DUPLICATE KEY UPDATE”语法吗?

    MySQL 支持 INSERT ON DUPLICATE KEY UPDATE 语法允许您 盲目 插入数据库 并回退到更新现有记录 如果存在 当您想要快速事务隔离并且想要更新的值取决于数据库中已有的值时 这非常有用 作为一个人为的示例 假设
  • 如何在不超时的情况下解析大型 CSV 文件?

    我正在尝试解析 50 MB 的 csv 文件 文件本身很好 但我正在尝试解决所涉及的大量超时问题 每个设置上传明智 我可以轻松上传并重新打开文件 但浏览器超时后 我收到 500 内部错误 我的猜测是我可以将文件保存到服务器上 打开它并保留我
  • MySQL有两个不同的密码?

    我确信它们是不同事物的密码 但我不确定是什么 当在终端连接到 MySQL 时 我输入 usr LOCAL mysql BIN mysql h host u username p然后系统会提示我输入密码 密码是 但是当使用 PHP 连接到 M
  • 如何用 UNION 运算符替换 OR 运算符?

    这是我的查询 SELECT h id h subject h body matnF h amount h keywords tags h closed h author id author h AcceptedAnswer h type h
  • SQL统计高于和低于平均分的学生人数

    我在下面有一个示例表 我试图获取高于平均分数的学生人数和低于平均分数的学生人数 name subject classroom classarm session first term score first term grade std1 m
  • 如何使PHP中的激活链接过期?

    我有一个 php 脚本 它通过电子邮件向用户发送激活链接 以便他们可以激活他们的帐户 链接是这样的 mysite com activation phpid id 20 如何创建 24 小时后过期的链接 我还没有尝试过任何东西 因为我找不到任
  • 如何在MyBatis foreach中迭代HashMap?

    我正在尝试在 mybatis 中生成如下所示的 sql SELECT COL C FROM TBLE 1 WHERE COL A COL B in kp kar srt sach 而我的输入参数类型是HashMap 现在如何从映射器 xml
  • MySQL InnoDB 查询性能

    我正在尝试优化一个简单的 sql 查询 该查询将多次运行大量数据 这是场景 MySQL 与 InnoDB 表 where 和 join 中使用的所有字段都已索引 表有 FK 我不需要查询的整个缓存 但每个表的缓存是可能的 表有更多的更新 插
  • Preg_replace() 删除除查询结尾之外的所有内容

    首先 为我糟糕的英语感到抱歉 我有这样的疑问 SELECT t1 SELECT COUNT FROM table a t2 WHERE t1 id t2 id c AND t2 status 1 AS aula FROM table c t
  • 通过连接从两个表中删除?

    我有两个表如下 tbl1 tbl2 id article id title image whole news tags author older datetime 其中 tbl1 id gt tbl2 article id 如何从两个表中删
  • 如何以最少的查询次数获取帖子列表和关联标签

    我的表格结构如下 标签 更多的是一个类别 id 标签名称 描述 slug POSTS ID 标题 网址 邮戳 id idPost idTag USERS ID 用户名 userSlug VOTES id idPost idUser 每个帖子
  • 社交应用程序的数据库设计和优化注意事项

    通常的情况 我有一个简单的应用程序 允许人们上传照片并关注其他人 因此 每个用户都会有类似 墙 或 活动源 的东西 他或她可以在其中看到他 她的朋友 他或她关注的人 上传的最新照片 大多数功能都很容易实现 然而 当涉及到这个历史活动源时 由
  • Mysql innoDB 不断崩溃[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我的数据库 mysql 服务器不断崩溃 重新启动 我不知道该怎么办 我不断在 dbname org err 文件中收到以下内容 13120
  • PDO SQLSRV 和 PDO MySQL 在获取 int 或 float 时返回字符串

    当您获取时 PDO MS SQL Server 和 PDO MySQL 都会返回一个字符串数组 即使列的 SQL 类型本应是数字类型 例如 int 或 float 我设法解决了这个问题 但我想了解为什么它们一开始就这样设计 是不是因为PDO
  • Hibernate 对集合的查询过滤器

    我想执行以下查询 from Item i where i categoryItems catalogId catId 然而 这会产生以下异常 非法尝试取消引用集合 所以我用谷歌搜索 找到了这个 Hibernate 论坛帖子https for
  • 如何在Mysql中仅将不同的值从一个表复制到另一个表?

    我有一个大约 2 5GB 的 MySql 数据库 表 A 具有以下列 anoid query date item rank url 我刚刚创建了另一个仅包含列的表 b query and date 我想在查询列中插入所有不同的记录 及其各自
  • 如何正确转义mysql?

    我刚刚发现如果我写 select from tbl where name like foo 然后添加 foo 作为参数及其值 a 用户数据 它不会正确转义 我勒个去 它想要 a 即使我使用参数 我还是忍不住觉得我对 sql 注入持开放态度
  • 无法通过套接字“/var/lib/mysql/mysql.sock”连接到本地 MySQL 服务器 (2)

    当我尝试连接 mysql 时出现以下错误 Can t connect to local MySQL server through socket var lib mysql mysql sock 2 这个错误有解决办法吗 其背后的原因可能是什
  • Mysql 中 UNION 子句的替代方案

    我有两张桌子 表 a 表 b table a ID 1 2 3 4 5 7 table b ID 2 3 4 5 6 我必须得到这样的输出而无需UNION命令 ID 1 2 3 4 5 6 7 注意 我有一个联合解决方案 select fr
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri

随机推荐

  • [docker]笔记-网络管理

    1 docker网络原理 docker安装完成后 会在宿主机中创建一个虚拟网桥 用于容器之间和容器与外部网络的连接 虚拟网桥通常名称为docker0 可以使用ip link show命令进行查看 在docker中 各个容器是通过这个dock
  • 虚拟+现实

    随着现代信息技术与软硬件技术的快速发展 嵌入式系统的功能日益强大 嵌入式设备和软件应用领域越来越宽泛 近年来 嵌入式软件代码量呈爆炸式增长 对测试的要求越来越高 尤其是涉及防务 航空 汽车等安全关键领域 半实物仿真测试系统的研制难度适中 投
  • 合宙Air103

    基础资料 基于Air103开发板 Air103 LuatOS 文档 上手 开发上手 LuatOS 文档 探讨重点 对官方I2C demo中功能的复现 进行相关内容的学习及探讨 实现功能 功能2 三轴加速度陀螺仪 MPU6050模块 硬件准备
  • Typora+PicGo-Core上传服务设置

    一 Typora中安装PicGo Core 二 安装插件 Win10为例 首先点击验证图片上传选项根据提示找到安装路径 我的路径为C Users 86137 AppData Roaming Typora picgo win64 picgo
  • Qt5.14版本通用环境配置安装——最详细教学(看不懂,你怪我)

    大家好 我是会飞的鱼 blog 今天我来给大家介绍一下Qt5 14 1安装 有不足之处 请大家多多指教 感谢大家支持 目录 前言 安装文件下载 安装 设置 QtCreator 编译路径 设置 Qt 源码路径 以上就是全部安装步骤 已经完成
  • moxa串口服务器型号,moxa串口服务器产品配置说明

    moxa串口服务器产品配置说明 内容精选 换一换 为弹性云服务器配置的安全组规则未生效 以下排查思路根据原因的出现概率进行排序 建议您从高频率原因往低频率原因排查 从而帮助您快速找到问题的原因 如果解决完某个可能原因仍未解决问题 请继续排查
  • 实现一个Android锁屏App的难点总结

    http blog csdn net ldld1717 article details 69389125 https segmentfault com a 1190000007157971 自定义一个漂亮实用的锁屏app 如果能赢得用户的认
  • 第一个汇编程序hello world

    近来 看了看以下汇编视频 终于学了第一个汇编程序 hello world 下面分享以下程序的各部分代码和注释 希望大家有所帮助 程序源码如下 assume cs code ds data 定义代码段和数据段框架 data segment 数
  • 由于找不到xinput1_3.dll,无法继续执行代码的解决方法都有哪些?

    关于由于找不到xinput1 3 dll 无法继续执行代码这个问题 其实在网上经常看别人提及 要解决这个问题 还是不难的 今天小编就来给大家详细的说说关于这个问题的解决方法吧 本文会介绍多种的修复方法 下面一起来看看 一 xinput1 3
  • ubuntu 安装Nginx 以及简单配置

    Nginx使用的地方特别多 很久以前就知道Nginx使用范围很广 却并不知道Nginx具体可以做什么 怎么使用 最近读了几篇关于Nginx的文章 对Nginx有了大致的了解 只看不练无法解决真正的问题 此处主要是Nginx的安装以及 Ngi
  • 常见异常汇总

    目录 登录异常 org apache ibatis binding BindingException Invalid bound statement not found com jt mapper UserMapper findUserBy
  • MyBatis<if>标签判断字符串相等写法

    mybatis 映射文件中 if标签判断字符串相等 两种方式 因为mybatis映射文件 是使用的ognl表达式 所以在判断字符串sex变量是否是字符串Y的时候 1
  • 【数据结构】栈的代码实现

    个人博客 www hellocode top 所有文章均在上方博客首发 其他平台同步更新 本文专栏 数据结构与算法 如有问题 欢迎指正 一起学习 文章参考整理自小码哥的 恋上数据结构和算法 课程 图片转载自课程PPT 如有侵权 请联系删除
  • shell命令

    1 系统信息 arch 显示机器的处理器架构 1 uname m 显示机器的处理器架构 2 uname r 显示正在使用的内核版本 dmidecode q 显示硬件系统部件 SMBIOS DMI hdparm i dev hda 罗列一个磁
  • JAVA代码添加License

    在开源代码的时候 我们经常会在代码顶部添加License信息 每个文件复制粘贴显然是比较麻烦的 我们可以在工具中进行配置 在创建新的类的时候自动为我们添加相关信息 以eclipse为例 进入Preference gt Java gt Cod
  • SQL笔记(一)

    1 初识MySQL JavaEE 企业级Java开发 Web 前端 页面 展示 数据 后台 连接点 连接数据库JDBC 链接前端 控制 控制视图跳转 和给前端传递数据 数据库 存数据 ITxt Excel word 只会写代码 学好数据库
  • sqli-labs (less-39)

    sqli labs less 39 输入id 1 http 127 0 0 1 sql1 Less 39 id 1 根据错误显示判断为数字型注入 这里我们就不讲使用union注入的方法 前面的关卡讲了很多union注入的方法 我们直接使用堆
  • word:表格中的文字居中

    如 操作 如下图 选择布局 点击2就可以把表格居中了 居中结果
  • 实时ETL解决方案总结

    问题导读1 实时ETL可以选择哪些架构部件 2 实时ETL有哪些实现方法 3 实时ETL有哪些难点 1 简述在架构实时ETL时的可以选择的架构部件 答 在建立数据仓库时 ETL通常都采用批处理的方式 一般来说是每天的夜间进行跑批 随着数据仓
  • 【MyBatis】一天之内快速掌握MyBatis的增删改查

    MyBatis 文章介绍 一共不到8000字 一天之内可以快速学会mybatis的增删改查 以及经常使用的操作 不讲废话 只将眼光聚焦到实操上 也可以搭配黑马的视频观看 看完之后 可以自己找个mybatis源码课继续学习 但是一般的业务代码