七年再回首,从JDBC到ORM

前言

初学ORM和JDBC还是2016年的10月15日,在宿舍里偷偷记下了一纸笔记。
七年再回首,从JDBC到ORM_第1张图片

转眼七年已过,从来没有手写过JDBC,数据库的连接都是通过框架和连接池就给完成了,ORM的工作框架也都顺手给完成了。

本篇文章就用七年后角度,再次学习JDBC和ORM。

JDBC

JDBC即Java数据库连接,是Java提供的一套连接数据库的接口规范,开发者可以通过模板代码来连接不同的数据库。这里就拿MySQL和oracle来举例,画了一个简单的图。

七年再回首,从JDBC到ORM_第2张图片

我们可以通过右边java.sql提供的JDBC流程,只要将对应数据库驱动注册到DriverManager中,就能实现对数据库的连接,然后获取连接对象、执行sql、返回结果集。这些在java.sql包里都提供了对应的类。

建表

安装数据库的文章之前有写过,这里直接建表。

七年再回首,从JDBC到ORM_第3张图片

一共三个字段,两个varchar字符串类型,一个int类型,然后插入数据。

代码实现

这里先定义一个和表字段一样的Java类。

七年再回首,从JDBC到ORM_第4张图片

这里就以MySQL为例,使用JDBC查询数据库。首先我们要引入MySQL的驱动依赖。

<dependency>
  <groupId>mysqlgroupId>
  <artifactId>mysql-connector-javaartifactId>
  <version>8.0.27version>
dependency>

然后就根据JDBC接口规范开始开发代码。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JdbcDemo {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String url = "jdbc:mysql://175.27.xxx.xxx:3306/test";
        String user = "root";
        String password = "xxxxxxx";
        Connection conn = DriverManager.getConnection(url, user, password);
        Statement statement =  conn.createStatement();
        String sql = "select * from people";
        ResultSet rs = statement.executeQuery(sql);
        while (rs.next()){
            // System.out.println(rs.getString(1) + "-" + rs.getInt(2) + "-" + rs.getString(3));
            People people = new People();
            people.setName(rs.getString(1));
            people.setAge(rs.getInt(2));
            people.setPhone(rs.getString(3));
            System.out.println(people);
        }
        rs.close();
        statement.close();
        conn.close();
    }
}

手动对ResultSet遍历,获取每个字段的值,将每个字段set到新创建的People对象中。这里要注意的是:下标是从1开始的。

运行输出结果:

七年再回首,从JDBC到ORM_第5张图片

数据表中的三条数据都被查询到并输出了出来。接下来就从头分析一下JDBC流程。

JDBC流程

1. 加载驱动

JDBC中通过Class.forName反射加载驱动类。com.mysql.cj.jdbc.Driver 是MySQL的驱动类,在MySQL的依赖包里,当没有添加MySQL依赖时,就会报错ClasNotFound的异常。

七年再回首,从JDBC到ORM_第6张图片

上图为MySQL驱动类源码,继承NonRegisteringDriver并实现了JDBC的Driver接口,在加载类的同时,也会调用static代码块,调用DriverManger的registerDriver方法,向DriverManger注册此驱动。

七年再回首,从JDBC到ORM_第7张图片

registeredDrivers是一个CopyOnWriteArrayList,即线程安全的List,记录着各个Driver的信息,addIfAbsent只有当这个driver不存在时,则会添加进去,保证每个数据库的驱动信息只会加载一次。

2. 数据库连接

DriverManger记录着所有驱动的信息,并通过getConnection() 连接数据库并返回Connection对象。代码如下:

七年再回首,从JDBC到ORM_第8张图片

aDriver就是存放在registeredDrivers中的Driver信息,这里指的就是MySQL驱动,然后调用此驱动的connect方法连接数据库,看看NonRegisteringDriver类中connect代码。

七年再回首,从JDBC到ORM_第9张图片

里面就是所有通过url、user、password信息连接MySQL数据库的逻辑实现,最后返回一个Connection对象。通过断点可以知道,最后返回的是MySQL驱动的ConnectionImpl类。

七年再回首,从JDBC到ORM_第10张图片

所以说,JDBC的DriverManger只是提供了管理Driver以及连接数据库的入口(connect方法),至于连接数据库的细节,需要每个数据库的驱动类自己实现细节,只要最后按照JDBC规范,返回一个Connection即可。

3. 执行查询SQL

使用连接对象createStatement方法创建一个Statement对象,即用来直行SQL的一个对象。通过断点可以看到,从MySQL数据库连接中返回的是MySQL实现的StatementImpl对象。

然后调用executeQuery()来执行查询SQL。

七年再回首,从JDBC到ORM_第11张图片

最后返回结果集ResultSet,其实返回的是MySQL驱动中自己实现的ResultSet子类ResultSetInternalMethods

七年再回首,从JDBC到ORM_第12张图片

最后我们根据ResultSet提供的next来遍历数据集,通过从1开始的索引来获取每条数据中每个字段,手动赋值给People对象。

总结

至此我们可以知道,JDBC提供的Driver、Connection、Statement和ResultSet都是接口,里面所有方法都需要数据库驱动自己实现,MySQL驱动如此,Oracle驱动亦是如此。

ORM

ORM(Object Relational Mapping),对象关系映射,我理解的是就是JAVA类和数据库中表的映射,类字段和表字段的映射以及字段类型的映射。

上面连接MySQL返回结果集ResultSet之后,需要完成手动遍历、创建People对象、赋值等一系列操作,超级麻烦。所以ORM框架就开始出现了,上面这些操作就完全由框架内部处理。从JavaWeb学的DButils,到SSM框架中的MyBatis等都是ORM框架。

与JDBC相比,我们只需要输入SQL,定义好Java类,ORM框架就自动将数据库中查询到的数据,封装到Java类中返回给我们,然后我们从类对象中get数据字段即可。

DButils

引入依赖:

<dependency>
    <groupId>commons-dbutilsgroupId>
    <artifactId>commons-dbutilsartifactId>
    <version>1.8.1version>
dependency>

使用DButils完成ORM测试代码。

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.List;

public class DBUtilsDemo {
    public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.cj.jdbc.Driver");
        String url = "jdbc:mysql://175.27.xxx.xx:3306/test";
        String user = "root";
        String password = "xxxxxx";
        Connection conn = DriverManager.getConnection(url, user, password);
        String sql = "select * from people";
        QueryRunner queryRunner = new QueryRunner();
        List<People> peoples = queryRunner.query(conn, sql, new BeanListHandler<>(People.class));
        for (People people : peoples) {
            System.out.println(people);
        }
    }
}

从代码里可以看出,这里不会再返回原始的ResultSet数据集,而是queryRunner.query之后直接返回List,这得益于BeanListHandler的内部逻辑,将每条数据都封装成People对象。

我们来看一下输出结果:

七年再回首,从JDBC到ORM_第13张图片

结果和上面JDBC的一样,但是少了很多代码。学过JavaWeb的都知道,DButils会和DataSource一起使用,例如C3P0等,所以在QueryRunner直接传入DataSource即可,而不是一个connection。这样代码又少了很多。

与JDBC对比一下,ORM的作用体现在:

七年再回首,从JDBC到ORM_第14张图片

MyBatis

MyBatis更为简单,在Mapper文件中使用注解传入SQL,通过返回值关联Java类,直接调用对应的mapper函数,就能获取对相应的数据,实现ORM。

七年再回首,从JDBC到ORM_第15张图片
这个方法就是查询数据库中的building_info表,映射成Java的BuildingDataInfo类,每条数据对应一个BuildingDataInfo对象。

七年再回首,从JDBC到ORM_第16张图片

与DButils相比,MyBatis更为简单,不需要传入Handler,不需要传入数据源,只要调用提前定义好的方法,就能获取到ORM后的数据。

结语

上面就是我对JDBC和ORM的理解,理解不足之处请指正,期待共同学习和进步。

你可能感兴趣的:(java,jdbc,orm,DBUTILS,mysql)