你一眼就看懂的手写JDBC底层实现原理!

news/2024/5/19 2:10:15 标签: 数据库, mysql, java, jdbc

最近在学习Spring框架技术,其中JDBC技术常常被用到,但是在框架中使用的JDBC技术都是经过封装过后的,我们直接可以进行SQL语句的CRUD操作。
这样虽然方面了我们操作,但若是我们想彻底理解JDBC底层实现原理,还是应该将整个流程原始的写下来,这样有利于我们了解JDBC底层的实现技术。 话不多说,我们开始吧!

概述

在 Java 中,数据库存取技术可分为如下几类:
1.JDBC 直接访问数据库
2.JDO 技术(Java Data Object)
3.第三方 O/R 工具,如 Hibernate, Mybatis 等 JDBC 是 java 访问数据库的基石,JDO, Hibernate 等只是更好的封装了 JDBC。

一、什么是 JDBC?

JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统(DBMS)、通用的 SQL 数据库存取和操作的 公共接口(一组 API),定义了用来访问数据库的标准 Java 类库,使用这个类库可以以一种标准的方法、方便地访 问数据库资源 JDBC 为访问不同的数据库提供了一种统一的途径, 为开发者屏蔽了一些细节问题。 JDBC 的目标是使 Java 程序员使用 JDBC 可以连接任何提供了 JDBC 驱动程序数据库系统,这样就使得程序员无需 对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。

如果没有 JDBC,那么 Java 程序访问数据库时是这样的:
在这里插入图片描述
改装:
在这里插入图片描述

实际上:
在这里插入图片描述

结论:

JDBC 是 SUN 公司提供一套用于数据库操作的接口 API,Java 程序员只需要面向这套接口编程即可。 不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。

2、JDBC API
JDBC API 是一系列的接口,它统一和规范了应用程序与数据库的连接、执行 SQL 语句,并到得到返回结果等各类操 作。声明在 java.sql 与 javax.sql 包中。

在这里插入图片描述
3、JDBC 程序编写步骤
在这里插入图片描述

二、使用 JDBC API

1.1 如何获取 JDBC 驱动程序
驱动程序由数据库提供商提供下载。 MySQL 的驱动下载地址:http://dev.mysql.com/downloads/

1.2 如何在 Java Project 项目应用中添加数据库驱动 jar

导入JAR包
在这里插入图片描述
2、加载并注册驱动
加载并注册驱动: 加载驱动,把驱动类加载到内存 注册驱动,
把驱动类的对象交给 DriverManager 管理,
用于后面创建连接等使用。

2.1 Driver 接口
Java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库 厂商提供不同的实现

在这里插入图片描述
2.2 编写加载与注册驱动的代码

1)直接创建 Driver 接口的实现类对象
例如:

java">Driver driver = new com.mysql.jdbc.Driver();
//因为与 mysql 驱动包中的类发生直接依赖,所以这样可移植性不够好

2)DriverManager 类的 registerDriver()

在实际开发中,程序中不直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager) 去调用这些 Driver 实现。
DriverManager 类是驱动程序管理器类,负责管理驱动程序。

java">//DriverManager.registerDriver()方式注册驱动,还是依赖 
DriverManager.registerDriver(new com.mysql.jdbc.Driver());

3)Class.forName()或 ClassLoader 对象.loadClass()
因 为 Driver 接 口 的 驱 动 程 序 类 都 包 含 了 静 态 代 码 块 , 在 这 个 静 态 代 码 块 中 , 会 调 用 DriverManager.registerDriver() 方法来注册自身的一个实例,所以可以换一种方式来加载驱动。
(即只要想办 法让驱动类的这段静态代码块执行即可注册驱动类,
而要让这段静态代码块执行,只要让该类被类加载器加载即可)。

在这里插入图片描述
调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名
在这里插入图片描述
4)服务提供者框架(例如:JDBC 的驱动程序)自动注册(有版本要求)
符合 JDBC 4.0 规范的驱动程序包含了一个文件 META-INF/services/java.sql.Driver,在这个文件中提供了 JDBC 驱动实 现的类名。
例如:mysql-connector-java-5.1.40-bin.jar 文件中就可以找到 java.sql.Driver 文件,用文本编辑器打开文件 就可以看到:com.mysql.jdbc.Driver 类

三、获取数据库链接

可以通过 DriverManager 类建立到数据库的连接 Connection: DriverManager 试图从已注册的 JDBC 驱动程序集中选择一个适当的驱动程序。

java">public static Connection getConnection(String url) 
public static Connection getConnection(String url,String user, String password) 
 public static Connection getConnection(String url,Properties info)

3.1 JDBC URL
JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据 库的连接。
JDBC URL 的标准由三部分组成,各部分间用冒号分隔。
在这里插入图片描述
在这里插入图片描述

java">//1、加载与注册驱动 Class.forName("com.mysql.jdbc.Driver");
 //2、获取数据库连接 
 String url = "jdbc:mysql://localhost:3306/test"; 
 Connection conn = DriverManager.getConnection(url, "root", "root"); 
 //硬编码

3.2 jdbc.properties
在 src 下建立文件 jdbc.properties,当然也可以是其他名字,只不过这里为了见名知意取这个名 通常至少应该包括 “user” 和 “password” 属性

java">#key=value driver=com.mysql.jdbc.Driver 
url=jdbc:mysql://localhost:3306/test
java">user=root 
password=root
java">public static void main(String[] args) throws Exception { //预先加载配置文件 jdbc.properties,把配置信息封装到 Properties 对象中 
Properties pro = new Properties();
 //ClassLoader 只能加载类路径下的资源文件 //如果不是类路径下,只能使用 FileInputStream pro.load(ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties"));
  //1、加载与注册驱动 Class.forName(pro.getProperty("driver")); //2、获取数据库连接 //
   Connection conn = DriverManager.getConnection(pro.getProperty("url"), pro); Connection conn = DriverManager.getConnection(pro.getProperty("url"), 
   pro.getProperty("user"),pro.getProperty("password")); 
   System.out.println(conn); }
    //解决了硬编码的问题

四、操作或访问数据库

数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。
其实一个数据库连接就是一个 Socket 连接。
java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:
在这里插入图片描述
4.1 Statement

通过调用 Connection 对象的 createStatement() 方法创建该对象 该对象用于执行静态的 SQL 语句,并且返回执行结果 Statement 接口中定义了下列方法用于执行 SQL 语句:

在这里插入图片描述
4.2 ResultSet

通过调用 Statement 对象的 excuteQuery() 方法创建该对象 ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商实现 ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行

ResultSet 接口的常用方法:

1. boolean next()
2. getXxx(String columnLabel)

5、释放资源

Connection、Statement、ResultSet 都是应用程序和数据库服务器的连接资源,使用后一定要关闭,可以在 finally 中 关闭

未关闭后果

java">@Test public void testConnection4()throws Exception{ 
Properties pro = new Properties(); pro.load(ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties"));
 String url = pro.getProperty("url");
  //my.ini 中 
 max_connections=10 for (int i = 0; i < 15; i++) {
  Connection conn = DriverManager.getConnection(url,pro
  );
   System.out.println(conn); 
  //没有关闭,资源一直没有释放
   } 
   }

下面附上一个完整的手写JDBC增、删、改、查的操作。

一、导包

在这里插入图片描述

二、JDBC配置文件

在这里插入图片描述

三、连接

java">package JDBC.Text;
import java.io.InputStream;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import org.junit.Test;
import com.mysql.jdbc.Connection;
public class PreparedStatementUpdateTest {
	/*
	 * 使用PreparedStatement来替换Statement,实现对数据表的增删改操作。
	 */
	@Test
	public void textInserect() {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			InputStream is = ConnectionText.class.getClassLoader().getResourceAsStream("jdbc.properties");
			//Properties类:用于获取java中的各种配置参数。
			Properties pros = new Properties();
			//加载文件流。
			pros.load(is);
			//写入四种基本参数。
			String user = pros.getProperty("user");
			String password = pros.getProperty("password");
			String url = pros.getProperty("url");
			String driverClass = pros.getProperty("driverClass");
			//2.加载驱动
			Class.forName(driverClass);
			//3.获取连接
			conn = (Connection) DriverManager.getConnection(url, user, password);
			//		System.out.println(conn);

			//预编译sql语句,返回PreparedStatement的实例
			String sql = "insert into customers(name,email,birth)values(?,?,?)"; //?为占位符
		    ps = conn.prepareStatement(sql);
			//5.填充占位符
			ps.setString(1, "梁登峰");
			ps.setString(2, "afeng@gmail.com");
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			java.util.Date date = sdf.parse("2000-08-03");
			ps.setDate(3, (java.sql.Date)new Date(date.getTime()));
		} catch (Exception e) {
		e.printStackTrace();
		}finally {
			try {
				if(ps!=null)
			    ps.close();
			}catch(SQLException e) {
				e.printStackTrace();
			}
			try {
				if(conn!=null)
			    conn.close();
			}catch(SQLException e) {
				e.printStackTrace();
			}
		}
	}
	
}

四、编写通用配置类

java">package Utils;
/*
 * 封装
 */
import java.io.IOException;
import java.io.InputStream;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

import com.mysql.jdbc.Connection;

public class JDBCutils {
	//得到连接数据库的示例。
	public static Connection getConnection()  {
	//3.获取连接
	Connection conn = null;
	try {
		InputStream is=	ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
		//Properties类:用于获取java中的各种配置参数。
		Properties pros = new Properties();
		//加载文件流。
		pros.load(is);
		//写入四种基本参数。
		String user = pros.getProperty("user");
		String password = pros.getProperty("password");
		String url = pros.getProperty("url");
		String driverClass = pros.getProperty("driverClass");
		//2.加载驱动
		Class.forName(driverClass);
		conn = (Connection) DriverManager.getConnection(url, user, password);
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	} catch (SQLException e) {
		e.printStackTrace();
	}
	return conn;	
	}
	//关闭资源。
	public static void closeResource(java.sql.Connection conn,Statement ps) {
		try {
			if(ps!=null)
		    ps.close();
		}catch(SQLException e) {
			e.printStackTrace();
		}
		try {
			if(conn!=null)
		    conn.close();
		}catch(SQLException e) {
			e.printStackTrace();
		}
	}
	public static void closeResource(Connection conn,Statement ps,ResultSet rs) {
		try {
			if(ps!=null)
		    ps.close();
		}catch(SQLException e) {
			e.printStackTrace();
		}
		try {
			if(conn!=null)
		    conn.close();
		}catch(SQLException e) {
			e.printStackTrace();
		}
		try {
			if(rs!=null)
				rs.close();
		}catch(SQLException e) {
			e.printStackTrace();
		}
	}
	
}



五、编写通用SQL语句进行对数据库的操作

java">* 通用的增删该操作方法
 */
public class JDUCcommonUpdate {
	public void update(String sql,Object ...args) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			//1.连接数据库
			conn = JDBCutils.getConnection();
			//2.预处理sql命令。
			ps = conn.prepareStatement(sql);
			//3.填充占位符。
			for(int i=0;i<args.length;i++)
			{	
				ps.setObject(i+1, args[i]); //注意: 形参格式容易出错。
			}
			//4.执行命令
			ps.execute();
		} catch (SQLException e) {
		
			e.printStackTrace();
		}finally {
		JDBCutils.closeResource(conn, ps);
		}
	}
	
	
	//数据插入
@Test
public void test1() {
	String sql = " insert into users(name,address)values(?,?)";
	update(sql,"龙普润","123456");
	
}
//数据更改
@Test
public void test2() {
	String sql ="update users set name= ? where id = ?";
	update(sql,"王选明",1);
}
//数据删除。
@Test
public void test3() {
	String sql ="delete from users where name=?";
	update(sql,"梁登峰");
	
}

}

希望对你有所帮助。

对生活有态度,对技术有追求、咱们下期见!


http://www.niftyadmin.cn/n/1490604.html

相关文章

看完这篇AOP入门解析,不懂你来打四我。

最近在学习Spring框架&#xff0c;总结后有所收获&#xff0c;现在尽量用通俗易懂的语言讲明白Spring框架核心之一 AOP&#xff08;面向切面编程&#xff09; 技术&#xff0c;在巩固自己知识的同时也希望对你有所帮助&#xff01; 话不多说&#xff0c;直接进入正文。 1、什么…

知识小结-06反射reflect的深入理解

1、interface 和 反射 先来看看Golang关于类型设计的一些原则,变量包括(type, value)两部分,理解这一点就知道为什么nil != nil了。 在Golang的实现中,每个interface变量都有一个对应pair,pair中记录了实际变量的值和类型: (value, type) value是实际变量值,type是实…

系统报:--->‘Tomcat8.5‘: port out of range:-1错误的解决方法

解决答案在这里&#xff1a; Error running ‘Tomcat 9.0.241’: port out of range:-1 修改默认配置&#xff0c;tomcat的server.xml检查一下&#xff0c;端口不能是-1, 数值在1-65535之间的任意一个整数&#xff0c;一般会选大于1024的&#xff0c;小于1024的一般被本地计算…

知识小结-08computed和watch的区别

区别一&#xff1a; &#xff08;1&#xff09;computed特性 1.是计算值&#xff0c; 2.应用&#xff1a;就是简化tempalte里面{{}}计算和处理props或$emit的传值 3.具有缓存性&#xff0c;页面重新渲染值不变化,计算属性会立即返回之前的计算结果&#xff0c;而不必再次执行函…

TomCat服务器的一个小问题

有的同学再启动Tomcat的时候会出现 淇℃伅 [main] org.apache.catalina.startup.VersionLoggerListener.log Server.鏈嶅姟鍣ㄧ増鏈&#xfffd;: 这种乱码的错误&#xff0c;虽然不影响启动和使用&#xff0c;但看着就很烦 解决这种乱码的问题&#xff0c;解决问题的方法是…

入门IOC解析

前天总结了一下Spring框架中AOP的原理和作用&#xff0c;今天来总结一下另一核心—>IOC&#xff08;控制反转&#xff09; 废话不多说&#xff0c;直接进入正题 IOC&#xff08;概念和原理&#xff09; 1、什么是 IOC&#xff1f; &#xff08;1&#xff09;控制反转&…

知识小结-09echarts的使用

echarts按需引入 // 引入基本模板 let echarts require("echarts/lib/echarts");// 引入柱状图组件 require("echarts/lib/chart/bar");// 引入提示框和title组件 require("echarts/lib/component/tooltip"); require("echarts/lib/compo…

知识小结-11Vue实现对数组、对象的深拷贝、复制

https://www.cnblogs.com/skura23/p/7072113.html 解决浅拷贝问题&#xff1a; let productLine JSON.parse(JSON.stringify(item));