MySQL学习笔记(4)--JDBC异常处理和工具类抽取

一:异常处理

在前面的学习中,所有的异常全部都是使用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);
    }
}

猜你喜欢

转载自blog.csdn.net/zyrdfly/article/details/82694176