我刚刚开始使用jsp,我的问题就是这个 - 当我有一个单身课程时,我该怎么整理它?
特别是:
public class DBConnection {
private static Connection connection = null;
private static Statement statement = null;
public static ResultSet executeQuery(String query){
if (connection == null) { /*initConnection*/ }
if (statement == null) { /*initStatement*/ }
// do some stuff
}
}
现在,我在几个页面中使用此类来从jdbc获取结果。但是,我最终需要拨打statement.close();
和connection.close();
- 我应该何时拨打这些电话?
我正在使用单例,因为每当我需要进行查询时,一遍又一遍地调用连接数据库是错误的。
答案 0 :(得分:1)
Connection
必须关闭始终,并且在执行了所需的操作的所有数据库语句之后。两个例子:
案例1:您必须向用户显示按数据库条件筛选的产品列表。解决方案:获取连接,使用筛选条件检索产品列表,关闭连接。
案例2:客户选择其中一些产品并更新最低库存以获得警报并重新进货。解决方案:获取连接,更新所有产品,关闭连接。
基于这些案例,我们可以学到很多东西:
结果:
Connection
,Statement
和ResultSet
以及其他JDBC资源声明为static
。它只会失败。相反,只声明Connection
类的DBConnection
字段。让每个方法决定处理每个Statement
(或PreparedStatement
)和ResultSet
以及特定的JDBC资源。void open()
和void close()
。这些方法将处理数据库连接检索和关闭该连接。DBConnection
看起来像Connection
类和数据库连接操作的包装类,我建议至少再使用三种方法:void setAutoCommit(boolean autoCommit)
,{{1} }和void commit()
。这些方法将分别是Connection#setAutoCommit
Connection#close
和Connection#rollback
的简单包装。然后你可以这样使用这个类:
void rollback()
请注意,在此示例中,public List<Product> getProducts(String categoryName) {
String sql = "SELECT id, name FROM Product WHERE categoryName = ?";
List<Product> productList = new ArrayList<Product>();
DBConnection dbConnection = new DBConnection();
try {
dbConnection.open();
ResultSet resultSet = dbConnection.executeSelect(sql, categoryName); //execute select and apply parameters
//fill productList...
} catch (Exception e) {
//always handle your exceptions
...
} finally {
//don't forget to also close other resources here like ResultSet...
//always close the connection
dbConnection.close();
}
}
不在PreparedStatement
方法中,它将是getProducts
方法的局部变量。
附加说明:
executeSelect
,而不是使用数据库连接池。您可以在这里解释一些数据库连接池库,如C3P0:How to establish a connection pool in JDBC?。或者在应用程序服务器中配置一个,我在这里解释:Is it a good idea to put jdbc connection code in servlet class? 更多信息:
答案 1 :(得分:1)
在mywebapp / META-INF / context.xml文件中定义连接资源
<Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource"
maxActive="10" maxIdle="2" maxWait="20000"
driverClassName="com.mysql.jdbc.Driver"
username="myuser" password="mypwd"
url="jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8"
validationQuery="SELECT 1" />
创建DB.java帮助程序类以最小化应用程序其他部分中的代码
import java.sql.*;
import javax.sql.DataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
public class DB {
public static Connection createConnection() throws SQLException {
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/mydb");
return ds.getConnection();
} catch (SQLException ex) {
throw ex;
} catch (Exception ex) {
SQLException sqex = new SQLException(ex.getMessage());
sqex.initCause(ex);
throw sqex;
}
}
public static void close(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) try { rs.close(); } catch (Exception e) { }
if (stmt != null) try { stmt.close(); } catch (Exception e) { }
if (conn != null) try { conn.close(); } catch (Exception e) { }
}
public static void close(ResultSet rs, boolean closeStmtAndConn) {
if (rs==null) return;
try {
Statement stmt = rs.getStatement();
close(rs, stmt, stmt!=null ? stmt.getConnection() : null);
} catch (Exception ex) { }
}
}
在您的应用程序DAO代码中的某处使用数据库帮助程序。
public List<MyBean> getBeans() throws SQLException {
List<MyBean> list = new ArrayList<MyBean>();
ResultSet rs=null;
try {
Connection con = DB.createConnection();
String sql = "Select * from beantable where typeid=?";
PreparedStatement stmt = con.prepareStatement(sql, Statement.NO_GENERATED_KEYS);
stmt.setInt(1, 101);
rs = stmt.executeQuery();
while(rs.next()
list.add( createBean(rs) );
} finally {
DB.close(rs, true); // or DB.close(rs, stmt, conn);
}
return list;
}
private MyBean createBean(ResultSet rs) throws SQLException {
MyBean bean = new MyBean();
bean.setId( rs.getLong("id") );
bean.setName( rs.getString("name" );
bean.setTypeId( rs.getInt("typeid") );
return bean;
}
答案 2 :(得分:0)
我会在课程中添加两个方法:
public static void open() throws SomeException;
public static void close() throws SomeException;
然后你的调用代码看起来像这样{
try {
DBConnection.open();
... code to use the connection one or more times ...
} finally {
DBConnection.close();
}
将所有数据库调用包含在其中,它将负责关闭是否抛出异常。
当然,这与普通课程没什么不同,我可能会建议:
try {
DBConnection conn = new DBConnection();
conn.open();
... all the code to use the database (but you pass 'conn' around) ...
} finally {
conn.close();
}
您可能需要查看java.lang.AutoCloseable
和java.io.Closeable
,看看是否对您有帮助。
<强> 2 强>
如果要在页面加载中保持打开状态,则没有任何地方可以放置try ... finally
内容,以便在servlet关闭或服务器关闭或类似的情况下打开它并关闭它。 / p>
如果您打算将其打开,则需要确保并添加代码以确认在您不看时它不会关闭。例如,短暂的网络故障可能会将其关闭。在这种情况下,您需要在关闭时重新打开它。否则,从该点开始的所有数据库访问都将失败。
您可能希望研究数据库池的概念。 Apache有一个 - DBCP。 Tomcat有自己的特色。其他容器,如JBOSS,WebSphere,WebLogic都有它们。有一对可以与Spring Framework一起使用。它的作用是管理一个或多个数据库连接。你的代码要求一个并且它返回一个打开的代码,除非没有可用的,然后它打开一个并返回它。当您的代码通过它时调用close
但它并没有真正关闭连接,它只是将它返回到池中。
您通常可以配置池以检查关闭连接,并在需要时重新打开。