什么是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文件配置
流程如下
-
通过在resource下面创建mapper包用于存储Mapper.xml映射文件。
-
在Mapper接口中定义需要的方法。
-
在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和注解方式。