1.什么是ORM框架

ORM(Object-Relational Mapping,面向对象关系映射)是一种技术,用于将面向对象编程中的对象(如类)与关系性数据库中的表相对应,从而通过操作对象来间接操作数据库对象,而无需直接编写SQL语句。

  1. ORM 框架的核心概念

    • 对象与表映射: 类对应数据库表,类的属性对应表中的字段,类的实例对应表中的一行记录。
    • 关系映射: 对象之间的关系(如一对一、一对多、多对多)对应数据库表之间的关系(如外键或关联表)。
    • 透明操作: 开发者只需编写面向对象的代码,ORM 框架会自动将其转换为相应的 SQL 操作。
  2. ORM 框架的作用

    • 简化开发:减少直接与 SQL 和数据库交互的代码,提高开发效率。
    • 降低耦合:数据库操作和数据库结构解耦,易于代码维护和迁移
    • 跨数据库支持:ORM通常支持多种数据库类型,通过配置即可切换
  3. ORM的核心功能

    • (1)基本的CRUD

      • 支持增删改查对象化操作,例如:
        创建对象,自动插入数据库。
        修改对象属性,自动更新到数据库。
        删除对象,自动执行对应的 SQL DELETE 操作。
    • (2)查询功能

      • 提供面向对象的查询方式,如 HQL(Hibernate Query Language)或 Criteria API
      • 支持动态查询构造,也可以直接执行原生 SQL
    • (3)关系映射

      • 支持处理复杂的对象关系:
        一对一(One-to-One)
        一对多(One-to-Many)
        多对多(Many-to-Many)
    • (4)事务管理

      • 支持数据库事务操作,确保数据操作的原子性和一致性
    • (5)延迟加载

      • 只有在需要时才从数据库加载关联数据,优化性能。

2.什么是Mybatis

MyBatis 是一个优秀的 持久层框架,它通过 SQL 映射文件或注解 来将 Java 对象与数据库中的数据记录进行绑定,从而简化了对数据库的操作。
与传统的 ORM 框架(如 Hibernate)不同,MyBatis 不会完全封装 SQL,它强调对 SQL 的直接使用,同时提供灵活的动态 SQL 构造和对象映射能力,兼顾了效率与易用性。

Mybatis核心特点

  1. 直接操作SQL

    • 开发者需要手写 SQL。
    • 提供对复杂 SQL 的完全控制
  2. 灵活的配置

    • 支持 XML 和注解配置 SQL。
    • 动态生成 SQL,适应多变的业务需求。
  3. 对象关系映射

    • 将数据库结果集映射为 Java 对象。
    • 提供简单的结果映射或高级的复杂关系映射。
  4. 支持主流数据库

    • 如 MySQL、PostgreSQL、Oracle、SQL Server 等。
  5. 轻量级框架

    • 不依赖其他大型框架,易于集成

Mybatis的核心组件

  1. SQL 映射文件 (XML)

    • 定义SQL语句和对象映射规则
  2. Mapper接口:

    • 绑定 SQL 映射文件的方法
    • 通过接口直接调用 SQL
  3. MyBatis配置文件(mybatis-config.xml)

    • 配置全局信息,如数据库连接、插件、类型别名等。
  4. 会话管理器 (SqlSessionFactory 和 SqlSession):

    • 用于管理数据库会话,执行 SQL 操作。

MyBatis核心功能

  1. 提供CRUD

    • 提供简单的增删改查操作,通过 SQL 完成数据操作。
  2. 动态SQL

    • 使用 XML 中的标签(如 <if>、<choose>等)或注解动态生成 SQL。
  3. 结果映射

    • 支持单表查询结果的映射到 Java 对象,也支持复杂对象关系的映射。
  4. 插件扩展

    • 提供灵活的拦截器机制,可扩展功能(如分页、审计等)。

MyBatis工作流程

  1. 初始化:加载全局配置文件和映射文件,创建SqlSessionFactory。
  2. 获取会话:通过SqlSessionFactory获取SqlSession
  3. 执行操作:使用SqlSession调用SQL,进行增删改查
  4. 返回结果:返回查询结果或者受影响的行数
  5. 关闭会话,释放资源

Mybatis的优点

  1. 小巧,学习成本低,会写SQL就可以上手
  2. 大部份工作只需要专注于SQL语句
  3. 方便维护管理,SQL代码可以分离出来
  4. 支持动态SQL语句(条件判断,范围判断)
  5. 支持对象与ORM字段的关系映射

Mybatis的核心组件

SqlSessionFactory
  • 作用

    • 是 MyBatis 的核心接口之一,用于创建 SqlSession 对象。
    • 它是线程安全的,通常被设计为单例模式,应用程序启动时只需要初始化一次
  • 工作原理

    • 根据 MyBatis 的配置文件(mybatis-config.xml)构建。
    • 负责加载配置信息,解析映射文件(Mapper)并初始化数据库连接池
    SqlSession
  • 作用

    • 是 MyBatis 与数据库交互的直接接口,用于执行 SQL 操作(如查询、插入、更新、删除)
    • 线程不安全,通常在每次数据库操作时创建并使用,完成后关闭。
  • 常用方法

    • selectOne
    • selectList
    • insert/update/delete
    Mapper映射器
  • 作用:映射文件(XML)或者接口,定义了 SQL 语句与 Java 方法的对应关系。
  • xml映射文件:

    • 让在Resource目录里,通常命名为xxxMapper.xml
    • 包含具体的 SQL 语句以及与 Java 对象的映射关系
    Mapper 接口
  • 作用:用来定义Java方法,与XML文件或者注解中的SQL语句绑定
MyBatis 配置文件
  • 作用:定义全局配置,包括数据库连接信息,用户名,密码,事务管理,映射文件路径
Executor执行器
  • 作用:

    • MyBatis 的底层执行组件,负责执行 SQL 语句并返回结果
    • 根据查询请求,调用数据库连接,处理参数映射和结果映射
  • 类型

    • singleExecutor: 每次执行都会打开和关闭连接。
    • reuseExecutor: 复用相同的 Statement 对象,提高性能。
    • batchExecutor: 执行批量操作,常用于批量插入或更新。
    StatementHandler
  • 作用:

    • 负责将 SQL 转换成数据库可执行的 Statement 对象。
    • 提供 SQL 的预编译、参数设置、执行结果处理等功能。
  • 工作流程

    • 接收Mapper中定义的SQL
    • 根据参数动态生成SQL语句
    • 使用JDBC执行SQL,并获取结果
    ParameterHandler
  • 作用:

    • 用于处理 SQL 语句的输入参数,将参数传递到预编译的 SQL 中
  • 示例:

    • 将 #{id} 替换成具体的值,比如 1
    ResultSetHandler
  • 作用:

    • 负责将 SQL 查询结果集(ResultSet)映射到 Java 对象或集合中
  • 映射方式:

    • 自动映射:通过列名与 Java 对象属性名匹配
    • 手动映射:通过 resultMap 明确映射关系。
<resultMap id="userResultMap" type="User">
    <result property="id" column="id" />
    <result property="name" column="name" />
    <result property="email" column="email" />
</resultMap>
TypeHandler(类型处理器)
  • 作用:

    • 用于处理 Java 数据类型与数据库字段类型之间的转换
  • 默认处理器:

    • MyBatis 内置了常用的类型处理器,如 StringTypeHandler、IntegerTypeHandler
  • 自定义处理器

    • Java String(JSON序列化)-> MySQL JSON类型
    Cache(缓存)
  • 作用:

    • 提升查询性能,减少对数据库的直接访问。
  • 类型

    • 一级缓存(本地缓存):SqlSession 级别,默认开启,同一个 SqlSession 内重复查询时缓存结果
    • 二级缓存(全局缓存):二级缓存(全局缓存):Mapper 级别,多个 SqlSession 可共享。

#{}${}的区别

#{}${} 都用于动态传参,但它们有不同的处理机制和适用场景

  1. 基本区别
特性 #{}(占位符处理) ${}(字符串替换处理)
解析方式 使用 预编译参数占位符 直接将值拼接到 SQL 中
安全性 自动进行 SQL 注入防护 无防护,可能引发 SQL 注入问题
SQL 表现 生成 ? 占位符,动态绑定参数 值直接拼接到 SQL 语句
使用条件 传递参数值,如条件、字段值等 动态拼接字段名、表名或其他 SQL 结构
  1. 使用示例

#{}示例:

<select id="getUserById" parameterType="int" resultType="User">
    SELECT * FROM users WHERE id = #{id};
</select>

实际执行 SQL:SELECT * FROM users WHERE id = ?
(MyBatis 使用 JDBC 将 1 绑定到 ? 中,防止 SQL 注入)
优点:安全、高效,适用于动态值(如查询条件、插入/更新字段值等)。

${}示例:

<select id="getUsersByTable" parameterType="string" resultType="User">
    SELECT * FROM ${tableName} WHERE id = #{id};
</select>

实际执行 SQL:SELECT * FROM users WHERE id = ?
优点:适用于动态结构(如表名、列名),但容易引发 SQL 注入,必须确保输入值可信。

  1. 安全性

#{} 的安全性

  • MyBatis 自动处理参数的转义,防止恶意注入

${} 的安全性

  • 如果用户输入的值包含恶意 SQL 片段(如 users; DROP TABLE users;),可能引发安全问题
<select id="getUserByName" parameterType="string" resultType="User">
    SELECT * FROM users WHERE name = '${name}';
</select>

实际执行 SQL:SELECT * FROM users WHERE name = 'admin' OR '1'='1';
结果:查询条件被篡改,返回了所有用户数据。

  1. 性能影响

#{} 优化性能:

  • SQL 使用占位符,数据库引擎会缓存 SQL 的执行计划(Prepare Statement 缓存),提升性能。

${} 缓存差:

  • 每次执行都会重新生成完整 SQL,数据库引擎无法缓存执行计划,性能稍逊。

Mybatis里的动态标签

MyBatis 的动态标签是为了简化动态 SQL 的编写,支持根据条件动态生成 SQL 语句。它提供了一些标签来处理常见的动态场景,比如条件判断、循环、拼接等。

  1. <if> 标签:用于根据条件判断是否生成某段 SQL。
<if test="条件表达式">
    SQL语句片段
</if>
  • test 属性是条件表达式,支持 Java 的逻辑表达式
  1. <choose><when><otherwise> 标签

类似于 Java 的 switch,用于多条件选择。

<choose>
    <when test="条件1">
        SQL语句片段1
    </when>
    <when test="条件2">
        SQL语句片段2
    </when>
    <otherwise>
        默认SQL语句片段
    </otherwise>
</choose>
  • <choose> 标签中只能有一个 <when> 生效,如果没有满足条件的 <when>,则执行 <otherwise>
  1. <trim> 标签
    用于对动态SQL进行前后缀处理(如添加 AND 或去除多余的逗号)
<trim prefix="前缀" suffix="后缀" suffixOverrides="移除后缀" prefixOverrides="移除前缀">
    SQL语句片段
</trim>

例子:

<select id="getUsers" resultType="User">
    SELECT * FROM users
    <trim prefix="WHERE" prefixOverrides="AND | OR">
        <if test="name != null and name != ''">
            AND name = #{name}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </trim>
</select>
  1. <where>标签
    智能地添加 WHERE 关键字,并自动去除多余的 AND 或 OR。
<select id="getUsers" resultType="User">
    SELECT * FROM users
    <where>
        <if test="name != null and name != ''">
            name = #{name}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>
  1. <set>标签
    用于动态生成 UPDATE 语句,自动处理多余的逗号。

说明:

<set>
    SQL语句片段
</set>

示例:

<update id="updateUser">
    UPDATE users
    <set>
        <if test="name != null">
            name = #{name},
        </if>
        <if test="age != null">
            age = #{age},
        </if>
        <if test="email != null">
            email = #{email}
        </if>
    </set>
    WHERE id = #{id}
</update>

说明:

  • 自动去除最后一个逗号。
  • 如果所有子条件为空,则 <set> 标签不生成内容。
  1. <foreach> 标签
    用于循环生成 SQL 片段,常用于 IN 查询或批量操作。

语法:

<foreach collection="集合" item="变量名" index="索引" open="开始符" close="结束符" separator="分隔符">
    SQL语句片段
</foreach>

动态标签总结

标签 功能描述 常见场景
if 根据条件动态生成SQL 动态条件拼接
choose/when/otherwise 类似于 switch,从多个条件中选择一个 条件分支逻辑
trim 自定义前后缀并去除多余关键字 灵活生成复杂SQL结构
where 自动添加 WHERE 并清理多余关键字 动态查询
set 自动处理 UPDATE 中的逗号 动态更新
foreach 遍历集合生成 SQL 批量操作或动态 IN 查询

xml映射文件上的标签

全局配置标签

1.<mapper> 表示一个映射文件的根目标

  • 描述:表示一个映射文件的根标签
  • 属性:namespace 定义映射的命名空间,用于区分SQL语句
  • 示例:
<mapper namespace="com.example.UserMapper">
    <!-- 映射内容 -->
</mapper>
SQL映射标签

2.select

  • 描述:用于定义查询语句。
  • 属性:

    • id:标识方法名,唯一。
    • resultType:返回的结果类型(如 Java 对象)
    • parameterType:传入参数的类型。
<select id="getUserById" parameterType="int" resultType="User">
    SELECT * FROM users WHERE id = #{id};
</select>

3.insert

  • 描述:用于定义插入语句
  • 属性:

    • id:方法名
    • parameterType:传入参数的类型
  • 示例:
<insert id="insertUser" parameterType="User">
    INSERT INTO users (name, age, email) VALUES (#{name}, #{age}, #{email});
</insert>

4.update

  • 描述:用于定义更新语句
  • 属性:

    • id:方法名
    • parameterType:传入方法类型
  • 示例:
<update id="updateUser" parameterType="User">
    UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id};
</update>

5.delete

  • 描述:用于定义删除语句
  • 属性:

    • id:方法名
    • parameterType:传入方法类型
  • 示例:
<delete id="deleteUserById" parameterType="int">
    DELETE FROM users WHERE id = #{id};
</delete>
动态SQL标签

6.<if>
根据条件动态生成 SQL 语句。

<if test = "name != null and name != ''">
    AND name = #{name}
</if>
  1. <choose>

用于多条件选择(类似于 switch-case)。

<choose>
    <when test = "status == 1">
        status = 1
    </when>
    <when test = "status == 2">
        status = 2
    </when>
    <otherwise>
        status IN (1, 2)
    </otherwise>
</choose>
  1. <trim>

动态添加或去除前缀、后缀。

    <trim prefix = "WHERE" prefixOverrides = "AND|OR">
        <if test = "name!= null and name != ''">
            AND name = #{name}
        </if>
        <if test = "age!= null and age !=''">
            AND age = #{age}
        </if>
    </trim>
  1. <where>

智能地添加 WHERE 并去掉多余的 AND 或 OR。

    <where>
        <if test = "name != null">
            name = #{name}
        </if>
        <if test = "age != null">
            AND age = #{age}
        </if>
    <where>

10.<set>

自动处理更新语句中的多余逗号。

    <set>
        <if test = "name != null">
            name = #{name}
        </if>
        <if test = "age != null">
            age = #{age}
        </if>
    </set>

11.<foreach>

用于遍历集合生成动态SQL

<foreach collection="ids" item="id" open="(" close=")" seperator=",">
    #{id}
</foreach>
可重用标签

12.<sql>

定义可重用的 SQL 片段。

<sql id = "baseColumns">
    id, name, age, email
</sql>

引用方式:

<select id="getAllUsers" resultTyper="User">
    SELECT <include refid = "baseColumns"/> FROM users;
</selecr>
  1. <include>
    引入可重用的 SQL 片段。
### 引入可重用的 SQL 片段
<include refid = "baseColumns"/>
高级功能标签
  1. <resultMap>

resultMap 是 MyBatis 提供的强大的结果映射功能,主要用于将查询结果集映射到Java对象

  • id: 唯一标识,供查询时引用。
  • type: 映射结果的 Java 对象类型。

示例 1:简单映射

<resultMap id="userResultMap" type="com.example.MyObject">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="age" column="age"/>
</resultMap>

<select id = "getUserById" resultMap = "userResultMap">
    SELECT id, user_name, user_age FROM users WHERE id = #{id}
</select>

示例 2:嵌套对象映射

<resultMap id="orderResultMap" type = "com.example.Order">
    <id property = "id" column = "id"/>
    <result property = "totalPrice" column = "total_price"/>
    <association property = "user" javaType = "com.example.User">
        <id property = "id" column = "user_id"/>
        <result property = "name" column = "user_name"/>
    </association>
</resultMap>

<select id = "getOrderById" resultMap = "orderResultMap">
    SELECT o.id, o.total_price, u.id AS user_id, u.name AS user_name
    FROM order o
    JOIN users u ON o.user_id = u.id
    WHERE o.id = #{id} 
</select>

示例 3:集合映射

<resultMap id = "catagoryResultMap" type = "com.example.Catagory">
    <id property = "id" column = "id"/>
    <result property = "name" column = "name"/>
    <collection property = "products" ofType = "com.example.Product">
        <id property = "id" column = "product_id"/>
        <result property = "name" column = "product_name"/>
    </collection>
</resultMap>
  1. <paramemterMap>标签

<parameterMap> 用于定义 SQL 语句的输入参数映射。
注意:在现代 MyBatis 中已不推荐使用,直接使用 JavaBean 或 Map 作为参数即可。

<parameterMap id = "paramMap" type ="com.example.User">
    <parameter property="id" column="id"/>
    <parameter property="name" column="user_name"/>
</parameterMap>
  1. <selectKey>标签

<selectKey> 用于在插入语句之前或之后生成主键值,适用于主键生成策略需要查询数据库或使用序列的情况。

基本语法

<selectKey keyProperty="id" resultType="int" order="BEFORE">
    SELECT SEQ_USER.NEXTVAL FROM DUAL
</selectKey>
<insert id="insertUser" parameterType="User">
    INSERT INTO users (id, name, age) VALUES (#{id}, #{name}, #{age});
</insert>

属性

  • keyProperty:生成主键值对应的 Java 对象属性。
  • resultType:主键的类型。
  • order:主键生成顺序,BEFORE 表示在执行 SQL 前生成,AFTER 表示在执行 SQL 后生成。

示例: 自动生成主键

适用于 MySQL 数据库,利用自增主键。

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO users (name, age) VALUES (#{name}, #{age});
</insert>

使用MyBatis进行分页

  1. 数据级别的分页

在 SQL 中直接使用 LIMIT 和 OFFSET,并通过参数传递页码和页大小。

<select id = "getUser" parameterType = "int" resultType = "User">
    SELECT * FROM users
    LIMIT #{pageSize} OFFSET #{offset}
</select>

说明:

  • pageSize 每页的数量
  • pageNum 页码

int offset =(pageNum - 1)* pageSize;

  1. 使用MyBatis插件实现分页(Page-Helper)

引入第三方分页插件,比如 PageHelper,可以简化分页操作。

PageHelper 提供静态方法,通过拦截器自动修改 SQL,添加分页参数。

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

public List<User> getPagedUsers(int pageNumber, int pageSize) {
    // 开启分页
    PageHelper.startPage(pageNumber, pageSize);
    // 执行查询
    List<User> users = userMapper.getAllUsers();
    // 封装为 PageInfo 对象,包含分页信息
    PageInfo<User> pageInfo = new PageInfo<>(users);
    return pageInfo.getList();
}
  1. 自定义分页查询(推荐结合数据库查询优化)
  • 对于复杂查询场景,可以手动优化分页逻辑,比如:

    • 只查询当前页的数据,而不是全量扫描。
    • 配合索引和 WHERE 条件优化性能。

Mybatis的动态代理实现(Mapper没有实现类 却可以调用)

什么是 MyBatis 动态代理?

动态代理是 Java 提供的一种机制,允许在运行时动态生成代理对象并拦截方法调用。
在 MyBatis 中,通过动态代理机制,Mapper 接口不需要手动实现,而由 MyBatis 自动生成代理实现类。

  • Mapper接口:定义数据库操作
  • 动态代理实现:在运行时生成接口的实现类,调用方法时由 MyBatis 的内部逻辑拦截并执行 SQL。
MyBatis 动态代理的核心原理
  1. Mapper 接口:用户只需要定义接口,并添加注解或编写 XML 映射文件。
  2. 动态代理生成实现类:MyBatis 使用 JDK 动态代理(Proxy.newProxyInstance)生成接口的代理类。
  3. 方法调用拦截:方法调用被动态代理拦截,并将方法名与 SQL 映射绑定,最终执行 SQL。

核心流程:

  • sqlSession.getMapper(Class<T> type) 方法返回一个代理对象
  • 调用接口方法时,代理对象会拦截方法调用,通过 MappedStatement 解析 SQL 语句并执行数据库操作
  • 返回结果自动映射为 Java 对象。
动态代理的底层原理
  1. 生成代理对象

调用 sqlSession.getMapper(UserMapper.class) 时,MyBatis 使用 JDK 动态代理创建了一个代理对象。

Proxy.newProxyInstance(
    targetInterface.getClassLoader(),
    new Class<?>[]{targetInterface},
    new MappperProxy<>(sqlSession, targetInterface, methodCache)
);
  1. 方法拦截
  • 调用getUserById方法时,代理对象会调用MapperProxy.invoke()方法
  • MapperProxy 查找对应的 MappedStatement,解析 SQL,并执行。
  1. SQL执行
  2. MappedStatement 包含了 SQL 配置和映射规则。
  3. MyBatis 使用 Executor 执行 SQL,并将结果映射到返回的对象。

实体属性和表中字段不一致解决方案

  1. 别名:比如order_num

select order_num OrderNum

  1. 通过映射

<result property = "order_Num" column = "order_num"/>

  1. 如果是驼峰注解用自动驼峰转换

mapUnderscoreToCamelCase = true

Mybatis嵌套查询用什么标签

  1. 多对一情况 <association> 标签

SQL映射文件(XML)

<resultMap id="UserResultMap" type="User">
    <id property="id" column="user_id"/>
    <result property="name" column="name"/>
    <!-- 多对一嵌套查询 -->
    <association property="address" javaType="Address" column="address_id" select="getAddressById"/>
</resultMap>

<select id="getUserById" resultMap="UserResultMap">
    SELECT * FROM users WHERE user_id = #{id}
</select>

<select id="getAddressById" resultType="Address">
    SELECT * FROM addresses WHERE id = #{id}
</select>
  1. 一对多情况 <collection> 标签

SQL 映射文件(XML)

<resultMap id="OrderResultMap" type="Order">
    <id property="id" column="order_id"/>
    <result property="orderName" column="order_name"/>
    <!-- 一对多嵌套查询 -->
    <collection property="items" ofType="OrderItem" column="order_id" select="getOrderItemsByOrderId"/>
</resultMap>

<select id="getOrderById" resultMap="OrderResultMap">
    SELECT * FROM orders WHERE order_id = #{id}
</select>

<select id="getOrderItemsByOrderId" resultType="OrderItem">
    SELECT * FROM order_items WHERE order_id = #{id}
</select>
  1. 嵌套查询的注意事项

性能问题:

  • 嵌套查询可能引发 N+1 查询问题(每次主表查询都触发关联表的单独查询)。
  • 如果数据量大,建议优化为连接查询或批量查询。

延迟加载:

  • MyBatis 支持延迟加载,可以减少不必要的嵌套查询执行
  • 通过配置文件启用:
<setting name="lazyLoadingEnabled" value="true"/>

使用Mybatis进行模糊查询

  1. 使用 #{} 占位符
  • 特点:
    #{} 会自动对参数进行 SQL 注入防护,推荐使用。
  • 示例:
    假设有一张用户表 users,字段包括 id 和 name,需要根据 name 进行模糊查询。
<select id = "findUserByName" result = "User">
    SELECT * FROM users
    WHERE name LINKE CONCAT('%', #{name}, '%')
</select>
  • #{name}:自动替换为参数值并进行 SQL 注入防护。
  • CONCAT('%', #{name}, '%'):将输入的值拼接成 %value% 的形式,实现模糊匹配。
  1. 使用 ${} 动态 SQL 拼接
  • 特点:
    ${} 会直接将参数拼接到SQL中,不进行防护。需确保参数安全性,否则可能引发SQL注入。
  • 示例:
<select id="findUsersByNameUnsafe" resultType="User">
    SELECT * FROM users
    WHERE name LIKE '%${name}%'
</select>
  1. 使用动态标签
  • 特点:
    利用 MyBatis 的 <if><trim> 标签,动态生成模糊查询条件。
    <select id = "findUsers" resultType = "User">
        SELECT * FROM users 
        WHERE 1=1
        <if test = "name != null and name != ''">
            AND name LIKE CONCAT('%', #{name}, '%')    
        </if>
        <if test = "enmail != null and name != ''">
            AND email LIKE CONCAT('%', #{email},'%')
        </if>
    </select>
    
  1. 配合 MyBatis Plus 或插件(高级方式)

如果使用了 MyBatis Plus,可以直接利用其内置的查询条件构造器,简化模糊查询的实现。

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name", "John"); // 相当于 name LIKE '%John%'
List<User> users = userMapper.selectList(wrapper);
  1. 使用<bind>实现模糊查询
<select id="findUsersByName" resultType="User">
    <bind name="searchName" value="'%' + name + '%'" />
    SELECT * FROM users
    WHERE name LIKE #{searchName}
</select>

推荐将 bind 与 #{} 一起使用,以避免 SQL 注入风险,并确保参数的安全性

Mybatis类型转换器

全局配置

<typeHandlers>
    <typeHandler handler="com.example.typehandler.CustomTypeHandler"/>
</typeHandlers>

局部配置

<resultMap id="userResultMap" type="User">
    <result property="isActive" column="active" typeHandler="com.example.typehandler.BooleanTypeHandler"/>
</resultMap>

SqlSessionFactoryBuilder生命周期

SqlSessionFactoryBuilder作用

SqlSessionFactoryBuilder 主要负责从配置文件(通常是 mybatis-config.xml)中读取 MyBatis 的配置信息,并根据这些配置信息构建 SqlSessionFactory。这个工厂类是 MyBatis 框架启动和初始化的关键组件之一。

SqlSessionFactory 的作用

SqlSessionFactory 是 SqlSession 的工厂类,它负责创建和配置 SqlSession。一个 SqlSessionFactory 对应一个数据库连接池,通常应用程序在启动时创建一次 SqlSessionFactory 实例,然后使用它来创建多个 SqlSession 实例。

SqlSession 提供的主要功能:
  • 执行SQL:通过 SqlSession 执行查询、插入、更新、删除等 SQL 操作。
  • 获取映射器接口示例:通过 getMapper() 方法获取 Mapper 接口实例,使用这些接口来执行具体的数据库操作。
  • 管理事务:SqlSession 可以通过手动提交或回滚来管理数据库事务。

MyBatis插件运行原理

具体原理
  1. 接口拦截:MyBatis 插件通过拦截器(Interceptor)接口来拦截某些方法的调用。MyBatis 提供了多种接口类型供开发者拦截,包括 Executor、StatementHandler、ParameterHandler、ResultSetHandler 等。插件会在这些接口的实现方法上进行增强。
  2. 插件注册:在 MyBatis 配置文件中,通过 <plugins>标签来注册自定义插件。MyBatis 会在初始化时扫描并加载这些插件,并将插件应用到相应的执行流程中。
  3. 动态代理:MyBatis 使用 Java 动态代理技术(通过 java.lang.reflect.Proxy)为 Executor、StatementHandler 等接口生成代理对象,并在这些对象的方法执行前后进行插入自定义逻辑。比如,你可以在执行 SQL 前后记录日志,或者修改 SQL 语句。
  4. 拦截方法:当 MyBatis 执行 SQL 操作时,会通过插件拦截器触发自定义的方法。在插件的 intercept 方法中,可以根据需要修改 SQL、修改参数、记录日志等。

MyBatis缓存

MyBatis 提供了缓存机制来提高数据库访问的效率,减少不必要的数据库查询操作。MyBatis 缓存的工作原理是将查询结果存储在内存中,避免重复查询相同的数据。当数据在缓存中存在时,MyBatis 会直接从缓存中获取数据,而不需要再次访问数据库。

缓存的工作原理
  1. 一级缓存(Local Cache):默认启用的缓存机制,缓存是作用于一个 SqlSession 的生命周期内,属于每个会话的本地缓存。
  2. 二级缓存(Global Cache):是跨多个 SqlSession 共享的缓存,它是通过 Mapper 映射文件来共享的。二级缓存的作用范围大于一级缓存,可以共享多个会话之间的数据。
一级缓存

一级缓存是默认启用的缓存,它存在于 SqlSession 的生命周期中。也就是说,在同一个 SqlSession 内,查询的结果会被缓存。一级缓存不会跨 SqlSession 共享数据,因此,关闭 SqlSession 后,一级缓存的数据会被清空。

  • 一级缓存是 MyBatis 默认启用的,并且是基于 SqlSession 的。
  • 缓存粒度:缓存的粒度是 SQL 查询,因此同一个 SQL 查询的结果会被缓存。
  • 生命周期:一级缓存的生命周期与 SqlSession 相同。当 SqlSession 被关闭时,缓存也会被清除。
  • 使用方式:不需要任何额外配置,只要使用 SqlSession 执行查询,查询结果会被缓存。
二级缓存

二级缓存是跨 SqlSession 的缓存,它是在多个 SqlSession 之间共享的缓存。二级缓存的作用域是 Mapper 映射文件,也就是说,不同 SqlSession 使用相同 Mapper 的查询时,数据会被存储在二级缓存中。

  • 需要手动启用:二级缓存默认是关闭的,需要通过配置启用。
  • 跨 SqlSession 共享:不同的 SqlSession 可以共享相同 Mapper 中的缓存数据。
  • 缓存粒度:缓存的粒度是 Mapper,同一个 Mapper 下的查询可以共享缓存数据。
  • 配置:二级缓存需要在 mybatis-config.xml 和 Mapper 映射文件中进行配置。
  1. 启用二级缓存
<configuration>
    <!-- 启用全局二级缓存 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>
  1. 在 Mapper 文件中启用缓存
<mapper namespace="com.example.mapper.UserMapper">
    <!-- 启用缓存 -->
    <cache/>
    
    <!-- 其他 SQL 映射 -->
</mapper>
  1. 二级缓存的回收策略

LRU(最近最少使用):缓存策略是一种常用的回收策略。LRU 缓存会移除最长时间未使用的缓存数据,以保证缓存的大小在一定范围内。
IFO(先进先出):按照对象进入缓存的顺序来移除
SOFT(软引用):移除基于垃圾收集器的状态和软引用规则的对象
WEAK(弱引用):更积极地移除基于垃圾收集器和弱引用规则对象

3.什么是Hibernate

Hibernate 是一个功能强大的 Java ORM(Object-Relational Mapping)框架,它提供了一个简单的方式来将 Java 对象与数据库中的表进行映射,从而简化了数据库操作。它能够自动生成 SQL 并执行,减少了开发人员编写 SQL 的负担,同时提供了一些优化和扩展机制。

Hibernate的核心特点

  1. 自动化的数据操作:

    • Hibernate自动生成SQL语句来进行数据库操作,开发者只需要操作Java对象,不要编写原生的SQL
  2. 对象关系映射(ORM)

    • 将Java类与数据库表进行映射,属性与字段映射,提供了对象和关系型数据库之间的桥梁
  3. 持久化管理

    • Hibernate提供了持久化机制,将Java对象的状态同步到数据库表中
  4. 透明持久化

    • 无需显式得处理对象和数据库的转换,Hibernate自动处理对象的持久化操作
  5. 查询语言

    • Hibernate提供了Hibernate Query Language(HQL),一种类似于 SQL 的面向对象查询语言
    • 支持 Criteria API 和 SQL 查询,可以灵活地进行数据库查询
  6. 缓存机制:

    • Hibernate 提供了 一级缓存 和 二级缓存,可以显著提升查询性能
  7. 数据库独立性:

    • Hibernate 可以支持多种数据库(如 MySQL、PostgreSQL、Oracle 等),使应用程序不依赖于具体的数据库类型
  8. 事务管理:

    • Hibernate 支持声明式事务管理,和 JTA(Java Transaction API)集成,可以确保事务的一致性和原子性。

Hibernate核心组成部分

  1. SessionFactory:

    • 是 Hibernate 的核心接口,用于创建和管理 Session 对象。SessionFactory 会读取配置文件,连接数据库,并提供 Session 的实例。
  2. Session:

    • Session 是与数据库交互的接口,负责执行数据库操作(如持久化、查询、删除、更新等)。
    • 一个 Session 对象代表一个数据库会话,它通常对应一个事务
  3. Transaction

    • Hibernate 管理事务,确保操作的原子性。每个操作都应在事务中完成。
  4. Mapping 文件

    • Hibernate 通过 XML 映射文件 或 注解 来定义 Java 对象与数据库表之间的映射关系。
  5. Query

    • Hibernate 提供了多种查询方式:HQL(Hibernate Query Language)、Criteria API 和原生 SQL。
  6. Cache

    • Hibernate 提供了 一级缓存(与 Session 相关)和 二级缓存(跨 Session 的缓存),用来提高性能

核心功能

  1. 持久化对象

    • Hibernate 可以自动将 Java 对象保存到数据库,也可以从数据库中加载数据到 Java 对象中。
  2. 查询功能

    • Hibernate 提供了多种查询方式

      • HQL:Hibernate Query Language,面向对象的查询语言。
      • Criteria API:通过 Criteria 构造查询。
      • 原生 SQL:可以直接使用 SQL 查询数据库。
  3. 关系映射

    • 支持 一对一、一对多、多对多 等关系的映射。
    • 使用 外键 或 连接表 来表示关系。
  4. 级联操作

    • Hibernate 支持级联操作,可以让数据库的增删改操作自动传播到相关的对象。
  5. 懒加载和预加载

    • 支持 懒加载(Lazy Loading)和 预加载(Eager Loading),帮助优化性能。
  6. 事务支持

    • Hibernate 支持与 Spring、Java EE 等框架集成,提供事务管理功能,确保数据一致性。

Hibernate的优点

  1. 无需管理数据库的连接,直接配置在xml中即可
  2. 一个会话,不要操作多个对象,而是操作Session对象

Hibernate的缺点

  1. 全表映射带来的不便,如果更新某个字段,需要发送所有的字段
  2. 无法根据不同的条件组装不同的Sql
  3. 对多表查询和复杂SQL的支持较差,需要自己写SQL,还需要自己数据组装成POJO
  4. 不能有效支持存储过程
  5. 虽然有HQL,但是性能很差,大型互联网需要优化SQL

4.Mybatis和Hibernate之间的比较

特性 Hibernate Mybatis
SQL控制 自动生成SQL 需要手动编写SQL
学习曲线 较高,需要学习HQL、Criteria API 等 较低,直接使用SQL语句
灵活性 较低,复杂查询需要调优生成的 SQL 高,完全控制 SQL
缓存支持 支持一二级缓存 不提供内建缓存机制
适用场景 对象关系映射较多的应用、简化 SQL 操作的场景 需要精细控制 SQL 的场景

爱跑步的猕猴桃
1 声望0 粉丝