0
点赞
收藏
分享

微信扫一扫

深入理解jdbc

笙烛 2021-09-21 阅读 86

JDBC 驱动

JDBC 是 Java 应用程序中用于访问数据库的一套标准 API,Sun 公司定义了4种类型的 JDBC 驱动,我公司主要用的是第4种,该类型驱动由纯 Java 语言编写,在 Java 应用中通过 socket 与数据库通信。

类型4驱动是通过 socket 来处理字节流的,它的基本操作和 HttpClient 这种网络操作类库相同。如果你之前用过 HttpClient ,肯定遇到过因为没有设置超时导致的错误。如果 socket 超时设置不合适,类型4驱动也可能有同样的错误(连接被阻塞)。

什么是 Socket 超时

类型4的 JDBC 驱动是用 Socket 方式与数据库连接的,应用程序和数据库之间的连接超时并不是由数据库处理的。

当数据库突然宕掉或发生网络错误(设备故障等)时,JDBC 驱动的 Socket 超时的值是必须的。由于 TCP/IP 的结构,Socket 没有办法检测到网络错误,因此应用不能检测到与数据库到连接断开了

如果没有设置 Socket 超时,应用程序会一直等待数据库返回结果。(这个连接也被叫做“死连接”) 为了避免死连接,Socket 必须要设置超时时间。Socket 超时可以通过 JDBC 驱动程序配置。通过设置 Socket 超时,可以防止出现网络错误时一直等待的情况并缩短故障时间。

下面展示了 Socket 超时设置的连个选项,其配置因不同的驱动而异。

  • Socket 连接时的超时:通过 Socket 对象的 connect(SocketAddress endpoint, int timeout) 方法来配置
  • Socket 读写时的超时:通过 Socket 对象的 setSoTimeout(int timeout) 方法来配置

通过查看MySQL 的JDBC 驱动源码,我们确认以上所有驱动都是使用上面的2个 API 来设置socket 超时的。

connectTimeout 和 socketTimeout 的默认值是 0 ,这意味着不会发生超时。

操作系统层面的 Socket 超时配置

如果没设置 Socket 超时或连接超时,应用程序多数情况下无法检测到网络错误。此时,应用程序将一直等待下去,直到连接上数据库或能读取到数据。然而,如果查看实际服务遇到的实际情况会发现问题常常在在应用程序在30分钟后尝试重新连接到网络后被解决了。这是因为操作系统也配置了 Socket 超时时间。我公司使用的 Linux 服务器将 Socket 超时时间设置为30分钟。它将在操作系统层面对网络连接做校验。因为公司的 Linux 服务器的 KeepAlive 检查周期为30分钟,因此即使应用程序里将 Socket 超时设置为0,由网络原因引起的数据库网络连接问题也不会超过30分钟。(keep alive机制)

jdbc socket timeout

设置的是jdbc I/O socket read and write operations的超时时间,防止因网络问题或数据库问题,导致driver一直阻塞等待

statement timeout(也相当于result set fetch timeout)

设置的是一个statement的执行超时时间,即driver等待statement执行完成,接收到数据的超时时间(注意statement的timeout不是整个查询的timeout,只是statement执行完成并拉取fetchSize数据返回的超时,之后resultSet的next在必要的时候还会触发fetch数据,每次fetch的超时时间是单独算的,默认也是以statement设置的timeout为准)

transaction timeout

设置的是一个事务的执行时间,里头可能包含多个statement

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()方法实现

举报

相关推荐

0 条评论