当前位置: 首页 > news >正文

MyBatis:开源、轻量级的数据持久化框架

什么是Mybatis

MyBatis是什么 - Mybatis教程 - 菜鸟教程:

        MyBatis 是一个开源、轻量级的数据持久化框架,是 JDBC 和 Hibernate 的替代方案。MyBatis 内部封装了 JDBC,简化了加载驱动、创建连接、创建 statement 等繁杂的过程,开发者只需要关注 SQL 语句本身。

        MyBatis 支持定制化 SQL、存储过程以及高级映射,可以在实体类和 SQL 语句之间建立映射关系,是一种半自动化的 ORM 实现。其封装性低于 Hibernate,但性能优秀、小巧、简单易学、应用广泛。

        MyBatis是一个优秀的半自动化持久层框架,简化了数据的操作,同时又保留了对SQL的高度自定义,兼容了灵活性和易用性,便于我们的开发。

什么是ORM

        ORM(Object Relational Mapping,对象关系映射)是一种编程技术,用于在关系型数据库和面向对象编程语言之间建立桥梁,通过自动化的数据转换机制,实现数据库记录与程序对象的双向映射。

        我们的项目中可能会存在大量的CRUD的重复性的SQL,如果每个都需要自己写的话会非常浪费时间且意义不大。通过采用ORM技术。自动生成基础的CRUD SQL,可以减少大量重复性代码。ORM还实现了程序对象与数据库对象的数据映射,消除了因为关系模型和对象模型产生的结构化问题。

常见的ORM框架对比

框架

MyBatis

Hibernate

JPA (规范)

Django ORM

控制级别

半自动(手动SQL)

全自动

接口规范

全自动

查询方式

XML/注解SQL

HQL/Criteria

JPQL

ORM API

性能优化

高(直接控SQL)

中(二级缓存)

依赖实现

学习曲线

中等

中等

典型应用

电商/金融系统

企业级后台

Java EE 系统

Python Web 应用


MyBatis的核心对象

  • SqlSessionFactoryBuilder:解析配置,创建SqlSessionFactory;临时对象,构建完Factory后销毁。

  • SqlSessionFactory:生产SqlSession的工程;单例模式,随着启动创建,关闭时销毁。

  • SqlSession:会话对象,执行CRUD操作、事务控制、获取Mapper接口。

  • Executor:执行SQL语句的核心处理器。

    • Executor.query 执行流程:检查一级缓存 - 未命中则查询数据库 - 通过StatementHandler执行SQL - 通过ResultSetHandler处理结果。


MyBatis的核心配置

        MyBatis的核心配置文件由两部分组成,分别是全局配置文件 mybatis-config.xml 喝 Mapper 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>
    <!-- ===================== 1. 全局属性配置 ===================== -->
    <!-- 加载外部属性文件,优先级:property标签 > resource属性 > 系统属性 -->
    <properties resource="jdbc.properties">
        <!-- 可在此覆盖外部文件的属性 -->
        <property name="jdbc.username" value="root"/>
    </properties>

    <!-- ===================== 2. 全局设置 ===================== -->
    <settings>
        <!-- 开启自动驼峰命名映射(下划线转驼峰) -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        
        <!-- 启用二级缓存(默认true,建议显式声明) -->
        <setting name="cacheEnabled" value="true"/>
        
        <!-- 配置JDBC的NULL值处理(Oracle需设为NULL) -->
        <setting name="jdbcTypeForNull" value="NULL"/>
        
        <!-- 延迟加载的触发方法(默认equals,clone,hashCode,toString) -->
        <setting name="lazyLoadTriggerMethods" value=""/>
        
        <!-- 日志实现(可选SLF4J | LOG4J | LOG4J2 | JDK_LOGGING等) -->
        <setting name="logImpl" value="SLF4J"/>
    </settings>

    <!-- ===================== 3. 类型别名 ===================== -->
    <typeAliases>
        <!-- 为单个类定义别名 -->
        <typeAlias type="com.example.model.User" alias="User"/>
        
        <!-- 扫描包,自动将类名首字母小写作为别名 -->
        <package name="com.example.model"/>
    </typeAliases>

    <!-- ===================== 4. 类型处理器 ===================== -->
    <typeHandlers>
        <!-- 自定义枚举处理器 -->
        <typeHandler handler="com.example.handler.EnumTypeHandler"
                     javaType="com.example.enums.StatusEnum"/>
        
        <!-- 注册包下的所有处理器 -->
        <package name="com.example.handler"/>
    </typeHandlers>

    <!-- ===================== 5. 插件配置 ===================== -->
    <plugins>
        <!-- MyBatis分页插件PageHelper -->
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <property name="helperDialect" value="mysql"/>
            <property name="reasonable" value="true"/>
        </plugin>
        
        <!-- SQL执行时间统计插件 -->
        <plugin interceptor="com.example.plugin.SqlCostInterceptor"/>
    </plugins>

    <!-- ===================== 6. 数据库环境配置 ===================== -->
    <!-- 默认使用环境ID -->
    <environments default="development">
        <!-- 开发环境 -->
        <environment id="development">
            <!-- 事务管理器类型:JDBC(支持事务)或MANAGED(容器管理) -->
            <transactionManager type="JDBC"/>
            
            <!-- 数据源类型:POOLED(连接池)、UNPOOLED、JNDI -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
                <!-- 连接池配置 -->
                <property name="poolMaximumActiveConnections" value="20"/>
                <property name="poolMaximumIdleConnections" value="5"/>
            </dataSource>
        </environment>

        <!-- 生产环境(多环境示例) -->
        <environment id="production">
            <transactionManager type="JDBC"/>
            <dataSource type="JNDI">
                <property name="initial_context" value="java:comp/env"/>
                <property name="data_source" value="jdbc/ProductionDB"/>
            </dataSource>
        </environment>
    </environments>

    <!-- ===================== 7. 映射器配置 ===================== -->
    <mappers>
        <!-- 指定XML映射文件 -->
        <mapper resource="mapper/UserMapper.xml"/>
        
        <!-- 指定Mapper接口类(需与XML同名同包) -->
        <mapper class="com.example.mapper.OrderMapper"/>
        
        <!-- 包扫描方式(推荐) -->
        <package name="com.example.mapper"/>
    </mappers>
    
</configuration>

MyBatis的两种使用方式

一、XML文件配置

流程如下

  1. 通过在resource下面创建mapper包用于存储Mapper.xml映射文件。

  2. 在Mapper接口中定义需要的方法。

  3. 在XML映射文件中配置SQL语句。

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">
<mapper namespace="com.example.mapper.UserMapper">

  <!-- 结果映射(解决字段名不一致问题) -->
  <resultMap id="userResultMap" type="User">
    <id property="id" column="user_id"/>
    <result property="name" column="user_name"/>
    <result property="email" column="user_email"/>
  </resultMap>

  <!-- 基础查询 -->
  <select id="selectUserById" resultMap="userResultMap">
    SELECT * FROM users WHERE user_id = #{id}
  </select>

  <!-- 动态SQL -->
  <select id="selectUsersByCondition" resultMap="userResultMap">
    SELECT * FROM users
    <where>
      <if test="name != null">
        AND user_name LIKE CONCAT('%', #{name}, '%')
      </if>
      <if test="minAge != null">
        AND age >= #{minAge}
      </if>
      <choose>
        <when test="role == 'admin'">
          AND is_admin = 1
        </when>
        <otherwise>
          AND status = 1
        </otherwise>
      </choose>
    </where>
    ORDER BY create_time DESC
  </select>

  <!-- 批量插入 -->
  <insert id="batchInsert" parameterType="list">
    INSERT INTO users (user_name, email)
    VALUES 
    <foreach item="user" collection="list" separator=",">
      (#{user.name}, #{user.email})
    </foreach>
  </insert>

</mapper>

二、注解方式配置

        该方法比较适用于SQL语句比较简单的时候,例如基础的CRUD。通过注解配置的方式可以简化开发。

注解映射示例

public interface UserMapper {

  @Select("SELECT * FROM users WHERE user_id = #{id}")
  @Results(id = "userResult", value = {
    @Result(property = "id", column = "user_id", id = true),
    @Result(property = "name", column = "user_name"),
    @Result(property = "email", column = "user_email")
  })
  User selectUserById(Long id);

  @SelectProvider(type = UserSqlBuilder.class, method = "buildSelectByCondition")
  List<User> selectUsersByCondition(Map<String, Object> params);

  @Insert("INSERT INTO users (user_name, email) VALUES (#{name}, #{email})")
  @Options(useGeneratedKeys = true, keyProperty = "id")
  int insertUser(User user);

  @UpdateProvider(type = UserSqlBuilder.class, method = "buildUpdateSql")
  int updateUser(User user);

  // 动态SQL构建器
  class UserSqlBuilder {
    public String buildSelectByCondition(Map<String, Object> params) {
      return new SQL() {{
        SELECT("*");
        FROM("users");
        if (params.get("name") != null) {
          WHERE("user_name LIKE CONCAT('%', #{name}, '%')");
        }
        if (params.get("minAge") != null) {
          WHERE("age >= #{minAge}");
        }
        ORDER_BY("create_time DESC");
      }}.toString();
    }
  }
}

两种方法的对比

  • XML的方式更适合复杂的SQL语句编写;对于简单的SQL语句,我们还是建议使用注解的方式进行编写。

  • XML将SQL进行统一管理,而注解的方式将SQL分散在了Java代码中。

  • XML支持动态SQL,而注解方式需要通过Provider类或拼接字符串实现动态SQL。

        建议根据使用场景,混合使用XML和注解方式。

http://www.dtcms.com/a/109445.html

相关文章:

  • 游戏引擎学习第201天
  • Muduo网络库实现 [九] - EventLoopThread模块
  • 康谋分享 | 仿真驱动、数据自造:巧用合成数据重构智能座舱
  • 去中心化交易所(DEX)
  • Unity3D开发AI桌面精灵/宠物系列 【三】 语音识别 ASR 技术、语音转文本多平台 - 支持科大讯飞、百度等 C# 开发
  • 【GCC警告报错4】warning: format not a string literal and no format arguments
  • 从扩展黎曼泽塔函数构造物质和时空的结构-13
  • 练习题:120
  • 【Linux学习笔记】开发工具git和gbd和cgbd的介绍和使用
  • PADS 9.5【附破解文件+安装教程】中文激活版下载
  • IP分片攻击实战模拟
  • 蓝桥杯真题——传送阵
  • xsync脚本是一个基于rsync的工具
  • LN2220 2A 高效率升压 DC/DC 电压调整器
  • 前端面试题(二):vue2中v-if和v-show的区别
  • 使用python完成手写数字识别
  • 列表某个字段由多个值组成,使用id匹配展示
  • Angular 项目 PDF 批注插件库在线版 API 示例教程
  • 儿童语义认知功能磁共振成像研究的元分析
  • Python+Playwright自动化测试-1-环境准备与搭建
  • 【爬虫开发】爬虫开发从0到1全知识教程第14篇:scrapy爬虫框架,介绍【附代码文档】
  • [原创](Modern C++)现代C++的关键性概念: 什么是左值?
  • 运维之 Centos7 防火墙(CentOS 7 Firewall for Operations and Maintenance)
  • 17、Swift框架微调实战(2)-QWQ-32B LORA微调cot数据集
  • 加密解密工具箱 - 专业的在线加密解密工具
  • 19-元素显示模式及浮动(CSS3)
  • 3D模型给可视化大屏带来了哪些创新,都涉及到哪些技术栈。
  • c#递规获取指定目录下的所有文件
  • C++Cherno 学习笔记day15 [57]-[60] 静态数组、函数指针、lambda、using namespace std
  • DataX实战教程