dljd_006_关于jdbc关闭连接问题的发散
一、数据库连接的示例
package edu.aeon.jdbc; import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * [说明]:使用jdbc连接mysql数据库 * @author aeon * 连接mysql数据库的步骤: * 一、准备工作 * 1.1新建一个java项目 * 1.2在该项目下新建一个lib(外部类库)文件夹(new->folder) * 1.3将我们的mysql驱动放到lib文件夹下 * 1.4将mysql驱动(即这个jar文件)添加(右键->build path->add to build path)到eclipse的构建路径里(作用同我们的环境变量) * 这样的话eclipse可以识别mysql驱动中的字节码文件。 * 1.5建包和类 * 二、正式步骤 * 2.1加载/注册驱动驱动(目的是让jvm可以使用驱动类) * 2.2获取和数据库服务器的连接(java程序是客户端 mysql是个服务器) * 2.2.1指定要连接到mysql服务器的相关信息(用户名&&密码&&url+端口+数据库名) * 2.3连接服务器 * 2.4通过连接对象获取执行sql语句的对象 * 2.5通过获取到的sql语句对象来执行sql * 2.6遍历输出结果 * 2.7关闭流 遵循原则:后打开的先关闭 */ public class TestJdbc { public static void main(String[] args) { Connection connection=null; Statement statement=null; ResultSet resultSet=null; try { //2.1加载/注册驱动 //driver是jdbc声明的标准接口、com.mysql.jdbc.Driver是mysql数据库厂商根据这个标准做的实现、注意这两个Driver是有区别的。 Driver driver=new com.mysql.jdbc.Driver(); //接口声明引用指向实现类的对象 DriverManager.registerDriver(driver); //2.2获取和数据库服务器的连接(java程序是客户端 mysql是个服务器) String username="root"; //用户名 String password="root"; //密码 //url中的jdbc:mysql说明:jdbc是由sun公司制定的一套网络协议 jdbc:mysql是指jdbc协议下的mysql子协议。 String url="jdbc:mysql://localhost:3306/db_test"; //2.3连接服务器 Connection是jdbc规范中声明的接口 connection=DriverManager.getConnection(url, username, password); //2.4通过连接对象获取执行sql语句的对象 statement=connection.createStatement(); String sql="select * from user"; //2.5通过获取到的sql语句对象来执行sql resultSet=statement.executeQuery(sql);//executeQuery对应的去执行DQL语句 //2.6遍历输出结果 System.out.println("用户id\t用户名\t用户密码"); while(resultSet.next()){//初始时指向表前面、和游标相似 .next()方法表示移动到下一条记录并判断有没有数据。如果有则结果为true。否则false //resultSet.getString(1);//根据记录下标来获取该下标所对应的字段值、不推荐 int userId=resultSet.getInt("userId");//根据表字段名获取该行记录上的字段名所对应的字段值 String userName=resultSet.getString("userName"); String userPw=resultSet.getString("userpw");//数据库中的字段不区分大小写 System.out.println(userId+"\t"+userName+"\t"+userPw); } } catch (SQLException e) { e.printStackTrace(); }finally{ //2.7关闭流 遵循原则:后打开的先关闭 if(null!=resultSet){ try { resultSet.close(); } catch (SQLException e) { System.out.println("关闭流失败!--->resultSet"); e.printStackTrace(); } } if(null!=statement){ try { statement.close(); } catch (SQLException e) { System.out.println("关闭流失败!--->statement"); e.printStackTrace(); } } if(null!=connection){ try { connection.close(); } catch (SQLException e) { System.out.println("关闭流失败!--->connection"); e.printStackTrace(); } } } } }
二、关于try...catch的思考
1.为什么注册数据库驱动、拿到数据库的连接、连接获得执行SQL的对象、然后用获得SQL的对象去执行SQL得到结果集、遍历结果集会放到一个try{ //some code }catch(SQLException e ){//some code}?
因为如果出现注册数据库驱动失败、我们能拿到数据库的连接吗?既然拿不到连接我们能根据连接获得执行SQL的对象吗?能得到结果集吗? 肯定不能啊、所以这种有前后因果关系的异常我们总体处理。这样当其中某一环节出现问题时,那么下面的环节就没必要去执行了、直接进入catch...finally环节。
2.为什么关闭数据库资源要单独进行分批处理?可不可以放到一个try...catch里面总体处理?
如果第一个问题你理解透彻了,那么这个问题就简单了,因为这个问题是建立在第一个问题基础上的。
为什么要进行单独处理?因为哪怕是你resultSet关闭失败了,我也要去关闭其它两个连接资源啊,不用了,所以我要去关闭啊,如果合起来总体处理的话,当resultSet关闭失败了,直接进入catch...finally环节,那么其它两个资源关闭问题就直接跳过了呀,学过try catch语句块的都应该知道这个问题。所以这两个就一直占用着资源、我们知道服务器是放置在网络上被大部分用户去访问的,那么这成百上千的都占用这点资源呢?上亿的也占用这点资源呢?服务器能受得了?虽然关闭连接这个过程很少出现关闭资源失败的情况,但是我们作为开发人员应该要考虑到千千万万种可能。所以关闭数据库资源方面我们不能合起来处理,最好单独处理。
3.关闭数据库资源之前要判断这个资源是否为null、如果不为null,我们才可以close(),如果为null,那么接下来会执行null.close()这种nullpointexception异常代码块,应该过滤掉这种可能。