前言
不论是自己的小项目也好,还是日常使用也好,都离不开Java使用数据库,自己之前也封装过一些使用JDBC库,今天打算花点时间好好梳理下,顺便手写一个简单的ORM框架,并且之后打算深入研究下mybatis框架。
原生JDBC
JDBC(Java DataBase Connectivity)java数据库连接,简单来说就是java下面的数据库连接API(接口),我们知道天下数据库种类很多,sun公司(现在应该说是oracle公司)的程序员不可能为这么多的数据库提供实现类,他们既没有这个必要,而且他们也不知道数据库的具体实现细节,所以这一部分应该交给各家数据库自己去实现,Java只需要自己制作标准即可。也就是我们使用接口编写代码,实际上的实现类是由各个厂商提供的驱动。
废话不多说,这里先提供一个最简单的数据库连接demo:
1 | public class Main { |
简单来说,有以下四个接口,分别是DriverManager(这个是类不是接口)、Connection、PreparedStatement(Statement)、ResultSet,中文也很好理解,分别叫驱动管理、连接、预处理语句和结果集,下面打算从源码角度来看看JDK是如何定义它们的。
DriverManager
我们在实际使用中这个类就两个功能:注册驱动和获得数据库连接。你可能会觉得奇怪,明明代码里只有获取连接,哪里来的注册驱动呢?其实这个类下面是有一个叫registerDriver()的方法的。而且你可能还会觉得神奇的是,我明明只是加载了指定的驱动,但是似乎并没有用,这个到底是怎么做到的呢?要解开这个秘密,看下源码便知道了:
1 | package com.mysql.cj.jdbc; |
从上面的代码中可以看到,只要当这个类被加载的时候,它就会执行静态代码段里面的内容,就会调用DriverManager去注册数据库的驱动。PS:现在可以不用注册了(Java SPI)。
Connection

利用IDEA可以很明显看出继承自两个接口:
- 一个是AutoCloseable接口,也就是说可以支持下面的语法:
1 | try (Connection conn = ......) { |
这样就会自动关闭。
- 第二个是Wrapper这个接口,里面只有两个方法,但是我看不太懂,先暂时放一边。
最后是Connection本身,它自己有两块重要的功能,一个是创建执行sql语句的对象,另一个是事务相关的操作,这里挑选几个重要的方法:
- createStatement() 创建一个Statement对象并且返回。
- prepareStatement(String sql) 接受一个sql语句,并且将其预编译,返回一个PrepareStatement对象。
- setAutoCommit(boolean autoCommit) 设置是否自动提交事务,默认是将一个sql语句都当成一个事务。所以传入false就相当于开启事务。
- commit() 提交事务,当所有数据库执行语句完成之后使用。
- rollback() 回滚,必须在自动提交是关闭的情况下才有效。一般会写在catch语句中。
Statement
其实在日常使用中几乎不怎么使用它,因为存在被SQL注入的风险,而一般使用PreparedStatement来代替它,但是它们俩其实在使用上几乎一样,所以拿它作为例子。它同样实现了AutoCloseable接口和Wrapper接口。下面是它的主要方法:
execute(String sql) 可以执行任何语句。一般不使用。
executeQuery(String sql) 执行一个查询的sql语句并且返回一个ResultSet对象。
executeUpdate(String sql) 可以执行增删改语句(即DML),还可以执行DDL语句,但是一般不用来执行DDL,返回值是影响的行数。
PreparedStatement
日常使用这个东西,使用预编译技术来防止sql注入。写sql语句的时候,参数使用占位符?代替,然后把sql语句代入到connection对象的preparedstatement方法中。然后将?赋值即可。
ResultSet
由字面意思可知,就是用来存放从数据库中查找到的结果集。接口和上面两位一样。
- boolean next() 最开始的时候光标在第一行之前,执行这个方法会将光标移动一行。
- 各类get方法,这里略过。
有了上面的知识梳理,对JDBC的操作进行一些简单的封装,相信是非常容易的事情。但是我们希望能够更进一步。因为Java是面向对象的,我们自然希望能够让Java中的一个对象,和数据库中查询出来一条记录进行匹配,也就是ORM(Object Relationship Mapping)
手写ORM
首先先来分析下,实现这个简单的框架,至少需要分成哪些部分。首先是数据库的连接部分
数据库连接部分
主流框架用的是XML进行配置,我这边为了简单起见,直接用文件读取,本质上两者都是一样的。
连接肯定需要有四个部分,分别是driver、url、username和password。