1. 使用 JDBC 时一般会有一句 Class.forName("xxx.xxx.xxx.xxx"); 的代码,问一下这句代码有什么作用?这行代码需要在每次获取 Connection 时都需要写么?
这一句的作用是加载一个类,并且注册 JDBC 驱动,但是这个方法没有注册驱动的功能。
我想大家应该都知道在类加载的过程中会初始化类中所有的静态部分,比如静态成员、静态代码块、静态方法,以及静态内部类。而 JDBC 规范规定,所有实现 java.sql.Driver 的驱动需要在类加载的过程使用 DriverManager.registerDriver 方法将自己注册给 DriverManager (详见 java.sql.Driver 的 API 文档),而大多数的 JDBC 驱动是在实现 java.sql.Driver 接口的驱动类的静态块中做这件事情的。
由于这里只需要加载一个类,并不需要生成这个类驱动类的实例的,因此就采用 Class.forName 方法来加载了,这样 JDBC 的驱动管理器才能使用这个驱动程序。
在实现 JDBC 4.0 规范的 JDBC 驱动不再这行代码了,当然了,你所使用 JDK 在 6.0 或以上版本才行。至于 JDBC 4.0 为什么可以不使用这种方式加载驱动,可以参考我在 5 楼的回复。
这一行代码并不需要每次写,这代码只需要在最初的地方写一次就可以了,虽然 JVM 保证一个类不会被加载两次,即便是这样,我们也不该每次都去写。
1. 为什么 JDBC 规范称从 javax.sql.DataSource 对象是获取连接的首选方法(javax.sql.DataSource 的 API 文档上有说),而不是从 java.sql.DriverManager 获取是首先方法?
javax.sql.DataSource 除了 DriverManager 固有的功能之外,还有其他的功能,比如:可以作为数据库连接池的实现,可以是基于分布式事务的实现。而且 DataSource 对象一般是从 JNDI 上查找而来,这样就能保证服务器迁移时数据库连接参数的修改不依赖于应用程序。
2. 如果让你设计一个数据库连接池,你可能会考虑到哪些方面的问题?
30 楼的朋友提到了很多,我再细化一下,当然了,这绝对不是连接池实现全部的问题:
a. 连接池需要实现前面提到的 javax.sql.DataSource 接口,以适合于不同的场合。
b. Connection#close 问题。使用者使用连接池与不使用连接池,除了从哪获得 Connection 对象不一样之外,其他 JDBC 的代码是完全相同的,并不能因为使用连接池而改变既有的 JDBC 代码。如果不能改变 JDBC 代码,就带来了一个 Connection close 的问题,大家都知道这个调用是关闭数据库连接,如果在连接池中这么做的话就会关闭连接,使用连接得不到重用。
c. 连接被动关闭问题。为了保证连接的复用性,将连接一直保存在池中。有些数据库服务器会将已经连接很久的客户端连接主动踢掉,如果碰到这种情况,在池中的这个连接池就会变为不可用状态,如果被客户端使用的话将会抛出连接被关闭的 SQLException。
d. 连接回收问题。假如我们的连接池最大设为 50 个,在某一并发很高的时段达到了 50 个,但是过后并发率就降下去了,对于连接池来说池中还是 50 个连接,实际上后面根本不需要那么多连接。这时连接池白白地浪费了几十个数据库宝贵的连接(数据库对于客户端的连接数是有限制的),如果连接池占用了很多的连接,那么可能会导致其他应用程序因为数据库客户端的连接数到了限制而无法再获得连接。我们应该及时地将不需要使用的连接关闭还给数据库服务器,保留一些基本连接数。
e. 网络中断重连问题。连接池中的连接在网络中断时,池中连接会全部断开,数据库服务端也会回收断开的连接。但是网络中断后,过了一些时间又连上了,这时池中的连接依然是断开的,如果取出来用的话,不用说就会抛出异常的。一个可用的连接需要有实现自动重连功能,否则就没有可用的价值。
3. 在 JDK 1.4 中引入了一个 NIO 的类库,使得 Java 涉及 IO 的操作拥有阻塞式和非阻塞式两种,问一下阻塞 IO 与非阻塞 IO 有什么区别?有什么优缺点?
在阻塞模式下,若从网络流中读取不到指定大小的数据量,阻塞 IO 就在那里阻塞着。比如,已经后面会有 10 个字节的数据发过来,但是我现在只收到 8 个字节,那么当前线程就在那傻傻地等到下一个字节的到来,对,就在那等着,啥事也不做,直到把这 10 个字节读取完,这才将阻塞放开通行。
在非阻塞模式下,若从网络流中读取不到指定大小的数据量,非阻塞 IO 就立即通行。比如,已经后面会有 10 个字节的数据发过来,但是我现在只收到 8 个字节,那么当前线程就读取这 8 个字节的数据,读完后就立即返回,等另外两个字节再来的时候再去读取。
从上面可以看出,阻塞 IO 在性能方面是很低下的,如果要使用阻塞 IO 完成一个 Web 服务器的话,那么对于每一个请求都必须启用一个线程进行处理。而使用非阻塞 IO 的话,一到两个线程基本上就够了,因为线程不会产生阻塞,好比一下接收 A 请求的数据,另一下接收 B 请求的数据,等等,就是不停地东奔西跑,直接到把数据接收完了。
虽然说,非阻塞 IO 比阻塞 IO 有更高的性能,但是对于开发来的,难度就成数倍递增了。由于是有多少数据就读取多少数据,这样在读取完整之前需要将已经读取到的数据保存起来,而且需要与其他地方来的数据隔离开来不能混在一起,否则就不知道这数据是谁的了,呵呵。