connection preparedstatement resultset关于多次重复使用查询及connection是否可以创建多个statement及数据库连接的基本使用

正确使用数据库连接的正常步骤:

        Connection con=null;
        PreparedStatement preStmt=null;
        try {
        con = ConnectionUtil.getConnection();
        con.setAutoCommit(false);
        StringBuffer sql = new StringBuffer("insert into lecture_check(lecture_id,student_id,attend_time,check_status) ")
                .append("values(?,?,?,?)");
        preStmt = con.prepareStatement(sql.toString());
        preStmt.setInt(1,lecture_id);
        preStmt.setInt(2,student_id);
        preStmt.setString(3,df.format(new Date()));
        preStmt.setInt(4,1);
        preStmt.executeUpdate();
        //preStmt注意关闭,疑问:为什么这里要关闭,下面不是要继续使用吗?答:connection.prepareStatement(sql)只是创建一 个 PreparedStatement 对象,调用2次,会创建2个对象和Connection一样,如果不调用close方法,见问题1,如果是查询操作,涉及resultset ,也需要调用close(),原因同理。
        preStmt.close();
        //更新讲座剩余座位数
        preStmt = con.prepareStatement("update lecture_lecture set rest_seat=rest_seat-1 where id=?");
        preStmt.setInt(1,lecture_id);
        preStmt.executeUpdate();
        con.commit();
        } catch (SQLException e) {
            try{
                if(con!=null&&(!con.isClosed())){
                    con.rollback();//注意回滚
                }
            }catch(Exception f){
                f.printStackTrace();
            }
            e.printStackTrace();
        }finally{
            ConnectionUtil.closeConnection(con, preStmt);//注意关闭
        }

更新,插入,删除使用executeUpdate(),查询使用executeQuery(),未知操作使用execute()

查询操作关闭顺序:resultset preparedstatement connection

问题1:是否一定需要按照顺序将resultset preparedstatement connection都关闭?

答:1.使用第三方数据库连接池时,获取到Connection之后,使用完成,调用的关闭方法(close()) ,并没有将Connection关闭,只是放回到连接池中,如果调用的这个方法,而没有手动关闭resultset,PreparedStatement ,则这个PreparedStatement并没有关闭,这样会使得程序内存急速增长,java的内存回收机制可能跟不上速度,最终造成答Out of memory Error。
2.如果使用JDK 7就不用了,它们都实现了java.lang.AutoCloseable

问题2:connection是否可以创建多个preparedstatement ?

答:connection对象可以创建任意多个preparedstatement 对象,而不需要你重新获取连接,并且一般一个线程只使用一个connection,一方面可以控制事务,另一方面可以降低数据库连接消耗,当然有例外的是如果需要开启嵌套的新事务,则需要获取新的connection(类似于spring的传播性:挂起当前事务,并新建事务)。

问题3:preparedstatement是否可以创建任意多个resultset对象,同时循环使用?

答:preparedstatement可以创建任意多个resultset结果集对象,但是每次只有一个结果集生效,并且之前的结果集已失效,要关闭,避免造成内存溢出。原因如下:

Connection con=null;
con=ConnectionUtil.getConnection();
PreparedStatement preStmt=null;
ResultSet rs=null;
ResultSet rs1=null;

preStmt = con.prepareStatement(sql.toString());
rs = preStmt.executeQuery();

preStmt = con.prepareStatement(sql1.toString());
rs1 = preStmt.executeQuery();

以上程序同一个preStmt变量,但其实con.prepareStatement(sql.toString()),con.prepareStatement(sql1.toString())分别创建了两个PreparedStatement对象,这里给名对象1,对象2,当创建对象2赋值给preStmt时,原先创建的对象1已经没有和任何变量绑定了,处于等待系统资源回收状态,那么rs结果集还能有效吗?很明显,它也是处于等待系统资源回收的状态了。跟使用con,preStmt,rs是无关的,所以不要纠结于是否能够重新利用,每次ConnectionUtil.getConnection(),con.prepareStatement(sql.toString()),preStmt.executeQuery()都会创建新的对象,关键在于有没有变量与它绑定。

那么使用createStatement创建的Statement对象是否就可以,因为没有创建新的Statement,答案是不可以的,一个Statement对象同时只能有一个结果集在活动.这是宽容性的,就是说即使没有调用ResultSet的close()方法,只要打开第二个结果集就隐含着对上一个结果集的关闭。

比如以下程序就是错误的

 Connection conn = null;
  Statement stmt = null;
  conn = .......;
  stmt = conm.createStatement(xxxxxx);
  ResultSet rs = stmt.executeQuery(sql1);
  while(rs.next()){
    str = rs.getString(xxxxx);
    ResultSet rs1 = stmt.executeQuery(\"select * from 表 where 字段=str\");
  }

当stmt.executeQuery(\"select * from 表 where 字段=str\");赋给rs1时,这时隐含的操作是已经关闭了rs,你还能循环下去吗?所以如果要同时操作多个结果集一定要让它他绑定到不同的Statement对象上,好在一个connection对象可以创建任意多个Statement对象,而不需要你重新获取连接。

问题4:那怎么编写,使得多个结果集对象能同时循环活动?

答:如果你想同时对多个结果集操作,就要创建多个Statement或者prepareStatement对象,如果不需要同时操作,那么可以在一个Statement或prepareStatement对象上顺序操作多个结果集,不过需要注意每次操作完成后关闭prepareStatement和ResultSet。

问题5:如果sql查询语句不变,使用同一个prepareStatement对象多次直接调用executeQuery方法(中间数据会进行更新),会从数据库查询出最新数据吗?

答:会,只要确保是同一个Connection数据库连接,涉及数据库事务,请参考以下链接。事务隔离性级别,数据库锁,spring事务传播性,Spring事务的隔离级别_porkczr的博客-CSDN博客

比如以下程序就是正确的

public static void main(String[] args) throws SQLException {
		Connection conn = DBpool.getConnection();
		conn.setAutoCommit(false);
		PreparedStatement preStmt=null;
		ResultSet rs=null;
		StringBuffer sql=null;
		
		sql = new StringBuffer("select * from REDUCEDORMITORYFEE r where r.ISSUCCESS='N'");
		preStmt = conn.prepareStatement(sql.toString());
		rs = preStmt.executeQuery();
		if(rs.next()){
			System.out.println(rs.getDouble("ARREARS"));
		}
		rs.close();//这里要对rs进行关闭,但是不能关闭preStmt,因为还要继续使用
		sql=new StringBuffer("update REDUCEDORMITORYFEE set ARREARS='2000' where ISSUCCESS='N'");
        //这里不能重新赋值给preStmt,要创建新的PreparedStatement变量,preStmt要确保引用的
        PreparedStatement preStmt1=conn.prepareStatement(sql.toString());
		preStmt1.executeUpdate();
		preStmt1.close();
        //还是之前的PreparedStatement对象。
        //preStmt直接调用executeQuery方法,再次从数据库查询最新数据
		rs = preStmt.executeQuery();
		if(rs.next()){
			System.out.println(rs.getDouble("ARREARS"));
		}
		rs.close();
		preStmt.close();
		conn.commit();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值