MyBatis:轻量级Java持久层框架初探

news2024/12/28 3:01:48

引言

在Java企业级应用开发领域,ORM框架无疑是构建高性能数据访问层的关键工具之一。MyBatis作为一款轻量级、易于学习且高度可定制化的持久层框架,以其简洁的设计理念、卓越的灵活性和高效的SQL处理能力,赢得了广大开发者的青睐。本文将系统全面地探讨MyBatis的基础架构、核心特性和应用场景,并结合实际开发经验,引导读者深入了解和高效使用MyBatis。本文偏向基础应用讲解,深入可查阅官方文档。

一、MyBatis入门与基础概念

1. MyBatis简介 

MyBatis是一款基于Java的持久层框架,它通过映射配置文件或注解方式将SQL语句与Java对象关联起来,极大降低了传统JDBC编程的复杂度。MyBatis通过SqlSession API提供CRUD操作,并支持事务管理和结果映射等功能,使得开发者能够集中精力于业务逻辑开发,而非繁琐的数据库交互细节。

Mybatis框架的简单应用架构,如图所示:

2. 基本架构与核心组件

  • Configuration(配置):MyBatis的核心配置文件,用于设置数据库连接信息、映射文件位置、插件、缓存策略等全局配置项。
  • SqlSessionFactoryBuilder(工厂构建器):用于根据Configuration对象构建SqlSessionFactory实例。
  • SqlSessionFactory(工厂):负责创建SqlSession实例,是数据库会话的生产者。
  • SqlSession(会话):MyBatis的工作单元,提供了执行SQL、获取映射结果、提交或回滚事务等操作接口,每个SqlSession都会维护自己的一级缓存。
  • Mapper接口与映射文件:通过XML或注解方式定义SQL语句和结果映射规则,MyBatis通过动态代理机制将接口方法与映射文件中的SQL绑定,实现面向对象的数据库操作。

二、MyBatis核心特性详解

1. 映射配置与动态SQL

  • Mapper XML配置:在XML映射文件中定义SQL查询语句、插入、更新、删除等操作,并通过<resultMap>标签精细化地配置结果集到Java对象的映射规则,支持嵌套结果集、集合、联合查询等多种复杂映射场景。
  • 动态SQL:MyBatis提供了一系列动态标签如<if><choose><when><otherwise><where><set>等,使得SQL语句可以根据Java变量的值动态生成,极大地增强了SQL表达力和灵活性。

1.1 xml与注解比较

1.1.1 xml定义

XML是一种可扩展性语言,用户可以自己定义标签,用来描述特定类型的数据;

XML的语法严格,每个标签都必须有一个结束标签,标签的嵌套关系也必须合法;

1.1.2 和SQL注解比较
  • xml配置SQL,可以将SQL语句和JAVA代码分离开
  • xml配置SQL,支持动态SQL语句
  • xml配置SQL,支持SQL语句的复用

1.2 环境初始化

  • SpringBoot版本:2.7.12
  • 依赖项

        1.MyBatis Framework

        2.MySQL Driver

1.3 使用流程

1.在resources目录下创建 mappers目录,用来存放xml配置文件

2.下载映射文件模板

3. application.properties中添加配置:mybatis框架映射配置文件的位置

# 设置MyBatis框架的映射(Mapper)配置文件的位置
mybatis.mapper-locations=classpath:mappers/*.xml

1.4 xml配置SQL标签

说明

在 Mybatis 的 XML 文件中,SQL 语句都是使用 SQL 标签来定义的。

常用的SQL标签

select

用于查询操作,包括多表查询、条件查询等。可以使用 resultType 来指定返回结果的类型。

insert

用于插入操作,并将其自动注入实体类中。

update

用于更新操作,包括更新一条记录或者批量更新。

delete

用于删除操作,包括删除一条记录或者批量删除。

if、foreach、set

用于条件控制,可以根据不同的条件进行查询、插入、更新和删除操作。if 标签用于指定可以 为空的查询条件,foreach 标签用于循环查询,set 标签用于指定更新操作的字段值。

sql:用于定义可重用的 SQL 片段,通常是一些较为复杂的 SQL 片段。可以在其它 SQL 语句 中使用 include 标签来引用 SQL 片段。

include:用于引入外部的 SQL 片段。可以在 include 标签的 refid 属性中指定外部 SQL 片段 的名字,然后在当前 SQL 中使用它。

这些 SQL 标签可以随意组合,可以使 SQL 语句变得很灵活和强大。通常需要根据实际业务场 景选择合适的标签来实现相应的 SQL 操作。

1.5 整合MyBatis完成用户数据操作

1.5.1 知识点设计

基于本业务实现MyBatis基本操作,掌握MyBatis中xml配置SQL的应用。

1.5.2 Dao接口设计

UserMapper.java

@Mapper
public interface UserMapper {
    /**在User表中插入一条表记录*/
    int insert(User user);
}
1.5.3 定义映射文件

UserMapper.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">

<!-- 1.填写namespace,填写UserMapper的绝对路径 -->
<mapper namespace="cn.qiang._04mybatis.mapper.UserMapper">
    <!-- id的属性值要和UserMapper中定义的方法名一致 -->
    <insert id="insert">
        INSERT INTO user VALUES (NULL,#{username},#{password},#{nickname},#
{created})
    </insert>
</mapper>
1.5.4 Dao接口单元测试
// 自动装配
@Autowired
private UserMapper userMapper;

// 测试插入数据
@Test
void testInsert(){
    User user = new User();
    user.setUsername("熊三");
    user.setPassword("123456");
    user.setNickname("只手遮天");
    user.setCreated(new Date());
    // 调用接口方法
    System.out.println(userMapper.insert(user));
}

1.6 整合MyBatis完成标签业务操作

1.6.1 业务描述

基于SpringBoot脚手架工程对MyBatis框架的整合,实现对微博内容weibo表进行操作。

1.6.2 Dao接口设计

WeiboMapper.java

package cn.qiang._04mybatis.mapper;

import cn.qiang._04mybatis.pojo.Weibo;
import org.apache.ibatis.annotations.*;
import java.util.List;

@Mapper
public interface WeiboMapper {
    /**在微博表中插入数据*/
    int insert(Weibo weibo);
    /**根据微博id查询数据*/
    Weibo selectByWeiboId(int id);
    /**查询所有微博信息*/
    List<Weibo> selectWeibo();
    /**更新微博表数据*/
    int updateById(Weibo weibo);
    /**删除微博表数据*/
    int deleteById(int id);
}
1.6.3 定义映射文件WeiboMapper.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">
<!-- 1.填写namespace,填写WeiboMapper的绝对路径 -->
<mapper namespace="cn.qiang._04mybatis.mapper.WeiboMapper">

    <!--在微博表中插入数据-->
    <insert id="insert">
        INSERT INTO weibo
        VALUES (NULL, #{content}, #{created}, #{userId})
    </insert>

    <!--根据微博id查询数据-->
    <select id="selectByWeiboId" resultType="cn.tedu._04mybatis.pojo.Weibo">
        SELECT *
        FROM weibo
        WHERE id = #{id}
    </select>

    <!--查询所有微博信息-->
    <select id="selectWeibo" resultType="cn.tedu._04mybatis.pojo.Weibo">
        SELECT *
        FROM weibo
    </select>

    <!--更新微博表数据-->
    <update id="updateById">
        UPDATE weibo
        SET content=#{content},
            created=#{created},
            user_id=#{userId}
        WHERE id = #{id}
    </update>
    <!--删除微博表数据-->
    <delete id="deleteById">
        DELETE
        FROM weibo
        WHERE id = 2
    </delete>
</mapper>

1.6.4 Dao接口单元测试
/**自动装配*/
@Autowired
private WeiboMapper weiboMapper;

/**在微博表中插入数据-测试方法*/
@Test
void InsertWeibo(){
    Weibo weibo = new Weibo();
    weibo.setContent("今天天气真不错呀");
    weibo.setCreated(new Date());
    weibo.setUserId(1);
    weiboMapper.insert(weibo);
}

/**查询所有微博信息-测试方法*/
@Test
void selectWeiboTest(){
    System.out.println(weiboMapper.selectWeibo());
}

/**根据微博id查询数据*/
@Test
void selectByWeiboIdTest(){
    System.out.println(weiboMapper.selectByWeiboId(2));
}

/**更新微博表数据-测试*/
@Test
void updateById(){
    Weibo weibo = new Weibo();
    weibo.setId(2);
    weibo.setContent("人生得意须尽欢");
    weibo.setCreated(new Date());
    weibo.setUserId(2);

    System.out.println(weiboMapper.updateById(weibo));
}

/**删除微博表数据-测试*/
@Test
void deleteByIdTest(){
    System.out.println(weiboMapper.deleteById(2));
}

1.7  动态SQL语句

1.7.1 Dao接口设计

CommentMapper

/**1.第一种批量删除: 传递Integer的数组*/
int deleteByIds1(Integer[] ids);
/**2.第二种批量删除:传递集合参数*/
int deleteByIds3(List<Integer> ids);
1.7.2 定义映射文件UserMapper.xml
<!-- 批量删除-数组格式:
    collection用来设置遍历对象的类型,
    item设置遍历出每一个变量的名称
    separator设置分隔符
    注意:注释一定要放在delete标签的外面,不能放在里面,放在里面会被当做sql语句执行!
-->
<delete id="deleteByIds1">
    DELETE FROM comment WHERE id IN(
    <foreach collection="array" item="id" separator=",">
        #{id}
    </foreach>
    )
</delete>

<!-- 集合传参,需要把collection改为 list -->
<delete id="deleteByIds2">
    DELETE FROM comment WHERE id IN(
    <foreach collection="list" item="id" separator=",">
        #{id}
    </foreach>
    )
</delete>
1.7.3 Dao接口单元测
/**1.第一种批量删除: 传递Integer的数组-测试*/
@Test
void delete1(){
    // 测试数组方式删除
    Integer[] ids = {2, 8};
    commentMapper.deleteByIds1(ids);
}

/**2.第二种批量删除:传递集合参数-测试*/
@Test
void delete3(){
    // 测试集合方式删除
    ArrayList<Integer> ids = new ArrayList<>();
    ids.add(18);
    ids.add(20);
    ids.add(22);
    commentMapper.deleteByIds2(ids);
}
1.7.4 动态修改数据

说明

如果表中字段很多,但是只改部分字段数据,比如只修改部分字段的值,不修改其他字段的值,如 果使用对象作为参数则会将其他字段的值也修改为null,如果使用传参方式解决,参数过多也会很 麻烦,所以可以使用动态修改。

实现

使用xml中的 <set></set>和 <if></if>标签组合

语法示例:

<update id="dynamicUpdate">
    UPDATE product
    <set>
        <if test="title!=null">title=#{title},</if>
        <if test="price!=null">price=#{price},</if>
        <if test="num!=null">num=#{num}</if>
    </set>
    WHERE id=#{id};
</update>
1.7.5 Dao接口设计

CommentMapper

/**动态修改数据*/
int dynamicUpdate(Comment comment);
1.7.6 定义映射文件UserMapper.xml
<!-- 动态修改-->
<update id="dynamicUpdate">
    UPDATE comment
    <set>
        <if test="content!=null">content=#{content},</if>
        <if test="created!=null">created=#{created},</if>
        <if test="userId!=null">user_id=#{userId},</if>
        <if test="weiboId!=null">weibo_id=#{weiboId}</if>
    </set>
    WHERE id=#{id};
</update>
1.7.7 Dao接口单元测试
/**动态修改数据-测试*/
@Test
void dynamicUpdateTest(){
    Comment comment = new Comment();
    comment.setId(27);
    comment.setContent("莫使金樽空对月");
    comment.setUserId(666);
    commentMapper.dynamicUpdate(comment);
}

1.8 SQL语句重用

1.8.1 说明

SQL语句重用是指在数据库应用程序中,多次执行相同或类似的SQL语句时,通过重用这些语句来提高 性能,减少系统消耗的资源。

1.8.2 实现

使用<sql></sql>和<include></include>标签组合

<sql></sql>标签中存放重复的SQL语句,使用<include></include>标签获取重复的SQL

1.8.3 示例

在三种动态删除的SQL语句中,都有重复的SQL语句: DELETE FROM comment WHERE id IN ,可以将 重复的语句抽取出来,来简化SQL。

1. mappers.CommentMapper.xml 将删除语句重复的SQL抽取出来

<!-- 1.重复SQL抽取-sql标签 -->
<sql id="deleteSql">
    DELETE FROM comment WHERE id in
</sql>

<delete id="deleteByIds1">
    <!--2.通过include标签复用-include标签-->
    <include refid="deleteSql"></include>(
    <foreach collection="array" item="id" separator=",">
        #{id}
    </foreach>
    )
</delete>

<delete id="deleteByIds2">
    <!--2.通过include标签复用-include标签-->
    <include refid="deleteSql"></include>(
    <foreach collection="list" item="id" separator=",">
        #{id}
    </foreach>
    )
</delete>

2. 执行对应的测试用例测试

1.9 多表联查

1.9.1 多表联查
  • 展示内容
用户昵称: 微博内容
花千骨说:今天天气不错挺风和日丽的
  • 查询内容

        微博id、微博内容、用户昵

  • 实现

1. mapper.WeiboMapper

// 首页微博列表数据
List<WeiboIndexVO> selectIndex();

2. mappers.WeiboMapper.xml


<select id="selectIndex"
resultType="cn.qiang.weibo.pojo.vo.WeiboIndexVO">
    SELECT w.id, w.content, u.nickname
    FROM weibo w JOIN user u ON w.user_id=u.id;
</select>

3. pojo.vo.WeiboIndexVO

public class WeiboIndexVO {
    // 显示微博的id content , 再显示一个nickname
    private Integer id;
    private String content;
    private String nickname;
}

4. 测试方法

@Test
void weiboIndexTest(){
    System.out.println(weiboMapper.selectIndex());
}

2. 事务管理 

        MyBatis支持两种事务管理模式:自动提交和手动控制。在开启手动控制的情况下,开发者可通过SqlSession的commit()rollback()方法管理事务边界。

3. 缓存机制

  • 一级缓存(本地缓存):在同一SqlSession生命周期内,对于相同的查询请求,MyBatis会优先从缓存中获取数据,减少不必要的数据库访问。
  • 二级缓存(全局缓存):跨越SqlSession的全局缓存,需在Mapper XML中明确开启,适合读多写少且数据变化不频繁的场景。二级缓存支持自定义缓存插件,比如Ehcache、Redis等。

三、MyBatis与Spring集成

1. 整合Spring Boot 

通过引入相关依赖和配置,将MyBatis无缝整合到Spring Boot项目中,利用Spring的依赖注入和事务管理能力,简化配置和增强整体架构的协调性。

2. MyBatis-Spring模块 

MyBatis-Spring模块提供了SqlSessionTemplate和MapperFactoryBean等组件,使得MyBatis可以更好地配合Spring容器进行事务管理和Mapper接口注入。

3. MyBatis与Spring Data JPA比较 

虽然Spring Data JPA提供了更为便捷的repository接口,但对于复杂查询和个性化需求,MyBatis的灵活性和可控性优势显著。

四、MyBatis最佳实践与性能优化

1. 合理设计Mapper接口和映射文件 

遵循单一职责原则,避免在一个Mapper接口中堆积过多SQL操作,保证映射文件结构清晰,提高代码可读性和可维护性。

2.SQL优化与缓存策略调整 

结合业务特点,对SQL语句进行优化,合理利用MyBatis的一级缓存和二级缓存,降低数据库压力,提升系统性能。

3.日志与调试 

配置合适的日志级别和日志框架(如Log4j、SLF4J),有助于在开发阶段快速定位问题,监控SQL执行情况和性能瓶颈。

结语

MyBatis作为一款优秀的Java持久层框架,它的广泛应用得益于其简单直观的API设计、丰富的SQL定制能力以及与主流Java生态的深度融合。通过深入理解和掌握MyBatis的各项特性,我们可以在实际开发过程中更加游刃有余地应对各种复杂的数据库操作需求,构建出高效稳定的持久层解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1437881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

肯尼斯·里科《C和指针》第12章 使用结构和指针(2)双链表

12.3 双链表 单链表的替代方案就是双链表。在一个双链表中&#xff0c;每个节点都包含两个指针——指向前一个节点的指针和指向后一个节点的指针。这可以使我们以任何方向遍历双链表&#xff0c;甚至可以随意在双链表中访问。下面的图展示了一个双链表。 下面是节点类型的声明&…

运维备忘录』之 TAR 命令详解

运维人员不仅要熟悉操作系统、服务器、网络等只是&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

go语言每日一练——链表篇(六)

传送门 牛客面试必刷101题—— 判断链表中是否有环 牛客面试必刷101题—— 链表中环的入口结点 题目及解析 题目一 代码 package mainimport . "nc_tools"/** type ListNode struct{* Val int* Next *ListNode* }*//**** param head ListNode类* return bool…

java日志框架总结(五、logback日志框架)

一、logback概述 Logback是由log4j创始人设计的又一个开源日志组件。 Logback当前分成三个模块&#xff1a; 1、logback-core, 2、logback- classic 3、logback-access。 1&#xff09;logback-core是其它两个模块的基础模块。 2&#xff09;logback-…

MySQL之建表操作

华子目录 表操作创建表数据类型文本类型数值类型日期/时间类型Bit数据类型常见数据类型 MySQL存储引擎创建表的三个操作创建表时指定存储引擎&#xff0c;字符集&#xff0c;校对规则&#xff0c;行格式 查看表显示数据库中所有表显示数据库中表的信息&#xff08;表结构&#…

flutter监听app进入前后台状态的实现

在开发app的过程中&#xff0c;我们经常需要根据app的前后台的状态&#xff0c;做一些事情&#xff0c;那么我们在flutter中是如何实现这一监听的&#xff1f; flutter给我们提供了WidgetsBindingObserver来进行一些状态的判断&#xff0c;但是判断前后台的状态只是该API种其中…

红队打靶练习:PHOTOGRAPHER: 1

目录 信息收集 1、arp 2、nmap 3、nikto 目录扫描 1、gobuster 2、dirsearch WEB 信息收集 enum4linux smbclient 8000端口 CMS利用 信息收集 文件上传漏洞利用 提权 信息收集 get user.txt get flag 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# a…

C#中实现串口通讯(使用SerialPort类)

仅作自己学习使用 1 准备部份 需要两个调试软件commix和Virtual Serial Port Driver&#xff0c;分别用于监视串口和创造虚拟串口。 第一个软件是这样的&#xff1a; 资源在这里&#xff1a;免费下载&#xff1a;Commix 也可以前往官网下载&#xff1a;Bwsensing— Attitude…

苹果macbook电脑删除数据恢复该怎么做?Mac电脑误删文件的恢复方法

苹果电脑删除数据恢复该怎么做&#xff1f;Mac电脑误删文件的恢复方法 如何在Mac上恢复误删除的文件&#xff1f;在日常使用Mac电脑时&#xff0c;无论是工作还是娱乐&#xff0c;我们都会创建和处理大量的文件。然而&#xff0c;有时候可能会不小心删除一些重要的文件&#x…

【GPT】一个高效使用excel获得结果的案例

问:请介绍通过规划求解&#xff0c;求出以最低成本购买固定数量礼品的方法。 ChatGPT: 通过规划求解方法&#xff0c;可以确定以最低成本购买固定数量礼品的方法。以下是使用规划求解进行最低成本购买礼品的一般步骤。 1.定义目标: 明确目标是以最低成本购买固定数量的礼品。…

哪个牌子的游泳耳机质量好又耐用?性价比高的游泳耳机品牌排行榜

如今&#xff0c;越来越多的人开始注重运动健身&#xff0c;并在运动时习惯享受音乐的陪伴。市场上的运动耳机种类繁多&#xff0c;以蓝牙耳机为主流。然而&#xff0c;在一些特定的运动项目&#xff0c;尤其是游泳&#xff0c;将手机放在附近并不方便。因此&#xff0c;如果在…

SpringMVC原理(设计原理+启动原理+工作原理)

文章目录 前言正文一、设计原理1.1 servlet生命周期简述1.2 设计原理小结 二、启动原理2.1 AbstractHandlerMethodMapping 初始化 --RequestMapping注解解析2.2 DispatcherServlet 的初始化2.3 DispatcherServlet#initHandlerMappings(...) 初始化示例说明 三、工作原理 前言 …

2023年12月CCF-GESP编程能力等级认证C++编程一级真题解析

一、单选题(共15题,共30分) 第1题 以下C++不可以作为变量的名称的是( )。 A:CCF GESP B:ccfGESP C:CCFgesp D:CCF_GESP 答案:A 第2题 C++表达式 10 - 3 * (2 + 1) % 10 的值是( )。 A:0 B:1 C:2 D:3 答案:B 第3题 假设现在是上午十点,求出N小时(正整数…

「 CISSP学习笔记 」08. 安全运营

该知识领域涉及如下考点&#xff0c;具体内容分布于如下各个子章节&#xff1a; 理解并遵守调查执行记录和监控活动执行配置管理 (CM)&#xff08;例如&#xff0c;预配、基线、自动化&#xff09;应用基本的安全操作概念应用资源保护执行事故管理执行和维护检测和预防措施实施…

基于微信小程序校园浴室预约系统设计与实现(php+mysql后台)

博主介绍&#xff1a;黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者&#xff0c;CSDN博客专家&#xff0c;在线教育专家&#xff0c;CSDN钻石讲师&#xff1b;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程&#xff…

分析伦敦银报价总失败?你试试这样

做伦敦银交易的投资者要先对伦敦银报价进行分析&#xff0c;但是有些投资者反映自己分析伦敦银报价总是失败&#xff0c;抓不住市场价格的变化趋势&#xff0c;为什么会这样呢&#xff1f;我们可以从以下这两个方面来考虑。 转变分析工具。为什么分析伦敦银报价总失败&#xff…

重生奇迹mu仙踪林npc

工匠尤达 NPC工匠尤达位于仙踪林的坐标为(87, 134)&#xff0c;他可以给玩家制作装备和强化装备。 精灵安吉拉 NPC精灵安吉拉位于仙踪林的坐标为(29, 196)&#xff0c;她可以给玩家提供补血、补魔服务&#xff0c;同时也能提供提高属性点数的服务。 仓库使者塞维特 NPC仓库…

相机图像质量研究(6)常见问题总结:光学结构对成像的影响--对焦距离

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

JetpackCompose中的Dialog、AlertDialog

跟View体系一样&#xff0c;Compose中也用Dialog做提示框的。既然有这个API&#xff0c;那我们还是得卷起来熟悉下使用流程及方法。 Dialog 其构造函数如下&#xff1a; Composable fun Dialog(onDismissRequest: () -> Unit,properties: DialogProperties DialogProper…

机器学习复习(5)——激活函数

目录 激活函数分类 区别与优缺点 饱和激活函数 非饱和激活函数 综合考虑 Sigmoid激活函数 Tanh激活函数 ReLU激活函数 Leaky Relu激活函数 Swish激活函数 激活函数分类 激活函数可以分为两大类 &#xff1a; 饱和激活函数&#xff1a;sigmoid、tanh非饱和激活函数:…