Java JSP中的单件,如何正确整理上下?
我刚刚开始学习jsp,我的问题是——当我有一个单例类时,我该如何整理它 特别是:Java JSP中的单件,如何正确整理上下?,java,jsp,destructor,Java,Jsp,Destructor,我刚刚开始学习jsp,我的问题是——当我有一个单例类时,我该如何整理它 特别是: public class DBConnection { private static Connection connection = null; private static Statement statement = null; public static ResultSet executeQuery(String query){ if (connection == null) { /*in
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获得结果。但是,我最终需要调用语句.close()代码>和连接。关闭()代码>-我应该什么时候打电话
我使用的是singleton,因为每当我需要进行查询时,反复调用与数据库的连接是错误的。我将向该类添加两个方法:
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关闭或服务器关闭时打开并关闭它
如果要让它保持打开状态,则需要确保并添加代码,以验证它在不查看时没有关闭。例如,一个短暂的网络故障可能会使它关闭。在这种情况下,需要在它关闭时重新打开它。否则,从该点开始的所有数据库访问都将失败
您可能想了解数据库池的概念。Apache有一个——DBCP。Tomcat有自己的数据库池,这很好。其他容器,如JBOSS、WebSphere和WebLogic都有。Spring框架可以使用两个。它所做的是管理一个或多个数据库连接。您的代码要求它连接,然后返回一个打开的连接,除非没有可用的连接,否则它会打开一个并返回它。当你的代码通过它时,你调用close
,但它没有真正关闭连接,它只是将它返回到池中
通常,您可以将池配置为检查关闭的连接,并在需要时重新打开。必须始终关闭连接,并且在为所需操作执行所有数据库语句后关闭。两个示例:
案例1:必须向用户显示根据数据库中的条件筛选的产品列表。解决方案:获取连接,使用筛选条件检索产品列表,关闭连接
案例2:客户选择其中一些产品并更新最低库存以获取警报并重新进货。解决方案:获取连接,更新所有产品,关闭连接
基于这些案例,我们可以学到很多东西:
- 在打开/维护单个连接时,可以执行多条语句
- 该连接应仅在使用它的块中有效。在此之前或之后不应有效
- 这两种情况都可能同时发生,因为它们处于多线程环境中。因此,单个数据库连接不能同时供两个线程使用,以避免结果问题。例如,用户a搜索类别为Foo的产品,用户B搜索类别栏中的产品,您不希望向用户A显示类别栏中的产品
- 从最后一句话开始,每个数据库操作(或一组类似的操作,如案例2)都应该在一个原子操作中处理。为了确保这一点,连接不能存储在单例对象中,而必须仅在所使用的方法中有效
因此:
- 不要将
连接
或语句
或结果集
或其他JDBC资源声明为静态
。它只会失败。相反,只将连接
声明为数据库连接
类的字段。让每个方法决定处理每一个语句(或PreparedStatement
)和ResultSet
以及特定的JDBC资源
- 由于必须在连接使用后关闭该连接,因此再添加两个方法:
void open()
和void close()
。这些方法将处理数据库连接检索和关闭该连接
- 另外,由于
DBConnection
看起来像是Connection
类和数据库连接操作的包装类,我建议至少还有三种方法:void setAutoCommit(boolean autoCommit)
,void commit()
和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();
}
}
public List getProducts(字符串categoryName){
String sql=“从产品中选择id、名称,其中categoryName=?”;
List productList=new ArrayList();
DBConnection DBConnection=新的DBConnection();
试一试{
dbConnection.open();
ResultSet ResultSet=dbConnection.executeSelect(sql,categoryName);//执行select和apply参数
//填写产品列表。。。
}捕获(例外e){
//始终处理您的异常
...
}最后{
//不要忘记关闭其他资源,如ResultSet。。。
//始终关闭连接
dbConnection.close();
}
}
请注意,在此示例中,PreparedStatement
不在getProducts
方法中,它将是executeSelect
方法的局部变量
补充说明:
- 在应用服务器中工作时,不应天真地打开连接,例如使用
类
<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" />
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) { }
}
}
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;
}