问题描述
在DAL层中,每次执行查询以后都会关闭prepareStatement对象和Connection对象,请问这样做合适吗?我的SQLHelper写成是静态的了,DAL层每个查询都从SQLHelper中获取一个PrepareStatement对象,然后每次执行完对应的查询后都会关闭pstmt对象和connection对象,然而这只是在DAL层,在BLL层中一般会调用1-5个DAL的方法,也就是说,一轮业务逻辑下来,Connection对象会开启和关闭1-5次,这样对性能有影响吗?有没有高手帮我改一下,不胜感激!主要是性能方面的问题,其他的没什么!!!就怕性能不足!!!但是又不想让BLL层接触数据库的东西,达到分层效果。[color=#FF0000][/color]下面是我的SQLHelper代码:importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;/***数据库通用逻辑组件**/publicclassSQLHelper{/**声明数据库三大连接对象*/publicstaticConnectionconn=null;//数据库连接对象publicstaticStatementstmt=null;//数据库命令执行对象publicstaticPreparedStatementpStmt=null;//数据库预编译命令执行对象publicstaticResultSetrs=null;//数据库结果集对象/**不允许实例化该类*/privateSQLHelper(){}/**连接数据库语句*///设置数据库连接驱动,默认使用JDBC4进行连接privatestaticStringdbDrive="com.microsoft.sqlserver.jdbc.SQLServerDriver";//数据库连接地址以及连接的数据库名privatestaticStringdbLocate="localhost";privatestaticStringdbName="sq_a1076";privatestaticStringdbPort="1433";privatestaticStringdbURL="jdbc:sqlserver://"+dbLocate+":"+dbPort+";DatabaseName="+dbName+"";//数据库帐号和密码privatestaticStringdbUser="";//忽略这个吧,我删掉了privatestaticStringdbPwd="";//============================================================//获取各种连接对象,用于内部使用//============================================================/**获取Connection连接对象*/privatestaticConnectiongetConnection(){Connectionconn=null;try{Class.forName(dbDrive);conn=DriverManager.getConnection(dbURL,dbUser,dbPwd);}catch(Exceptione){e.printStackTrace();}//判断是否成功生成conn连接对象if(conn==null){System.err.println("警告:数据库连接失败!");}returnconn;}//method/***获取Statement对象**@return返回一个指针可滚动、可更新的SQL语句执行对象*/publicstaticStatementgetStatement(){conn=getConnection();if(conn==null){returnnull;}try{returnconn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);}catch(Exceptione){//TO-DO是否需要关闭Connection?e.printStackTrace();returnnull;}}/***获取PrepareStatement对象**@paramsql特定的带'?'的SQL执行语句*示例:Stringsql="select*fromgoodswheregoodsName=?andgoodsType=?";**@return返回一个预编译指针可滚动、可更新SQL语句执行对象*/publicstaticPreparedStatementgetPreparedStatement(Stringsql){conn=getConnection();if(conn==null){returnnull;}try{returnconn.prepareStatement(sql,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);//使用第一个方法}catch(Exceptione){e.printStackTrace();returnnull;}}/**关闭数据库连接*/publicstaticvoidcloseConnection()throwsException{//关闭连接对象try{if(conn!=null){conn.close();}}catch(Exceptione){throwe;}}//method}//class
下面是DAL层中其中一个SQL原子执行语句:publicUserfindUserByUserName(StringuserName)throwsException{Useruser=null;//一个可以指向用户对象的变量Stringsql="selectuserName,userTypeId,personIdfrom[User]whereuserName=?";pstmt=SQLHelper.getPreparedStatement(sql);pstmt.setString(1,userName);ResultSetrs=pstmt.executeQuery();while(rs.next()){user=newUser();user.setUserName(rs.getString(1));user.setUserTypeId(rs.getInt(2));user.setPersonId(rs.getInt(3));}pstmt.close();SQLHelper.closeConnection();returnuser;}
感激各位大神的帮助
解决方案
本帖最后由 u011688498 于 2015-01-04 17:50:16 编辑
解决方案二:
主要是性能方面的问题,其他的没什么!!!就怕性能不足!!!但是又不想让BLL层接触数据库的东西,达到分层效果。
解决方案三:
不要这么做,我在CSDN强调过不下10次了,不要把Connection等JDBC对象弄成静态的,这会产生非常严重的问题。JDBCconnection讨论Connection能设置成静态的吗
解决方案四:
引用2楼bao110908的回复:
不要这么做,我在CSDN强调过不下10次了,不要把Connection等JDBC对象弄成静态的,这会产生非常严重的问题。JDBCconnection讨论Connection能设置成静态的吗
还是不是很懂,连接泄漏这方面的问题,那应该怎么做?在三层架构里面,我不想DAL和BAL耦合太大,求支招!
解决方案五:
一个Connection的开启和关闭一般用于代表一个事务,对于Connection,设置为一个成员变量的时候,当出现多线程调用这个Connection成员变量,如果不处理同步问题,则可能你在线程1中调用这个Connection成员变量的时候,发现这个是一个空指针,于是就新建了一个Connection,但是如果同时线程2也在跑,也同时发现这个是一个空指针,同样新建了一个Connection(多线程就是这样的,因为你没有处理异步问题),这样你的Connection关闭就很有问题了,并且可能会很快占用完数据库连接(new了太多Connection)!所以最佳的做法就是,每次操作数据库之前都独立获取一个Connection对象,并且操作完之后对其进行关闭!也就很好地保证了事务的一致性以及代码的同步操作。
解决方案六:
引用4楼u010097361的回复:
一个Connection的开启和关闭一般用于代表一个事务,对于Connection,设置为一个成员变量的时候,当出现多线程调用这个Connection成员变量,如果不处理同步问题,则可能你在线程1中调用这个Connection成员变量的时候,发现这个是一个空指针,于是就新建了一个Connection,但是如果同时线程2也在跑,也同时发现这个是一个空指针,同样新建了一个Connection(多线程就是这样的,因为你没有处理异步问题),这样你的Connection关闭就很有问题了,并且可能会很快占用完数据库连接(new了太多Connection)!所以最佳的做法就是,每次操作数据库之前都独立获取一个Connection对象,并且操作完之后对其进行关闭!也就很好地保证了事务的一致性以及代码的同步操作。
可以把每次单独获取Connection和prepareStatement的代码写到一起提供复用。多次开启和关闭独立的Connection是没有问题的,一般都是这么做的,如果想更加优化,一般推荐使用连接池!
解决方案七:
你的代码都不是性能问题了,是肯定会出多线程问题。除非你能保证,同一时间SqlHelper只有一个线程被调用。A线程调用了getPreparedStatement,B线程也调用了getPreparedStatement。。。这时候A先调用结束然后调用了closeConnection关掉了Connection,那么等B线程调用结束后如何关掉B线程用的Connection?这个Connection就泄漏了,迟早会达到数据库连接上限。所以建议是除非你能保证,同一时间只有一个线程调用SqlHelper上的方法,不然别这么做。你可以使用DataSource数据源,这都说烂的事了。比如C3P0之类的,你只需要问他拿Connection使用完调用close就可以了。性能由C3P0来保证。当然数据源实现有好多种了。
解决方案八:
引用5楼u010097361的回复:
Quote: 引用4楼u010097361的回复:
一个Connection的开启和关闭一般用于代表一个事务,对于Connection,设置为一个成员变量的时候,当出现多线程调用这个Connection成员变量,如果不处理同步问题,则可能你在线程1中调用这个Connection成员变量的时候,发现这个是一个空指针,于是就新建了一个Connection,但是如果同时线程2也在跑,也同时发现这个是一个空指针,同样新建了一个Connection(多线程就是这样的,因为你没有处理异步问题),这样你的Connection关闭就很有问题了,并且可能会很快占用完数据库连接(new了太多Connection)!所以最佳的做法就是,每次操作数据库之前都独立获取一个Connection对象,并且操作完之后对其进行关闭!也就很好地保证了事务的一致性以及代码的同步操作。可以把每次单独获取Connection和prepareStatement的代码写到一起提供复用。多次开启和关闭独立的Connection是没有问题的,一般都是这么做的,如果想更加优化,一般推荐使用连接池!
可以给各小例子吗?谢谢,我不知道怎么复用,是静态还是动态的?!
解决方案九:
引用6楼etnet的回复:
你的代码都不是性能问题了,是肯定会出多线程问题。除非你能保证,同一时间SqlHelper只有一个线程被调用。A线程调用了getPreparedStatement,B线程也调用了getPreparedStatement。。。这时候A先调用结束然后调用了closeConnection关掉了Connection,那么等B线程调用结束后如何关掉B线程用的Connection?这个Connection就泄漏了,迟早会达到数据库连接上限。所以建议是除非你能保证,同一时间只有一个线程调用SqlHelper上的方法,不然别这么做。你可以使用DataSource数据源,这都说烂的事了。比如C3P0之类的,你只需要问他拿Connection使用完调用close就可以了。性能由C3P0来保证。当然数据源实现有好多种了。
好,后面我把数据库SQLHelper写成动态的了,不知道这样行不行,我也在多线程环境下调用过,在SQLManager看连接,在程序结束后就没有连接了,应该是没问题了,以后再用C3P0,谢谢