以下是我用于使用Prepared Statement在Oracle数据库中插入multiple records( around 5000-7000)
的代码。
我目前的做法很好吗?或者使用某些batch thing
可以提高效率?
pstatement = db_connection.prepareStatement(PDSLnPConstants.UPSERT_SQL);
for (Entry<Integer, LinkedHashMap<Integer, String>> entry : MAPPING.entrySet()) {
pstatement.setInt(1, entry.getKey());
pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID));
pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID));
pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID));
pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID));
pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID));
pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID));
pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID));
pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID));
pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID));
pstatement.executeUpdate();
pstatement.clearParameters();
}
我正在使用的Udpated代码: -
public void runNextCommand() {
Connection db_connection = null;
PreparedStatement pstatement = null;
int batchLimit = 1000;
boolean autoCommit = false;
try {
db_connection = getDBConnection();
autoCommit = db_connection.getAutoCommit();
db_connection.setAutoCommit(false); //Turn off autoCommit
pstatement = db_connection.prepareStatement(LnPConstants.UPSERT_SQL); // create a statement
for (Entry<Integer, LinkedHashMap<Integer, String>> entry : GUID_ID_MAPPING.entrySet()) {
pstatement.setInt(1, entry.getKey());
pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID));
pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID));
pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID));
pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID));
pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID));
pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID));
pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID));
pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID));
pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID));
pstatement.addBatch();
batchLimit--;
if(batchLimit == 0){
pstatement.executeBatch();
pstatement.clearBatch();
batchLimit = 1000;
}
pstatement.clearParameters();
}
} catch (SQLException e) {
getLogger().log(LogLevel.ERROR, e);
} finally {
try {
pstatement.executeBatch();
db_connection.commit();
db_connection.setAutoCommit(autoCommit);
} catch (SQLException e1) {
getLogger().log(LogLevel.ERROR, e1.getMessage(), e1.fillInStackTrace());
}
if (pstatement != null) {
try {
pstatement.close();
pstatement = null;
} catch (SQLException e) {
getLogger().log(LogLevel.ERROR, e.getMessage(), e.fillInStackTrace());
}
}
if (db_connection!= null) {
try {
db_connection.close();
db_connection = null;
} catch (SQLException e) {
getLogger().log(LogLevel.ERROR, e.getMessage(), e.fillInStackTrace());
}
}
}
}
答案 0 :(得分:8)
您可以考虑使用addBatch()
并一次性执行一个语句。另外,正如@pst在您的问题中发表了评论,请考虑使用trasaction
。
您的方式如下:
boolean autoCommit = connection.getAutoCommit();
try{
connection.setAutoCommit(false //Turn off autoCommit
pstatement = db_connection.prepareStatement(PDSLnPConstants.UPSERT_SQL);
int batchLimit = 1000;
try{
for (Entry<Integer, LinkedHashMap<Integer, String>> entry : MAPPING.entrySet()) {
pstatement.setInt(1, entry.getKey());
pstatement.setString(2, entry.getValue().get(LnPConstants.CGUID_ID));
pstatement.setString(3, entry.getValue().get(LnPConstants.PGUID_ID));
pstatement.setString(4, entry.getValue().get(LnPConstants.SGUID_ID));
pstatement.setString(5, entry.getValue().get(LnPConstants.UID_ID));
pstatement.setString(6, entry.getValue().get(LnPConstants.ULOC_ID));
pstatement.setString(7, entry.getValue().get(LnPConstants.SLOC_ID));
pstatement.setString(8, entry.getValue().get(LnPConstants.PLOC_ID));
pstatement.setString(9, entry.getValue().get(LnPConstants.ALOC_ID));
pstatement.setString(10, entry.getValue().get(LnPConstants.SITE_ID));
pstatement.addBatch();
batchLimit--;
if(batchLimit == 0){
pstatement.executeBatch();
pstatement.clearBatch
batchLimit = 1000;
}
pstatement.clearParameters();
}
}finally{
//for the remaining ones
pstatement.executeBatch();
//commit your updates
connection.commit();
}
}finally{
connection.setAutoCommit(autoCommit);
}
我们的想法是为批量更新设置限制,并仅在达到特定限制时执行数据库更新。这样,您将每个batchLimit
定义的数据库调用限制为一次。这样会更快。
另请注意transaction
,我刚刚展示了commit
的方式和时间。这可能并不总是commit
的正确点,因为此决定将基于您的要求。如果发生异常,您可能还需要执行rollback
。所以由你来决定。
查看"Using Transaction"教程,以便更好地了解如何使用transaction
。
答案 1 :(得分:1)
你的代码对我来说似乎很好。
为了代码清洁,我将entry.getValue()
放入变量(称之为value
)。
而且无需拨打clearParameters()
。
最后,请记住在不再需要它时正确处理准备好的语句(close()
)。
答案 2 :(得分:1)
是的,进行批量更新可以显着提高您的性能。只是google for it,我的首选答案是this one from Mkyong.com。否则,您的代码看起来不错。 “clearParameters()”并不是必需的,甚至可能会占用一些处理器周期。重要提示:如果启用了AutoCommit,请不要忘记之前禁用它,并在执行更新后启用它,这再次带来了巨大的改进。
PS
以上建议也取决于我的经验。我刚刚注意到这个问题已被问到here at Stackoverflow,答案非常详细。有关PreparedStatements和批次的更多信息,请参阅Oracle文档here和关于事务(AutoCommit)here。