JDBC模型—深入理解JDBC设计思想(探究Class.forName("DBDriver"))
写在前面:笔者上篇文章《JDBC要点总结、SQL注入示例(Statement和PreparedStatement)》中提到过,JDBC是sun公司制定的一系列接口标准,由不同厂商(Oracle、MySQL等)实现接口方法并封装成驱动文件,供开发人员操作数据库。开发者可通过统一的代码操作不同类型数据库,那么如何实现这种统一操作呢?本篇深入JDBC设计思想,用示例代码模拟整个JDBC运行原理。
背景知识:
1.JVM(Java虚拟机)将系统分配的内存区域分为三块(堆区、栈区、方法区)
2.类的加载:当使用new 关键字新建一个对象,或使用Class.forName()加载指定类时,虚拟机读取类(.class)的字节码文件并加载到方法区。<由类加载器完成>
3.类在加载时,静态成员会被执行,包括静态成员被赋值,静态代码块被执行
补充:任何堆区的Java对象都有一个指针指向方法区中的class对象(每个类只有一个),即方法区共享了类的方法。
如以下代码段:
- Student s1 = new Student("张三");
- s1.study();
- Student s2 = new Student("李四");
- s2.study();
程序执行流程:
1.程序经过编译后,.java文件转换成字节码.class文件
2.执行Student s1 = new Student("张三");时:
a.JVM读取Student类的字节码文件并加载到方法区,生成class对象;
b.然后在堆区开辟内存区域初始化Student("张三")对象,该对象有一个指针指向方法区中的class对象;
c.在栈区分配一个变量s1,s1指向堆区Student("张三")对象的首地址;
3.执行s1.study();时,JVM通过堆区s1对象指向方法区的指针,找到class对象的方法并执行
4.执行Student s2 = new Student("李四");时,不会再加载并生成class对象(再次强调:同一个类只有一个class对象在方法区),但在堆区和栈区的操作同s1一样
图示如下:
接下来,我们来看看JDBC是如何实现对数据库的统一操作的
实现步骤:
1.sun公司制定标准接口
2.数据库厂商实现标准接口,并封装在定制的驱动文件中
3.开发者通过各厂商驱动文件对不同数据库操作
设计思想关键词:接口、类加载器、静态代码块
设计描述:
1.sun公司制定接口标准:Connection接口和DriverManager类(Connection接口提供操作数据库的抽象方法,待数据库厂商实现;DriverManager类提供给数据库厂商注册连接和获取连接的方法) 。
2.数据库厂商实现Connection接口中的方法(用来定义具体的数据库操作)
3.数据库厂商自定义驱动文件Driver类,将2中的连接注册到SUN提供的DriverManager中(此过程在静态代码块中,确保类被加载时即可执行)
4.程序员通过Class.for("");加载驱动文件,并获取连接,进而对数据库进行操作
示意图:
SUN公司:
首先,SUN公司定义了一个接口类:
- /**
- * @Description:sun公司定义的接口类
- *
- * @author:SUN
- */
- public interface Connection {
- public void f1();
- }
同时,SUN公司定义了一个驱动管理类:
- /**
- * @Description:SUN公司定义的驱动管理类
- *
- * @author:SUN
- */
- public class DriverManager {
- public static Connection conn = null;
- /**
- * 注册连接
- *
- * @param connection
- */
- public static void registConnection(Connection connection) {
- conn = connection;
- }
- /**
- * 获取连接
- *
- * @return
- */
- public static Connection getConnection() {
- return conn;
- }
- }
数据库厂商:(如Oracle、MySQL等)
各数据库厂商实现SUN制定的接口标准,如:
Oracle
- /**
- * @Description:Oracle数据库厂商实现的接口类
- *
- * @author:Oracle
- */
- public class ConnectionOracleImpl implements Connection {
- @Override
- public void f1() {
- // 这里实现Oracle操作数据库的具体方法,封装在.jar文件中,供程序员调用
- System.out.println("Oracle的f1()方法实现");
- }
- }
或者MySQL
- /**
- * @Description:MySQL数据库厂商实现的接口类
- *
- * @author:MySQL
- */
- public class ConnectionMySQLImpl implements Connection {
- @Override
- public void f1() {
- //这里实现MySQL操作数据库的具体方法,封装在.jar文件中,供程序员调用
- System.out.println("MySQL的f1()方法实现");
- }
- }
同时,数据库厂商定制自己的驱动类,并通过静态代码块,确保该驱动类被加载时,SUN的驱动管理类可以注册厂商的数据库连接,如:
Oracle
- /**
- * @Description:Oracle厂商制定的驱动类
- *
- * @author:Oracle
- */
- public class OracleDriver {
- static {
- DriverManager.registConnection(new ConnectionOracleImpl());
- }
- }
或者MySQL
- /**
- * @Description:MySQL厂商制定的驱动类
- *
- * @author:MySQL
- */
- public class MySQLDriver {
- static {
- DriverManager.registConnection(new ConnectionMySQLImpl());
- }
- }
开发者:
开发人员引入某个数据库厂商的驱动文件,即可调用内部方法操作数据库,如:
- /**
- * @Description:开发人员
- *
- * @author:me
- */
- public class Test2 {
- public static void main(String[] args) throws Exception {
- Class.forName("test.OracleDriver");// 虚拟机根据类名找到字节码文件
- Connection con = DriverManager.getConnection();
- con.f1();
- Class.forName("test.MySQLDriver");// 虚拟机根据类名找到字节码文件
- Connection con2 = DriverManager.getConnection();
- con2.f1();
- }
- }
运行结果:
Oracle的f1()方法实现
MySQL的f1()方法实现
转载请注明出处:
http://blog.****.NET/daijin888888/article/details/50969621