一、优化之前代码
public class Select {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "root");
statement = connection.createStatement();
String sql = "select * from user_info";
resultSet = statement.executeQuery(sql);
while(resultSet.next()) {
String id = resultSet.getString("id");
String userName = resultSet.getString("user_name");
String password = resultSet.getString("password");
System.out.println(id+","+userName+","+password);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (resultSet!=null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (statement!=null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
二、第一次尝试优化代码(失败)
依据JDBC实现增删改过程代码优化的思路,定义一个方法,将查询功能的实现过程封装到该方法中以提高代码的复用性。代码如下:
public class Select {
public static ResultSet query(String sql) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "root");
statement = connection.createStatement();
return statement.executeQuery(sql);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (resultSet!=null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (statement!=null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
public static void main(String[] args) {
String sql = "select * from user_info";
try {
ResultSet resultSet = query(sql);
while(resultSet.next()) {
String id = resultSet.getString("id");
String userName = resultSet.getString("user_name");
String password = resultSet.getString("password");
System.out.println(id+","+userName+","+password);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
但是当运行该程序时,却报出如下错误,这又是为什么呢?下面是运行结果截图:
这是因为在ResultSet resultSet = query(sql)这句代码中,query(sql)方法执行完毕后,在finally代码块中已经释放了资源,所以会造成与数据库的连接已经关闭的结果,自然也就无法再向下执行程序。那么既然如此,在query方法中不关闭资源是不是就能解决问题呢?代码如下:
三、第二次尝试优化代码(可以实现,但是不推荐)
public class Select {
static Connection connection = null;
static Statement statement = null;
public static ResultSet query(String sql) {
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "root");
statement = connection.createStatement();
return statement.executeQuery(sql);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
String sql = "select * from user_info";
ResultSet resultSet =null;
try {
resultSet = query(sql);
while(resultSet.next()) {
String id = resultSet.getString("id");
String userName = resultSet.getString("user_name");
String password = resultSet.getString("password");
System.out.println(id+","+userName+","+password);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (resultSet!=null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (statement!=null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
下面是运行结果截图:
虽然这种改进方法可以实现功能,但是仍需要每次在main函数中写关闭资源的代码,代码的复用性仍然很差,那么有没有更好的改进方法呢?代码如下:
四、第三次尝试优化代码(推荐)
interface IRowMapper{//定义一个接口
void rowMapper(ResultSet rs);//接口中有一个抽象方法,该方法需要传入一个ResultSet类型的参数
}
public class Select {
public static void query(String sql,IRowMapper rowMapper) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "root");
statement = connection.createStatement();
resultSet = statement.executeQuery(sql);
rowMapper.rowMapper(resultSet);//多态
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (resultSet!=null) {
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (statement!=null) {
statement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (connection!=null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
String sql = "select * from user_info";
class RowMapper implements IRowMapper{//定义一个内部类实现该接口
@Override
public void rowMapper(ResultSet rs) {//重写抽象方法
try {
while(rs.next()) {
String id = rs.getString("id");
String userName = rs.getString("user_name");
String password = rs.getString("password");
System.out.println(id+","+userName+","+password);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
IRowMapper rowMapper = new RowMapper();//创建内部类对象
query(sql,rowMapper);
}
}
下面是运行结果截图:
上述方法利用多态和内部类巧妙地优化了JDBC实现查询过程的代码,既没有第一次尝试优化代码时出现的资源提早关闭造成无法继续执行程序的弊端,代码的复用性也得到了提高。推荐使用该方法。
运行过程分析:当我们想要实现查询功能时,首先需要在主函数中写SQL语句,然后创建接口实现类的对象(在接口实现类中实现接口中的抽象方法),调用query(sql,rowMapper)方法,然后在query方法中加载驱动,建立连接,
创建SQL语句,执行SQL语句,生成ResultSet类型的结果集,然后用一个变量记录住结果集的地址,然后调用rowMapper对象(此时为上转型对象)的rowMapper(resultSet)方法,此处出现了多态,实际运行时调用的是接口实现类中的rowMapper(resultSet)方法,然后执行主函数中的内部类中的该方法,将结果集中的内容遍历取出即可。