手写JDBC的几个步骤

手写JDBC的几个步骤

十月 25, 2020

手写JDBC的几个步骤

编者:顾念

使用的MySQL版本:8.0.19;

序言

因为数据库厂商有很多种,为了能够统一让java程序员使用更方便,sun公司编写了一套JDBC接口用于连接数据库。但是只有JDBC接口我们仍然是连接不了数据库的。这时候各个数据库厂商要为这个接口写程序,为了能够使其连接。

一、什么是JDBC

JDBC(JavaDataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。

二、JDBC的原理

由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动!
在这里插入图片描述

三、什么是驱动

其实驱动也非常好理解,驱动:只不过是为数据库连接这个动作起一个非常高大上的名字而已。你只需要明白在这里说这个词就可以了。其他的也就没有什么可说的了。

四、使用JDBC的前期准备

  1. 下载各个数据库厂商的数据库连接驱动
  2. 准备一个编辑器(推荐使用IDEA)
  3. 下载驱动,需要找对应的版本(可以直接去官网下载)
  4. 将驱动加载到编辑器中

开始进行操作

一、在IDEA中准备

  1. 创建一个普通的java工程
  2. 在该工程中创建一个lib文件夹
  3. 将你的数据库驱动文件(也就是你下载下来的jar包)复制到你的lib文件加下,但是现在还不能使用。
  4. 在你的lib文件中右击,在菜单栏中选择==Add as Libraly==。到这里你的驱动文件就已经加载到你的IDEA中了。

二、开始进行编码

  1. 在src中创建一个你自己的包,==com.qianmo.Connection== 这个自己根据自己的情况自己创建

  2. 在该包下创建自己的java文件,==ConnectionTest.java==.名字可以自己定

  3. 在src中创建一个==jdbc.properties==配置文件

  4. 编码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class ConnectionTest{
    //如果你想做测试的话也可以使用@Test来创建方法

    public static void main(String[] args){

    //使用IO数据流引用配置文件
    InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");

    Properties proe = new Properties();
    proe.load(is);
    String driver = proe.getProperty("driver");
    String url = proe.getProperty("url");
    String user = proe.getProperty("user");
    String password = proe.getProperty("password");

    //加载驱动
    Class.forName(driver);
    //获取链接
    Connection conn = DriverManager.getConnection(url,user,password);
    //输出是否链接成功
    System.out.println(conn);
    }
    }
  5. 关于==jdbc.properties==文件内容

    将配置文件命名为JDBC.properties.针对于MySQL8.0以上版本的配置文件内容与MySQL5.7版本的配置文件内容有所区别,现在我们写以下关与MySQL8.0以上的配置文件内容

    1
    2
    3
    4
    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
    user=root
    password=1213

三、输出为:

==com.mysql.cj.jdbc.ConnectionImpl@31dc339b==:或者一些特殊的符号,但是必须有com.mysql.cj.jdbc,表示连接成功。

四、介绍以下ORM编程思想,并做代码实例

内容:

  1. 一个数据表对应一个Java类
  2. 表中的一条记录对应着Java类中的一个对象
  3. 表中的一个字段对应着Java类中的一个属性

实例:

假设我们有一张customers表,表中有3个字段,name,email,birth

那么我们根据ORM的编程思想可以将数据表映射成Java类为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.sql.Date;
public class Customers{
private int id;
private String name;
private String email;
private Date brith;

//空参方法
public Customer(){
super();
}
//有参方法
public Customer(int id, String name, String email, Date birth) {
this.id = id;
this.name = name;
this.email = email;
this.birth = birth;
}
//get方法
public int getId() {
return id;
}

public String getName() {
return name;
}

public String getEmail() {
return email;
}

public Date getBirth() {
return birth;
}
//set方法
public void setId(int id) {
this.id = id;
}

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

public void setEmail(String email) {
this.email = email;
}

public void setBirth(Date birth) {
this.birth = birth;
}
//tostring方法
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
", birth=" + birth +
'}';
}
}

五、抽出连接数据库共享部分,将它们作为一个类进行使用

在写数据库的操作的时候,我们发现在获取数据库连接,和关闭数据库连接的时候这两个操作基本是一致的,所以我们将它抽出到JDBCUtil.java这个类中。

JDBCUtil.java代码实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/*
* 操作数据库个工具类
* */

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils{

//连接数据库
public static Connection getConnection() throws Exception{
//1.读取配置文件中的4个重要信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties proe = new Properties();
proe.load(is);
String user = proe.getProperty("user");
String url = proe.getProperty("url");
String password = proe.getProperty("password");
String driver = proe.getProperty("driver");
//2.加载驱动
Class.forName(driver);
//3.获取连接
Connection conn = DriverManage.getConnection(url,user,password);
return conn;
}

//关闭资源
public static void closeResource(Connection conn, PreparedStatement ps){
//资源的关闭
try {
if (ps != null) {
ps.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if (conn != null){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}

public static void closeResource(Connection conn, PreparedStatement ps, ResultSet rs){
//资源的关闭
try {
if (ps != null) {
ps.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if (conn != null){
conn.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
try {
if (rs != null){
rs.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}

}

六、操作数据库,对其进行增删改

为什么将增删改作为一个合并来讲呢,愿意是这三个操作不会返回结果集。而查询操作,我们需要看到返回来的结果集。所以归类的话我们将增删改归为一类,将查询归为一类。

因为时间有限,我只写一个通用的增删改操作

PreparedStatementUpdateTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import com.anran2.util.JDBCUtils;
import org.junit.Test;

import java.io.InputStream;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Properties;

public class PreparedStatementUpdateTest{

//测试
@Test
public void testCommonUpdate(){
String sql = "delete from customers where id = ?";
update(sql,3);
}

//通用的增删改操作
public void update(String sql,Object ...args){//sql中的占位符的个数,与可变形参的长度一样
Connection conn = null;
PreparedStatement ps = null;
try{
//1.获取数据库连接
conn = JDBCUtils.getConnection();
//2.预编译sql语句,返回preparedStatement的实例
ps = conn.preparedStatement(sql);
//3.填充占位符
for(int i = 0; i < args.length; i++){
ps.setObject(i+1,args[i]);
}
//4.执行sql语句
ps.excute();
}catch(Exception e){
e.printStackTrace();
}finally{
//5.关闭资源
JDBCUtils.closeResource(conn,ps);
}

}
}

七、操作数据库,对其进行查询操作

PreparedStatementQueryTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import com.anran2.bean.Customer;
import com.anran2.bean.Order;
import com.anran2.util.JDBCUtils;
import org.junit.Test;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

public class PreparedStatementQueryTest{
//测试
@Test
public void testGetForList(){
String sql = "select id,name,email from customers where id < ?";
List<Customer> list = getForList(Customer.class,sql,12);
list.forEach(System.out::println);

String sql1 = "select order_id orderId,order_name orderName from `order` where order_id < ?";
List<Order> list1 = getForList(Order.class,sql1,5);
list1.forEach(System.out::println);
}

//针对不同表的查询操作,返回多条记录
public <T> List<T> getForList(Class<T> clazz,String sql,Object ...args){
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = JDBCUtils.getConnection();

ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1,args[i]);
}

rs = ps.executeQuery();
//获取结果集的元数据
ResultSetMetaData rsmd = rs.getMetaData();
//通过ResultSetMetaData获取结果集中的列数
int columnCount = rsmd.getColumnCount();
//创建集合对象
ArrayList<T> list = new ArrayList<T>();
while (rs.next()){
T t = clazz.newInstance();
//处理结果集一行数据中的每一个列:给t对象指定的属性赋值
for (int i = 0; i < columnCount; i++) {
//获取列值
Object columnvalue = rs.getObject(i+1);

//获取列名
String columnlabel = rsmd.getColumnLabel(i+1);

//给cust对象指定的columName属性,赋值为columvalue
Field filed = clazz.getDeclaredField(columnlabel);
filed.setAccessible(true);
filed.set(t,columnvalue);
}
list.add(t);
}
return list;
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.closeResource(conn,ps,rs);
}
return null;
}
}

至此原生的数据库操作就到此结束了。希望你们都能学会