之前整理的jdbc流程并不完整,少了最后的关闭连接的操作,以及并没有对其中一些重复的流程进行优化。
int selectId = 3;
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://localhost:3307/study?useUnicode=true&characterEncoding=UTF-8", "root", "1234");
String sql = "SELECT id,`name`,age,gender FROM student WHERE id >= ?";
// PreparedStatement 使用预编译的sql
statement = connection.prepareStatement(sql);
// 填上 ?(占位符的值) parameterIndex 代表参数的索引(第几个参数)
statement.setInt(1, selectId);
System.out.println(statement);
resultSet = statement.executeQuery();
ArrayList<Student> list = new ArrayList<>();
while(resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
String gender = resultSet.getString("gender");
Student student = new Student(id, name, age, gender);
list.add(student);
}
for (Student student : list) {
System.out.println(student);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally { // 关闭连接
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
首先我们要注意的是,我们要再最后的finally语句中进行关闭连接操作(注意先打开的要后关闭),如果不把connection、statement和resultSet的定义放在前面的话,直接执行关闭连接操作会报错(也就是说要注意变量的作用域问题),以及注意局部变量一定要初始化(即这里的三个变量定义之后要先初始化)。
以及要在每一次执行关闭操作前判断非空,否则可能会发生空指针异常的问题。解释:例如在创建 connection 的过程中抛出了异常,因此 try 语句块中 该条语句后面的语句没有执行,相当于 statement 和 resultSet 并没有创建,仍是初始化时候的 null,此时如果不判断它们非空就会出现 null.close() ,即出现空指针异常。
对于整个流程的简单优化
上面流程中重复的操作较多,例如在每次对数据库执行增删改查操作的时候,都要进行类加载,创建连接以及最后的关闭连接等操作,且在每一次执行增删改查操作的时候,这些代码基本没有改变,所以可以把它们封装到另一个我们自定义的工具类中,然后在要使用的时候,直接调用相应方法即可,可以省去很多重复的代码。工具类的定义如下:
import java.sql.*;
public class JDBCUtil {
private JDBCUtil() {
}
// 静态代码块 只执行一次,保证这个驱动只加载一次
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3307/study?useUnicode=true&characterEncoding=UTF-8", "root", "1234");
return connection;
}
public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
// 先打开的后关闭
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
流程优化后的jdbc操作
int selectId = 3;
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = JDBCUtil.getConnection();
String sql = "SELECT id,`name`,age,gender FROM student WHERE id >= ?";
// PreparedStatement 使用预编译的sql
statement = connection.prepareStatement(sql);
// 填上 ?(占位符的值) parameterIndex 代表参数的索引(第几个参数)
statement.setInt(1, selectId);
System.out.println(statement);
resultSet = statement.executeQuery();
ArrayList<Student> list = new ArrayList<>();
while(resultSet.next()) {
int id = resultSet.getInt("id");
String name = resultSet.getString("name");
int age = resultSet.getInt("age");
String gender = resultSet.getString("gender");
Student student = new Student(id, name, age, gender);
list.add(student);
}
for (Student student : list) {
System.out.println(student);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally { // 关闭连接
JDBCUtil.close(connection, statement, resultSet);
}