mybatis源码阅读系列(一)

WuYiLong原创大约 6 分钟mybatis源码阅读系列mybatis

源码下载

mybatisopen in new window

初识mybatis

MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解用于配置和原始映射,将接口和 Java 的 POJOs(Plain Old Java Objects)映射成数据库中的记录。 MyBatis 的几个主要特点:

  1. 支持定制化 SQL、存储过程和高级映射:MyBatis 主要管理 SQL 语句的运行,让开发者可以专注于 SQL 语句本身,而不是花费精力处理 JDBC 等数据库连接相关的代码。
  2. 灵活的映射规则:MyBatis 提供了很多灵活的映射规则,比如一对一、一对多、多对多等复杂关系都可以通过简单的 XML 配置实现。
  3. 松耦合:MyBatis 不会像一些传统的 ORM 框架那样强迫你使用某种编程模型,它允许你使用简单的 XML 或注解来配置 SQL 语句和映射关系,不会强制你抽象出 POJOs。
  4. 易于上手和集成:MyBatis 易于理解和实施,它可以很容易地集成到各种应用之中。
  5. 动态 SQL:MyBatis 提供了强大的动态 SQL 功能,可以方便地实现复杂的查询和操作。
  6. 可定制 SQL 执行:MyBatis 允许自定义 SQL 执行语句,提供了包括插件在内的多种方式来优化 SQL 的执行。
  7. 丰富的映射标签:MyBatis 提供了丰富的映射标签,使得数据库操作更加灵活、方便。
  8. 良好的支持性:MyBatis 支持多种数据库,如 MySQL、Oracle、SQL Server、H2、Sqlite 等。 MyBatis 的使用步骤大致如下:
  9. 配置 MyBatis:通过 SQL 映射文件或注解来配置 SQL 语句。
  10. 创建会话工厂(SqlSessionFactory):通过配置文件或代码来创建 SqlSessionFactory。
  11. 创建 SQL 会话(SqlSession):利用 SqlSessionFactory 来创建 SQL 会话。
  12. 执行操作:通过 SQL 会话执行定义好的 SQL 语句。
  13. 处理结果:根据执行的 SQL 语句处理结果集。
  14. 关闭会话:操作完成后关闭 SQL 会话。 MyBatis 框架在国内外都有广泛的应用,是 Java 开发中常用的一种数据库操作框架。

原生jdbc操作数据库

原生 JDBC(Java Database Connectivity)是指 Java 数据库连接,它是一个用于 Java 程序和各种数据库之间进行交互的 API。JDBC 提供了一种标准方法来访问数据库,允许 Java 应用程序以一种统一的方式与不同的数据库进行通信。

package com.wyl.mybatis.service;

import java.sql.*;

/**
 * @Description
 * @Author WuYiLong
 * @Date 2024/2/26 11:36
 */
public class JdbcService {

    /**
     * 数据库链接
     */
    private static final String url = "jdbc:mysql://localhost:3306/blog?zeroDateTimeBehavior=CONVERT_TO_NULL&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=GMT%2B8";

    /**
     * 用户名
     */
    private static final String username = "root";

    /**
     * 密码
     */
    private static final String  password = "123456";

    public static void main(String[] args) {
        try {
            // 加载所需的 JDBC 驱动,这通常是通过调用 Class.forName() 方法来完成的
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 使用 DriverManager.getConnection() 方法建立与数据库的连接。
            Connection connection = DriverManager.getConnection(url, username, password);
            // 创建一个 Statement 或 PreparedStatement 对象来执行 SQL 语句。
            String sql = "SELECT * FROM `b_expert` limit 10;";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.executeQuery(sql);
            // 如果是查询操作,执行 executeQuery() 方法,并处理返回的 ResultSet。
            ResultSet resultSet = preparedStatement.executeQuery(sql);
            // 通过遍历,输出数据
            while (resultSet.next()) {
                System.out.println("专家名称:"+resultSet.getString("name"));
            }
            // 关闭 ResultSet、Statement 和 Connection,以释放数据库资源。
            resultSet.close();
            preparedStatement.close();
            connection.close();
        } catch (SQLException | ClassNotFoundException throwables) {
            System.out.println(throwables.getMessage());
        }
    }
}

image.png

mybatis操作数据库

数据表设计

CREATE TABLE `d_full_city` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `name` varchar(255) DEFAULT NULL COMMENT '名称',
  `code` varchar(255) DEFAULT NULL COMMENT '区域码',
  `full_name` varchar(255) DEFAULT NULL COMMENT '全名称',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=46476 DEFAULT CHARSET=utf8mb4 COMMENT='省市区-字典';

实体类

package com.wyl.mybatis.entity;

/**
 * @Description 省市区-字典
 * @Author wuyilong
 * @Date 2024-02-26
 */
public class FullCity {

    private static final long serialVersionUID = 1L;

    /**
     * 主键ID
     */
    private Long id;

    /**
     * 名称
     */
    private String name;

    /**
     * 区域码
     */
    private String code;

    /**
     * 全名称
     */
    private String fullName;

    public static long getSerialVersionUID() {
        return serialVersionUID;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
}

mapper接口

package com.wyl.mybatis.mapper;

import com.wyl.mybatis.entity.FullCity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
* @Description 省市区-字典
* @Author wuyilong
* @Date 2024-02-26
*/
@Mapper
public interface FullCityMapper {

    /**
     * 根据名称查询
     * @param name
     * @return
     */
    FullCity selectByName(@Param("name") String name);
}

mapper.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.wyl.mybatis.mapper.FullCityMapper">

  <!-- 通用查询映射结果 -->
  <resultMap id="BaseResultMap" type="com.wyl.mybatis.entity.FullCity">
    <id column="id" property="id"/>
    <result column="name" property="name"/>
    <result column="code" property="code"/>
    <result column="full_name" property="fullName"/>
  </resultMap>

  <select id="selectByName" resultType="com.wyl.mybatis.entity.FullCity">
    select * from d_full_city where name = #{name}
  </select>


</mapper>

mybatis的配置文件

<?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>
    <!-- 属性:定义配置外在化 -->

    <properties resource="mybatis-mysql.properties">
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <property name="driver" value=""/>
        <property name="url" value=""/>
    </properties>
    <!-- 设置:定义mybatis的一些全局性设置 -->
    <settings>
        <!-- 具体的参数名和参数值 -->
        <setting name="cacheEnabled" value="true"/>
<!--        <setting name="lazyLoadingEnabled" value="true"/>-->
<!--        <setting name="multipleResultSetsEnabled" value="true"/>-->
<!--        <setting name="useColumnLabel" value="true"/>-->
<!--        <setting name="useGeneratedKeys" value="false"/>-->
<!--        <setting name="autoMappingBehavior" value="PARTIAL"/>-->
<!--        <setting name="defaultExecutorType" value="SIMPLE"/>-->
<!--        <setting name="defaultStatementTimeout" value="25"/>-->
<!--        <setting name="defaultFetchSize" value="100"/>-->
<!--        <setting name="safeRowBoundsEnabled" value="false"/>-->
<!--        <setting name="mapUnderscoreToCamelCase" value="false"/>-->
<!--        <setting name="localCacheScope" value="SESSION"/>-->
<!--        <setting name="jdbcTypeForNull" value="OTHER"/>-->
<!--        <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>-->
    </settings>

    <!-- 环境:配置mybatis的环境 -->
    <environments default="development">
        <!-- 环境变量:可以配置多个环境变量,比如使用多数据源时,就需要配置多个环境变量 -->
        <environment id="development">
            <!-- 事务管理器 -->
            <transactionManager type="jdbc"></transactionManager>
            <!-- 数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="./mapper/ExpertMapper.xml"  />
    </mappers>
</configuration>

mybatis的数据库配置文件

username=root
password=123456
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/blog?zeroDateTimeBehavior=CONVERT_TO_NULL&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=GMT%2B8

执行过程

package com.wyl.mybatis.service;

import com.wyl.mybatis.entity.FullCity;
import com.wyl.mybatis.mapper.FullCityMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @Description
 * @Author WuYiLong
 * @Date 2024/2/26 16:04
 */
public class MybatisService {

    public static void main(String[] args) throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();

        FullCityMapper mapper = sqlSession.getMapper(FullCityMapper.class);
        FullCity fullCity = mapper.selectByName("广东省");
        System.out.println("城市的名称:"+fullCity.getName());

    }
}

image.png

总结

JDBC 提供了最底层的访问数据库的方式,直接使用SQL语句,灵活但需要手动管理连接和事务。 MyBatis 是在JDBC之上的一个抽象层,隐藏了如何连接数据库、如何处理事务、如何关闭流、自动提交,通过ORM提供了更高层次的数据库操作,通过编写简单的sql就可以完成增删改查,简化了开发流程,更适合于复杂的SQL操作和动态SQL需求。 所以在选择使用JDBC还是MyBatis时,通常考虑应用的复杂性、性能需求和开发效率等因素。对于简单的数据库操作,JDBC可能更直接高效;而对于复杂的业务逻辑和大量的数据库交互,MyBatis提供的抽象和便利可能会更加合适。

上次编辑于:
贡献者: wuyilong