JDBC全称JAVA DATABASE Connectivity,是java提供的用于执行SQL语句的java api,提供关系型数据库的访问,其中使用最多的便是java.sql包中的相关接口和类
DriverManagement 用于管理一组JDBC驱动的基本服务,其中可以调用加载过的驱动来进行连接
那么最熟悉的也就是jdbc的第一句话:
Class.forName(“blablabla”);那么这句话究竟是起到什么作用了? Class类是java类型中的表述类型信息,用于创建所有的常规对象。每个类都有一个class对象,为了生成这个类的对象,运行这个程序的jvm将使用类加载器。ForName是这个类的一个静态方法,能够根据填入的类的全限定名来查询到对应的.class文件,将其加载,在加载的过程中这个类的所有静态方法会被执行,例如:
这样的一个对象 那么我们去加载一下他
可以看到,类中的静态块被执行,但是构造函数等均没有执行,因为只做了加载操作,并没有执行其他操作,而所有的方法执行之前,都会进行class的加载。
那么回到正题,加载数据库驱动有什么作用呢? 我们知道,java.sql中有一个接口叫做Driver,那么这个是给各个数据库厂商(mysql、oracle等)来提供统一的接口
可以看到,mysql提供的驱动也要实现java.sql包中的driver接口,那么当我们让类加载器加载了mysql驱动的包之后,就相当于加载了一个java.sql的驱动,那么我们知道,驱动通过forName加载是会执行类中的静态块方法,所以mysql驱动下的静态块会被执行
这个方法将自身注册到DriverManager中,就完成了整个驱动的初始化,因此,尽管没有与driverManager进行任何连接,也可以直接在drivermanager中获得连接进行数据库操作
但是这里产生个问题,如果我们把class.forName注释掉,依然能够获取想要的数据,既然没有加载,为什么也会这样呢?这里关系到一个叫做SPI(service provider interface)的机制,一个简单的服务提供商加载工具。简单来讲,通过配置在资源文件中的META-INF/services来提供加载服务,通过文件名的全限定名来定位接口,而实现类按行写在文件中,例如mysql的spi:
这是mysql的spi文件,在jar包的META-INF/services下,里面定义了实现这个接口的两个类:分别是driver和fabricmysqldriver,那么高版本的mysql可以通过这种方式加载。 也就代替了Class.forName()的作用,也就是说ServiceLoader会向jar包读取这个文件并加载,那么加载的时间是什么时候呢?这是一个惰性加载,属于用的时候才会加载,也就是说在DriverManager被加载的时候,
这句话,那么会先执行DriverManager中的静态块:
那么在调用堆栈中就可以看到ServiceLoader的影子
在调用的时候自动加载,这也是不用Class.forName()就能够加载驱动的原因,而在java的api文档中也有说明: DriverManager方法getConnection和getDrivers已得到增强,以支持Java Standard Edition Service Provider机制。 JDBC 4.0驱动程序必须包含文件META-INF/services/java.sql.Driver 。 该文件包含java.sql.Driver的JDBC驱动程序实现的java.sql.Driver 。 例如,要加载my.sql.Driver类, META-INF/services/java.sql.Driver文件将包含条目: my.sql.Driver
常用方法: getConnection(url,username,password),驱动加载后,这些加载就能找到指定的驱动进行加载啦!而如果我们需要更换驱动,只需要更换对应的driver包,不需要更改代码就能实现新的数据库的连接。那么利用jdbc进行数据库的更换也是非常简单的,不需要额外工作,顶多更改Class.forName()中加载的类名,而高版本的驱动不需要加载便可以直接使用
这个就是我们的连接类了,可以理解为session(会话),也就是这个对象就是我们和数据库之间的连接,打开了可以进行多次访问,访问结束就要对其进行关闭。
Close(),释放资源,最好在释放之前进行submit或rollback操作,这样能够更好的操纵数据的事物
CreateStatement(),用于执行静态SQL语句并返回其生成的结果的对象。这个就是我们执行语句的关键对象了,将稍后进行讲解。
用于语句执行返回结果对象,一般返回ResultSet(结果集)、int(作用条数)等,而常用方法则 Excute(sql)、excuteQuery(sql)、excuteUpdate(sql) Excute(sql),返回值为boolean,如果true,则语句查询结果为结果集,若为false,则查询结果为更新计数或没有结果,那么可以据此判断是否需要拿出结果集或判断计数。getResultSet() , getUpdateCount() , getMoreResults()这三个函数则为与这个函数绑定使用,用于获得语句执行结果
excuteQuery(sql)执行给定的SQL语句,返回单个ResultSet对象,通常使用的语句为静态select!!!,而返回的结果集也不可能不可能不可能产生null,就算没有查询到结果,也会返回一个空的结果集,通过isEmpty来进行查看
excuteUpdate(sql)执行给定的SQL语句,这可能是INSERT , UPDATE ,或DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句。
从这个可以看出,如果能够判断语句的类型,采用excuteQuery、excuteUpdate是比较方便的,能够简化判断,直接拿到想要的结果,而如果不知道插入的语句是什么,就要去使用excute函数,对返回结果的判断来决定是获取结果集还是获取更新计数。那么通过excute函数的特点,可以发现,resultset是与statement绑定的,也就是说你无法在一个结果集还在使用的时候去再次用同一个statement对象进行查询,这样结果集就会报错 上面的例子,在结果集还在获取数据的时候,再次执行了操作,我们的控制台:
在结果集关闭之前,不允许下一步操作 也就是说statement与resultset是一一对应的,你无法在一个结果集操作的过程中更新结果集,那么这样可以吗?
答案是可以的,因为结果集已经到了末尾,因此可以进行下一步操作 在java api中也是如此规定的: 默认情况下,每个Statement对象只能有一个ResultSet对象同时打开。 因此,如果一个ResultSet对象的读取与另一个对象的读取交错,则ResultSet对象必须由不同的Statement对象生成。
Jdbc 2.0 在java 的DriverManager中提到, JDBC 2.0 API中新增的DataSource接口提供了另一种连接到数据源的方法。 使用DataSource对象是连接到数据源的首选方法。那么DataSource是做什么用的?
DataSource 一个连接到这个DataSource对象所代表的物理数据源的工厂。 DriverManager设备的DriverManager , DataSource对象是获取连接的首选方法。 实现DataSource接口的对象通常将基于Java“命名和目录(JNDI)API”的命名服务注册。
这个接口只有两个方法:
但是却给我们提供了管理连接池、管理数据源的功能,能够将DriverManager封装在getConnection中,可以直接修改数据源的属性而不需要修改访问数据源的代码