MyBatis源码之前言—JDBC编码存在的问题和Mybatis的介绍

mybatis,jdbc · 浏览次数 : 0

小编点评

**MyBatis代码解析的几个关键问题及其解决方案** **1. 结果集解析复杂** * 解决方法:在编码时,使用 `selectList()` 方法指定 sql 语句的唯一标识作为参数。 **2. sql语句硬编码** * 解决方法:使用 `select()` 方法指定 sql 语句的唯一标识和参数。 **3. 频繁连接、释放数据库资源** * 解决方法:使用 `SqlSessionFactory` 创建并关闭 SqlSession 对象,并设置 `statementCache` 属性为 `true`。 **4. 预参数问题** * 解决方法:在配置文件中定义参数,并在代码中传入参数。

正文

MyBatis源码之前言—JDBC编码存在的问题和Mybatis的介绍

为了方便操作,我们在sjdwz_test数据库下建立一张表:

CREATE TABLE `t_student` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(255) DEFAULT NULL COMMENT '名字',
  `age` int(255) DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

数据如下:

数据

实体类如下:

package com.sjdwz.db;

import lombok.*;

/**
 * @Description 数据库实体
 * @Created by 随机的未知
 */
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Student {
    private Long id;
    private String name;
    private Integer age;
}

JDBC操作数据库

我们先来回顾一下JDBC操作数据库的代码:

package com.sjdwz.jdbc;

import com.sjdwz.db.Student;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description JDBC操作数据库代码示例
 * @Date 2023/12/14
 * @Created by 随机的未知 sjdwz.com
 */
public class JDBCMain {
    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        //数据库连接地址
        String url = "jdbc:mysql://localhost:3306/sjdwz_test";
        String user = "root";//用户名
        String password = "1234567";//密码
        //1.注册数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.获取数据库连接对象Connection。
        Connection conn = DriverManager.getConnection(url, user, password);
        //3.创建Sql语句对象Statement,填写SQL语句
        PreparedStatement preparedStatement = conn.prepareStatement("select * from t_student where `name` = ?; ");
        //传入查询参数
        preparedStatement.setString(1, "张三");
        //4.执行SQL查询,返回结果集对象ResultSet
        ResultSet resultSet = preparedStatement.executeQuery();
        List<Student> studentList = new ArrayList<>();
        //5.循环解析结果集,获取查询用户list集合
        while (resultSet.next()) {
            Student student = Student.builder()
                    .id(resultSet.getLong("id"))
                    .name(resultSet.getString("name"))
                    .age(resultSet.getInt("age"))
                    .build();
            studentList.add(student);
        }
        //打印查询结果
        System.out.println(studentList);
        //6.关闭连接,释放资源
        resultSet.close();//关闭结果集对象
        preparedStatement.close();//关闭Sql语句对象
        conn.close();//关闭数据库连接对象
    }
}

运行截图如下:

运行截图

这段代码主要有如下四点问题:

  1. 结果集解析复杂,列名硬编码,sql变化导致解析代码变化,系统不易维护;
  2. sql语句硬编码,数据库配置硬编码,难以维护;
  3. 频繁连接、释放数据库资源,没有用到池化思想,系统性能不高;
  4. prepareadStatement向占位符传参数存在硬编码,不易维护。

所以我们需要一个ORM框架,来解决这些痛点。我用的最多的ORM框架是MyBatis,我们就来从源码角度来分析它,看看MyBatis是怎么解决这些问题的。

MyBatis介绍

什么是MyBatis

  • MyBatis是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。
  • MyBatis对JDBC封装使得开发者只需要关注SQL语句与业务本身即可,无需开发者处理加载驱动、获取连接、创建Statement等繁琐的过程。
  • MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO为数据库中的记录。
  • MyBatis是一个实现了ORM思想的持久层框架。

什么是ORM?为什么说MyBatis是一个半ORM框架?

  • ORM:Object/Relation Mapping 对象/关系映射。
  • ORM思想:将数据库中的关系数据表映射为Java中的对象,把对数据表的操作转换为操作对象,实现面向对象编程。因此,ORM的目的是使得开发人员以面向对象的思想来操作数据库
  • MyBatis框架是一个半自动的ORM持久层框架,也可以在Java中实现类似insert(Student)的操作最终操作数据库,但是需要我们自己写SQL语句。

MyBatis操作数据库

项目结构截图如下:

项目结构截图

在resources目录下创建mybatis-config.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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/sjdwz_test?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="1234567"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--        加载sql映射文件-->
        <mapper resource="StudentMapper.xml"/>
    </mappers>
</configuration>

在resources目录下创建StudentMapper.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="test">
    <!--    id是指sql的唯一标识,resulttype是指返回值的类型-->
    <select id="findListByName" resultType="com.sjdwz.db.Student" parameterType="string">
        select * from t_student where `name` = #{name};
    </select>
</mapper>

MyBatis操作数据库代码如下:

package com.sjdwz.mybatis;

import com.sjdwz.db.Student;
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;
import java.util.List;

/**
 * @Description Mybatis示例
 * @Created by 随机的未知
 */
public class MybatisTest {
    public static void main(String[] args) throws IOException {
        //1.创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        //2.SqlSessionFactoryBuilder对象创建工厂对象
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        //3.工厂对象Factory打开SqlSession会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //4.SqlSession会话对象执行SQL语句,findListByName(命名空间+查询语句唯一标识)
        List<Student> studentList = sqlSession.selectList("test.findListByName","张三");
        //5.打印查询结果
        System.out.println(studentList);
        //6.关闭sqlSession会话
        sqlSession.close();
    }
}

运行截图如下:

运行截图

Mybatis配置和代码解决的问题

在前文,使用JDBC存在四个问题,而Mybatis就解决了这四个问题。

JDBC编码存在的第一个问题的解决

第一个问题是结果集解析复杂,列名硬编码,sql变化导致解析代码变化,系统不易维护;

MyBatis编码中我们不需要进行结果集解析,只需要在编码时指定sql即可,MyBatis会给我们结果;

List<Student> studentList = sqlSession.selectList("test.findListByName","张三");

JDBC编码存在的第二个问题的解决

第二个问题是sql语句硬编码,数据库配置硬编码,难以维护;

数据库的配置和sql语句,我们写到了xml文件,解决了硬编码的问题

JDBC编码存在的第三个问题的解决

第三个问题是频繁连接、释放数据库资源,没有用到池化思想,系统性能不高

MyBatis使用了池化思想,解决了这个问题;

JDBC编码存在的第四个问题的解决

第三个问题是prepareadStatement向占位符传参数存在硬编码,不易维护

我们在配置文件标签上写明了参数,并在代码中传入,避免了占位符的硬编码,解决了此问题。

截图

截图

总结

我们回顾了JDBC和MyBatis的编码方式,了解了JDBC编码存在的问题,并知道了MyBatis编码确实解决了这几个问题。

后面我们就来分析MyBatis源码了。

与MyBatis源码之前言—JDBC编码存在的问题和Mybatis的介绍相似的内容:

MyBatis源码之前言—JDBC编码存在的问题和Mybatis的介绍

本文是MyBatis源码之前言,主要介绍了JDBC编码存在的问题和介绍了Mybatis的配置、使用。 本文指出了JDBC编码操作数据库的问题,并给出了分析。

MyBatis源码之MyBatis中SQL语句执行过程

本文是MyBatis源码之MyBatis中SQL语句执行过程,使用图文并茂的方式,讲解了SQL语句执行过程,调用了哪些方法,和这些方法是如何调用的。

Mybatis源码解析之执行SQL语句

作者:郑志杰 mybatis 操作数据库的过程 // 第一步:读取mybatis-config.xml配置文件 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 第二步:构建SqlSes

Mybatis中的设计模式

最近在看《通用源码阅读指导书:Mybatis源码详解》,这本书一一介绍了Mybatis中的各个包的功能,同时也涉及讲了一些阅读源码的技巧,还讲了一些源码中涉及的设计模式,这是本篇文章介绍的内容 在多说一点这本书,Mybatis是大部分Java开发者都熟悉的一个框架,通过这本书去学习如何阅读源码非常合

【简写Mybatis-02】注册机的实现以及SqlSession处理

学习源码一定一定不要太关注代码的编写,而是注意代码实现思想:通过设问方式来体现代码中的思想;方法:5W+1H

聊聊Mybatis集成Spring的原理

一般都是研究框架源码,我为什么要反过来研究集成原理呢? 在我自己看来,集成虽然比较简单,但要求的细节比较多,需要掌握根本性的东西才能做到集成。 Mybatis集成Spring用到了FactoryBean以及BeanDefinition注册的原理,从这两个维度来实现集成,而我们单独学习Spring时,

Mybatis Plus 3.X版本的insert填充自增id的IdType.ID_WORKER策略源码分析

总结/朱季谦 某天同事突然问我,你知道Mybatis Plus的insert方法,插入数据后自增id是如何自增的吗? 我愣了一下,脑海里只想到,当在POJO类的id设置一个自增策略后,例如@TableId(value = "id",type = IdType.ID_WORKER)的注解策略时,就能实

聊聊Mybatis的实现原理

### 使用示例 平时我们使用的一般是集成了Spring或是Spring Boot的Mybatis,封装了一层,看源码不直接;如下,看看原生的Mybatis使用示例 ![image](https://img2023.cnblogs.com/blog/971683/202305/971683-2023

Mybatis执行器

mybatis执行sql语句的操作是由执行器(Executor)完成的,mybatis中一共提供了3种Executor: 类型 名称 功能 REUSE 重用执行器 缓存PreparedStatement,下一次执行相同的sql可重用 BATCH 批量执行器 将修改操作记录在本地,等待程序触发或有下一

『手写Mybatis』实现映射器的注册和使用

前言 如何面对复杂系统的设计? 我们可以把 Spring、MyBatis、Dubbo 这样的大型框架或者一些公司内部的较核心的项目,都可以称为复杂的系统。 这样的工程也不在是初学编程手里的玩具项目,没有所谓的 CRUD,更多时候要面对的都是对系统分层的结构设计和聚合逻辑功能的实现,再通过层层转换进行