1. JDBC程序访问数据库步骤?
2.JDBC的驱动注册分析:
有多种方式,这儿只说下最主流的一种实现方式:
// 1. 加载驱动,
// 该方法会触发驱动类的加载
Class.forName(driverClass);
// 2. 获取连接
Connection conn = DriverManager.getConnection(url, user, password);
Class.forName()触发类的加载,类加载的初始化过程中会调用static方法块的代码,数据库驱动的注册就在该static块中。以mysql为例,源码如下:
package com.mysql.jdbc;
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
// 基本功,类加载<clint>方法会执行静态代码块
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
3. JDBC中PreparedStatement和Statement 相比优势在于?
- PreparedStatement代码的可读性和可维护性强
- PreparedStatement可以防止SQL注入
- PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL
语句,能最大可能提高性能(代码缓存)
4. 说说数据库连接池工作原理和实现方案?
工作原理:数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。
实现方案:返回的Connection是原始Connection的代理,代理Connection的close方法,当调用close方法时,不是真正关连接,而是把它代理的Connection对象放回到连接池中,等待下一次重复利用。
5.数据库事务获取connection用到了threadlocal,事务结束后需要手动清空threadLock中数据吗?
需要,如果Thread是从Thread Pool中拿出来的,那么意味着Thread可能会被复用,如果被复用,你就一定得保证这个Thread上一次结束的时候,其关联的ThreadLocal被清空掉,否则就会串到下一次使用。
同理,对于hreadlocal线程结束会不会释放当前线程的数据这个问题? 答案是线程复用的情况下不会清空。
总结: 在使用 ThreadLocal 时,当使用完变量后,必须手动调用 remove() 方法删除 entry 对象,否则会造成 value 的内存泄露,严格来说,ThreadLocal 是没有内存泄漏问题,有的话,那也是忘记执行 remove() 引起的,这是使用不规范导致的。
/**
* 释放连接(两步,必不可少)
* 1. 调用connection的close()方法, 将connection放回连接池
* 2. 调用threadLocal的remove方法将数据清除, 线程返回线程池
*/
public void release(){
try {
connectionUtils.getThreadConnection().close(); //还回连接池中
threadLocal.remove();
}catch (Exception e){
e.printStackTrace();
}
}
最后: 什么是JDBC的最佳实践?
- 数据库资源是非常昂贵的,用完了应该尽快关闭它。Connection, Statement,
ResultSet等JDBC对象都有close方法,调用它就好了。 - 养成在代码中显式关闭掉ResultSet,Statement,Connection的习惯,如果你用的是连接池的话,连接用完后会放回池里,但是没有关闭的ResultSet和Statement就会造成资源泄漏了。
- 在finally块中关闭资源,保证即便出了异常也能正常关闭。
- 尽量使用PreparedStatement而不是Statement,以避免SQL注入,同时还能通过预编译和缓存机制提升执行的效率。