一:异常处理
在前面的学习中,所有的异常全部都是使用throws方法解决的,现在尝试将异常在程序内部进行处理。
为什么要在程序内部处理异常?
因为采用throws方法,一旦产生异常,程序会停止运行,并将异常抛出,但是此时程序内的资源并没有释放出来,而Connection对象资源是非常宝贵的,所以要使用try…catch…finally语句在程序内部处理异常,即使异常产生了,也能保证资源被释放。
解决思路依然是四个步骤
1、连接驱动
2、获取连接
3、处理数据
4、释放资源
实现代码:
@Test
public void test_jdbc() {
// 1. 装载驱动
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("驱动加载失败!");
}
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 2. 建立连接
conn = DriverManager.getConnection("jdbc:mysql:///mydb", "root", "123");
// 3. 操作数据
String sql = "select * from user;";
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " : " + username + " : " + password + " : " + email);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 4. 释放资源
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
二 :工具类抽取
通过前面的学习,发现通过Java程序对数据库进行访问的时候,无论进行什么操作,总体来说就是加载驱动、获取连接、处理数据和释放资源这四个步骤。
其中,除了操作数据这个步骤不同之外,其他三个步骤都是一样的,考虑将代码提取出来进行封装,提高代码的复用性。
实现方法:
将加载驱动、获取连接、释放资源三个所有操作共有的方法包装成一个工具类,将方法都定义成静态方法,使用的时候直接通过类名调用。
实现代码:
工具类:JDBCUtils
import java.sql.*;
// 硬编码 : 将数据写死在 `类` 中, 而不是将数据写在配置文件中.
public class JDBCUtils {
// 属性 (数据)
private static final String driverClass = "com.mysql.cj.jdbc.Driver";
private static final String url = "jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC&characterEncoding=UTF-8";
private static final String username = "root";
private static final String password = "123456";
// 1. 加载驱动
public static void loadDriver() {
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
// 说明 : 如果驱动加载失败, 之后的所有操作就无需继续执行了...
throw new RuntimeException("驱动加载失败!");
}
}
// 2. 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
// 3. 释放资源
public static void release(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null; // clear to let GC do its work
}
// 调用下面的方法实现 conn, stmt
release(conn, stmt);
}
public static void release(Connection conn, Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
测试类
@Test
public void test1() {
// 1. 加载驱动
JDBCUtils.loadDriver();
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 2. 获取连接
conn = JDBCUtils.getConnection();
// 3. 操作数据
String sql = "select * from user where id < 10;";
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " : " + username + " : " + password + " : " + email);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 4. 释放资源
JDBCUtils.release(conn, stmt, rs);
}
}
@Test
public void test2() {
// 1. 加载驱动
JDBCUtils.loadDriver();
Connection conn = null;
Statement stmt = null;
try {
// 2. 获取连接
conn = JDBCUtils.getConnection();
// 3. 操作数据
String sql = "update user set username='赵六', email='[email protected]' where id = 4;";
stmt = conn.createStatement();
int count = stmt.executeUpdate(sql);
System.out.println("count = " + count);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 4. 释放资源
JDBCUtils.release(conn, stmt);
}
}
工具类提高了代码的复用性问题,但是这个还能再进行优化
// 属性 (数据)
private static final String driverClass = "com.mysql.cj.jdbc.Driver";
private static final String url = "jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC&characterEncoding=UTF-8";
private static final String username = "root";
private static final String password = "123456";
我们发现,是程序中的所有属性都是固定的,一旦其中一个属性发生变化,这个工具类就不能再用了,这种包装方法叫硬编码。我们可以考虑将属性的赋值写到配置文件中去,当属性改变的时候我们只需要更改配置文件即可继续使用这段代码,提高代码的通用性。这种叫软编码。
首先,创建配置文件给工具类的属性进行赋值
mydb.propertises
driverClass = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC&characterEncoding=UTF-8
username = root
password = 123456
工具类代码实现:
静态代码块的特点 :
1. 类加载时, 自动执行静态代码块.
2. 静态静态块仅会被执行一次, 因为类只会被虚拟机加载一次.
public class JDBCUtils {
// 属性 (数据)
// 静态属性如果使用 final 修饰, 还可以在 `静态代码块中` 实现赋值
private static final String driverClass;
private static final String url;
private static final String username;
private static final String password;
// 静态代码块 :
static {
// 1. 创建一个 Properties 对象.
Properties prop = new Properties();
try {
// 2. 加载配置文件数据到 prop 对象中
prop.load(new FileReader("jdbc.properties"));
// 3. 如果加载成功, 为静态属性赋值
driverClass = prop.getProperty("driverClass");
url = prop.getProperty("url");
username = prop.getProperty("username");
password = prop.getProperty("password");
// 加载驱动
loadDriver();
} catch (IOException e) {
// 注意 : 配置文件如果加载失败, 直接抛出一个运行时异常
throw new RuntimeException("配置文件加载失败!");
}
}
// 1. 加载驱动
private static void loadDriver() {
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
// 说明 : 如果驱动加载失败, 之后的所有操作就无需继续执行了...
throw new RuntimeException("驱动加载失败!");
}
}
// 2. 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
// 3. 释放资源
public static void release(Connection conn, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null; // clear to let GC do its work
}
// 调用下面的方法实现 conn, stmt
release(conn, stmt);
}
public static void release(Connection conn, Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
测试类
@Test
public void test1() {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1. 获取连接
conn = JDBCUtils.getConnection();
// 2. 操作数据
String sql = "select * from user where id < 10;";
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt("id");
String username = rs.getString("username");
String password = rs.getString("password");
String email = rs.getString("email");
System.out.println(id + " : " + username + " : " + password + " : " + email);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 3. 释放资源
JDBCUtils.release(conn, stmt, rs);
}
}
@Test
public void test2() {
Connection conn = null;
Statement stmt = null;
try {
// 1. 获取连接
conn = JDBCUtils.getConnection();
// 2. 操作数据
String sql = "update user set username='赵六', email='[email protected]' where id = 4;";
stmt = conn.createStatement();
int count = stmt.executeUpdate(sql);
System.out.println("count = " + count);
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 3. 释放资源
JDBCUtils.release(conn, stmt);
}
}