企业数据库连接性的恰当构建是非常重要的,并且在为有限连接设备配置(Connection Limited Device Configuration(CLDC))构建应用程序和编写特定于 MIDP(移动接口)的接口之间,哪一种是最佳选择取决于 J2ME 和 Java 技术。
方式
介绍在把企业数据桥接到无线移动设备时建立 JDBC 连接的一条简单原则,这可以帮助您使解决方案具有更好的可扩展性和更高效的性能。
连接池
任何应用程序都必须先访问活动的数据库连接,然后才能访问数据库。数据库连接是一个很占资源且 I/O 开销很大的操作,并且如果每次想使用数据库连接时都必须创建它,那么它将会成为您的性能瓶颈。
例如,如果您使用 Java servlet(Java servlet 通过 init() 方法创建并在其生命周期结束时被销毁(通过 destroy() 方法))的方式,您是虽然避免了每次 servlet 被实例化时重新建立连接。这样一种方式会明显地降低应用程序的性能。完成相同功能的更好的途径是使用“连接池(Connection Pool)”,您可以在连接池中初始化多个连接(并且参数可以从 XML 配置文件中读取)。
连接本身由一组集合对象和一个在整个请求过程中使连接保持打开的用户请求组成。创建连接池的关键是在数据库访问代码中使用如下一些块:try{}.. catch{}... finally{}..。然后您使用 close() 方法来确认连接确实被返回到了连接池而不是被彻底关闭了。在“finally{}”块中指定 close() 方法使得执行过程中发生的异常会被捕获到,并且该语句仍被执行 — 连接返回到连接池,这就防止了应用程序中“连接泄漏(connection leak)”的发生。
以下是构建一个 JDBC 连接的示例:
Connection con = null;
try { ds = (DataSource)myContext.lookup("<specify JDBC driver>");
pooledCon = ds.getConnection("scott", "tiger");
// Processing Code goes here
} catch (Exception ignored) {
// catch JNDI or JDBC exceptions here
} finally {
if(pooledCon != null)
pooledCon.close();
}
使用 PreparedStatement
人们认为 PreparedStatement 对象的效率比多个 Statement 对象更高,尤其是如果您必须多次执行同一条语句而差别仅在于参数不同时更是如此。PreparedStatement 允许您将 SQL 语句“编译”一次(尽管这种编译第一次要消耗较多的时间),然后将它保存在高速缓存中,从而实现有效的重用。同时它也提供了可读性更好的代码。
另一个额外的优势是由驱动程序完成的对用户传递给语句的字符串的自动转义。举例来说,这意味着当您试图将字符串“D'Marco”插入到一个基于字符的数据域(它可能是 VARCHAR, VARCHAR2, CHAR 等)中时,SQL 语句不会在遇到第一个撇号时就产生灾难性的失败。
使用 PreparedStatement 对象时的另一个良好习惯是调用对象自身的 close() 方法来“关闭对象”,这个方法将被用来运行 SQL 语句。这会关闭任何与正在执行的 SQL 语句相关联的游标,这样就能防止打开的游标把数据库弄得十分凌乱。
以下是一个创建 PreparedSatement 的示例:
PreparedStatement sqlstmt = dbCon.prepareStatement("select *
from table1 where field_1=?");
sqlstmt.setInt(1, 12);
ResultSet rs = sqlstmt.executeQuery();
// close the resultset statement to avoid hanging cursors in database
sqlstmt.close();
// processing of new statement
sqlstmt = dbCon.prepareStatement("select * from table2 where field_2 = ?");
// repeat creating the result set
恰当地利用事务
在更新动态数据库表和数据时常常会遗忘的一个方面,就是在向超过一个表示一个逻辑事务的表更新或插入数据时,这个事务应该反映到所有的表中,或者在碰到事务失败时,通过“回滚”该事务而在每一个表中都没有反映。
一些核心的 JDBC 包支持了四种事务隔离模式(transaction isolation mode),这些模式允许程序指定它们想事务表现出怎样的行为。大多数程序都至少支持两种模式:“读取提交(read committed)”(缺省值)和“可序列化的(serializable)”。当不可重复读取应该允许在多个查询之间由一个事务作出的修改对于另一个事务可见时,请使用“读取提交”;要使由另一个事务作出的修改在一个查询运行时成为可见的,请使用幻象读取(phantom read)。当您需要一个跨多个操作前后完全一致的数据库视图时,就应该使用更为严格的“可序列化的”设置。把连接的自动提交设置为“假”(autocommit = "false"),记住这一点是很有用的。
以下是构建一个连接并设置其各个属性参数的示例:
Connection con = null;
try {
dtsr = (DataSource <the JDBC driver you use>");
pConn = dtsr.getConnection("<specify login>", "<specify password>");
pConn.setAutoCommit(false); // transaction are not committed uponm execution
pConn.setTransactionIsolation(
Connection.TRANSACTION_SERIALIZABLE);
// pConn is pooled connection
pConn.commit();
} catch (Exception ignored) {
try { pConnn.rollback(); } catch (SQLException esgl) {}
} finally {
if(pConn != null) {
pConn.setAutoCommit(true); //reset autocommit
pConn.close();
}
}
您也可以利用一个可选的 JDBC 包 — JTA(Java Transaction API),它允许容易地和完全独立的事务服务器进行集成。