Java SpringJDBC-批删除和插入
在我的应用程序中,我有一个表,其中包含大约200K条需要在数据库中更新的记录。我认为一种更快的方法是删除数据库中的所有匹配记录并插入它们,而不是检查数据库中是否存在匹配记录,然后插入或更新。我使用的是SpringJDBC框架。 为了删除,我使用了Jdbctemplate batchUpdate方法以及参数化PreparedStatementSetter,对于insert,我使用的是SimpleJDBCInsert。 插入工作正常,但是批删除性能非常慢。 我不太确定我应该采取什么其他方法来删除数据库中的记录并插入它们。任何建议都会很有帮助。我正在使用SQLServer2008R2Java SpringJDBC-批删除和插入,java,jdbc,spring-jdbc,jdbctemplate,Java,Jdbc,Spring Jdbc,Jdbctemplate,在我的应用程序中,我有一个表,其中包含大约200K条需要在数据库中更新的记录。我认为一种更快的方法是删除数据库中的所有匹配记录并插入它们,而不是检查数据库中是否存在匹配记录,然后插入或更新。我使用的是SpringJDBC框架。 为了删除,我使用了Jdbctemplate batchUpdate方法以及参数化PreparedStatementSetter,对于insert,我使用的是SimpleJDBCInsert。 插入工作正常,但是批删除性能非常慢。 我不太确定我应该采取什么其他方法来删除数据
ParameterizedPreparedStatementSetter<Order> vSetter =
new ParameterizedPreparedStatementSetter<Order>() {
@Override
public void setValues(PreparedStatement ps,
Order order) throws SQLException {
ps.setInt(1, order.getOrderNum());
}
};
getJdbcTemplate().batchUpdate("DELETE FROM Order WHERE OrderNum = ?",
aDemandOrders,
50000,
vSetter);
ParameterizedPreparedStatementSetter vSetter=
新的参数化PreparedStatementSetter(){
@凌驾
公共无效设置值(准备的声明ps,
订单)抛出SQLException{
ps.setInt(1,order.getOrderNum());
}
};
getJdbcTemplate().batchUpdate(“从Order中删除,其中OrderNum=?”,
阿德曼命令,
50000,
vSetter);
性能缓慢的原因是DB将接收到一批语句,但仍然逐个执行它们
另一种方法是使用in()
子句手动批处理语句,以允许DB使用每个批处理大小执行一条语句
然而,为了仍然获得查询缓存的好处,您不能简单地在一个in()
子句中发送所有内容,而应该对它们进行适当的批处理
private static final int MIN = 1;
private static final int SML = 4;
private static final int MED = 11;
private static final int MAX = 51;
private static final String DEL_ORDERS_QRY
= "DELETE FROM Order WHERE OrderNum in (:orders)";
public void deleteOrders(Collection<Integer> origIds) {
int done = getJdbcTemplate().execute((Connection con) -> {
// Reuse this query, `:orders` is a placeholder for the in-clause.
LinkedList<Integer> ids = new LinkedList<>(origIds);
int remainder = ids.size();
int updated = 0;
while (remainder > 0) {
// identify the batch size for this execution.
int batchSize;
if (remainder >= MAX) {
batchSize = MAX;
} else if (remainder >= MED) {
batchSize = MED;
} else if (remainder >= SML) {
batchSize = SML;
} else {
batchSize = MIN;
}
remainder -= batchSize;
// Build the in-clause parameters.
StringBuilder inClause = new StringBuilder(batchSize * 2);
for (int i = 0; i < batchSize; i++) {
if (i > 0) {
inClause.append(',');
}
inClause.append('?');
}
try (PreparedStatement ps = con.prepareStatement(
DEL_ORDERS_QRY.replace(":orders", inClause.toString()))) {
for (int i = 0; i < batchSize; i++) {
ps.setInt(i + 1, ids.pop());
}
updated += ps.executeUpdate();
} catch (SQLException ex) {
log.error("Couldn't execute batch", ex);
throw new RuntimeException(ex.getMessage(), ex);
}
}
return updated;
});
}
private static final int MIN=1;
专用静态最终int SML=4;
专用静态最终int MED=11;
专用静态最终int MAX=51;
私有静态最终字符串DEL_ORDERS_QRY
=“从OrderNum所在的订单中删除(:orders)”;
公共作废删除订单(收款来源){
int done=getJdbcTemplate().execute((连接con)->{
//重用此查询,`:orders`是in子句的占位符。
LinkedList ID=新的LinkedList(origIds);
int rements=ids.size();
int=0;
而(余数>0){
//标识此执行的批大小。
int批量大小;
如果(余数>=最大值){
batchSize=最大值;
}否则如果(余数>=MED){
batchSize=MED;
}否则如果(余数>=SML){
batchSize=SML;
}否则{
batchSize=MIN;
}
余数-=批量大小;
//构建in子句参数。
StringBuilder Incluse=新的StringBuilder(批量大小*2);
对于(int i=0;i0){
附加(',');
}
附加(“?”);
}
try(PreparedStatement ps=con.PreparedStatement(
删除订单\u QRY.replace(“:ORDERS”,包括.toString())){
对于(int i=0;i
性能缓慢的原因是DB将接收到一批语句,但仍然逐个执行它们
另一种方法是使用in()
子句手动批处理语句,以允许DB使用每个批处理大小执行一条语句
然而,为了仍然获得查询缓存的好处,您不能简单地在一个in()
子句中发送所有内容,而应该对它们进行适当的批处理
private static final int MIN = 1;
private static final int SML = 4;
private static final int MED = 11;
private static final int MAX = 51;
private static final String DEL_ORDERS_QRY
= "DELETE FROM Order WHERE OrderNum in (:orders)";
public void deleteOrders(Collection<Integer> origIds) {
int done = getJdbcTemplate().execute((Connection con) -> {
// Reuse this query, `:orders` is a placeholder for the in-clause.
LinkedList<Integer> ids = new LinkedList<>(origIds);
int remainder = ids.size();
int updated = 0;
while (remainder > 0) {
// identify the batch size for this execution.
int batchSize;
if (remainder >= MAX) {
batchSize = MAX;
} else if (remainder >= MED) {
batchSize = MED;
} else if (remainder >= SML) {
batchSize = SML;
} else {
batchSize = MIN;
}
remainder -= batchSize;
// Build the in-clause parameters.
StringBuilder inClause = new StringBuilder(batchSize * 2);
for (int i = 0; i < batchSize; i++) {
if (i > 0) {
inClause.append(',');
}
inClause.append('?');
}
try (PreparedStatement ps = con.prepareStatement(
DEL_ORDERS_QRY.replace(":orders", inClause.toString()))) {
for (int i = 0; i < batchSize; i++) {
ps.setInt(i + 1, ids.pop());
}
updated += ps.executeUpdate();
} catch (SQLException ex) {
log.error("Couldn't execute batch", ex);
throw new RuntimeException(ex.getMessage(), ex);
}
}
return updated;
});
}
private static final int MIN=1;
专用静态最终int SML=4;
专用静态最终int MED=11;
专用静态最终int MAX=51;
私有静态最终字符串DEL_ORDERS_QRY
=“从OrderNum所在的订单中删除(:orders)”;
公共作废删除订单(收款来源){
int done=getJdbcTemplate().execute((连接con)->{
//重用此查询,`:orders`是in子句的占位符。
LinkedList ID=新的LinkedList(origIds);
int rements=ids.size();
int=0;
而(余数>0){
//标识此执行的批大小。
int批量大小;
如果(余数>=最大值){
batchSize=最大值;
}否则如果(余数>=MED){
batchSize=MED;
}否则如果(余数>=SML){
batchSize=SML;
}否则{
batchSize=MIN;
}
余数-=批量大小;
//构建in子句参数。
StringBuilder Incluse=新的StringBuilder(批量大小*2);
对于(int i=0;i0){
附加(',');
}
附加(“?”);
}
try(PreparedStatement ps=con.PreparedStatement(
删除订单\u QRY.replace(“:ORDERS”,包括.toString())){
对于(int i=0;i
我建议使用,而不是删除然后插入。我最后做了一次更新,并根据更新计数执行了一次插入。有助于提高性能