在哪里使用 JDBC 创建准备好的语句?
Posted
技术标签:
【中文标题】在哪里使用 JDBC 创建准备好的语句?【英文标题】:Where to create a prepared statement with JDBC? 【发布时间】:2010-05-12 09:31:46 【问题描述】:考虑以下方法,从某些数据结构 (InteractionNetwork
) 读取数据并使用 SQLite-JDBC dirver 将它们写入 SQLite 数据库中的表:
private void loadAnnotations(InteractionNetwork network) throws SQLException
PreparedStatement insertAnnotationsQuery =
connection.prepareStatement(
"INSERT INTO Annotations(GOId, ProteinId, OnthologyId) VALUES(?, ?, ?)");
PreparedStatement getProteinIdQuery =
connection.prepareStatement(
"SELECT Id FROM Proteins WHERE PrimaryUniProtKBAccessionNumber = ?");
connection.setAutoCommit(false);
for(common.Protein protein : network.get_protein_vector())
/* Get ProteinId for the current protein from another table and
insert the value into the prepared statement. */
getProteinIdQuery.setString(1, protein.get_primary_id());
ResultSet result = getProteinIdQuery.executeQuery();
result.next();
insertAnnotationsQuery.setLong(2, result.getLong(1));
/* Extract all the other data and add all the tuples to the batch. */
insertAnnotationsQuery.executeBatch();
connection.commit();
connection.setAutoCommit(true);
这段代码运行良好,程序运行时间约为 30 秒,平均占用 80m 堆空间。因为代码看起来很难看,我想重构它。我做的第一件事是将getProteinIdQuery
的声明移到循环中:
private void loadAnnotations(InteractionNetwork network) throws SQLException
PreparedStatement insertAnnotationsQuery =
connection.prepareStatement(
"INSERT INTO Annotations(GOId, ProteinId, OnthologyId) VALUES(?, ?, ?)");
connection.setAutoCommit(false);
for(common.Protein protein : network.get_protein_vector())
/* Get ProteinId for the current protein from another table and
insert the value into the prepared statement. */
PreparedStatement getProteinIdQuery = // <--- moved declaration of statement here
connection.prepareStatement(
"SELECT Id FROM Proteins WHERE PrimaryUniProtKBAccessionNumber = ?");
getProteinIdQuery.setString(1, protein.get_primary_id());
ResultSet result = getProteinIdQuery.executeQuery();
result.next();
insertAnnotationsQuery.setLong(2, result.getLong(1));
/* Extract all the other data and add all the tuples to the batch. */
insertAnnotationsQuery.executeBatch();
connection.commit();
connection.setAutoCommit(true);
当我现在运行代码时会发生什么,它需要大约 130m 的堆空间并且需要很长时间才能运行。谁能解释这种奇怪的行为?
【问题讨论】:
【参考方案1】:正如您所发现的,准备一份声明需要时间。不管代码丑不丑,速度下降也很丑,所以你需要使用更快的形式。
但你可以做的是使用内部类来保存细节并提供更好的界面:
private class DatabaseInterface
private PreparedStatement insertAnnotation, getProteinId;
public DatabaseInterface()
// This is an inner class; 'connection' is variable in outer class
insertAnnotation = connection.prepareStatement(
"INSERT INTO Annotations(GOId, ProteinId, OnthologyId) VALUES(?, ?, ?)");
getProteinId = connection.prepareStatement(
"SELECT Id FROM Proteins WHERE PrimaryUniProtKBAccessionNumber = ?");
public long getId(Protein protein) // Exceptions omitted...
getProteinId.setString(1, protein.get_primary_id());
ResultSet result = getProteinId.executeQuery();
try
result.next();
return result.getLong(1);
finally
result.close();
public void insertAnnotation(int GOId, long proteinId, String ontologyId)
insertAnnotation.setInt(1, GOId); // type may be wrong
insertAnnotation.setLong(2, proteinId);
insertAnnotation.setString(3, ontologyId); // type may be wrong
insertAnnotation.executeUpdate();
private void loadAnnotations(InteractionNetwork network) throws SQLException
connection.setAutoCommit(false);
DatabaseInterface dbi = new DatabaseInterface();
for(common.Protein protein : network.get_protein_vector())
dbi.insertAnnotation(..., dbi.getId(protein), ...);
connection.commit();
connection.setAutoCommit(true);
目标是您拥有一段代码知道如何将事物整合到 SQL 中(如果您使用不同的数据库,这很容易适应),而另一段代码知道如何将这些事物协调在一起。
【讨论】:
还请注意,您可以考虑更广泛地共享胶水类;它与连接相关,而不是特定操作。【参考方案2】:如果第一个片段看起来很难看,我想这是一个品味问题 ;-)...
但是,第二个代码片段需要更长的时间(恕我直言)的原因是,现在对于 for 循环的每次迭代,都会创建一个 PreparedStatement (getProteinIdQuery) 的新实例,而在第一个片段中,您重用了准备好的语句,以应有的方式使用它:实例化,然后提供适当的值。
至少,这是我的看法... 一月
【讨论】:
以上是关于在哪里使用 JDBC 创建准备好的语句?的主要内容,如果未能解决你的问题,请参考以下文章
SQLITE JDBC 驱动程序准备好的语句失败(内部指针 0)