Java 使用Hibernate和多线程大容量更新DB2

Java 使用Hibernate和多线程大容量更新DB2,java,hibernate,exception,db2,Java,Hibernate,Exception,Db2,我需要更新DB2数据库中超过1000000条记录。 我尝试使用hibernate和多线程应用程序更新记录。然而,在这样做时,我得到了lockacquisitionexception。我觉得这是因为我与多个线程一起进行批量提交。 有人能推荐一个更好的解决方案或更好的方法吗。 如果我需要上传我正在使用的代码,请告诉我。 提前谢谢 //Code running multiple times with threads Transaction tx = null; tx = session.begin

我需要更新DB2数据库中超过1000000条记录。 我尝试使用hibernate和多线程应用程序更新记录。然而,在这样做时,我得到了lockacquisitionexception。我觉得这是因为我与多个线程一起进行批量提交。 有人能推荐一个更好的解决方案或更好的方法吗。 如果我需要上传我正在使用的代码,请告诉我。 提前谢谢

//Code running multiple times with threads 
Transaction tx = null; 
tx = session.beginTransaction(); 
for(EncryptRef abc : arList) { 
String encrypted = keyUtils.encrypt(abc.getNumber()); //to encrypt some data
Object o = session.load(EncryptRef.class,new Long(abc.getId())); //primary key EncryptRef object = (EncryptRef)o; 
object.setEncryptedNumber(encrypted); //updating the row 
} 
tx.commit(); //bulk commiting the updates
表只包含三列。ID |明文|加密文本

更新: 我尝试使用JDBC准备的statemenets进行批量更新。但是,我仍然面临以下例外情况:

com.ibm.db2.jcc.am.BatchUpdateException: [jcc][t4][102][10040][3.63.75]批次失败。这批货很便宜 已提交,但单个成员上至少发生一个异常 一批中的一批。使用getNextException()检索的异常 特定的批处理元素。错误代码=-4229,SQLSTATE=null com.ibm.db2.jcc.am.fd.a(fd.java:407)位于 com.ibm.db2.jcc.am.n.a(n.java:386)位于 com.ibm.db2.jcc.am.zn.a(zn.java:4897)位于 com.ibm.db2.jcc.am.zn.c(zn.java:4528)位于 com.ibm.db2.jcc.am.zn.executeBatch(zn.java:2837)位于 org.npci.ThreadClass.run(ThreadClass.java:63)位于 run(Thread.java:748)

以下是批量大小为50-100条记录时执行的代码:

String queryToUpdate = "UPDATE INST1.ENCRYPT_REF SET ENCR_NUM=? WHERE ID=?";
            PreparedStatement pstmtForUpdate = conn.prepareStatement(queryToUpdate);
            for (Map.Entry<Long,String> entry : encryptMap.entrySet()) {
                pstmtForUpdate.setString(1, entry.getValue());
                pstmtForUpdate.setLong(2, entry.getKey());
                pstmtForUpdate.addBatch();
            }
            pstmtForUpdate.executeBatch();
            conn.close();
String queryToUpdate=“UPDATE INST1.ENCRYPT\u REF SET ENCR\u NUM=?其中ID=?”;
PreparedStatement pstmtForUpdate=conn.prepareStatement(queryUpdate);
对于(Map.Entry:encryptMap.entrySet()){
pstmtForUpdate.setString(1,entry.getValue());
setLong(2,entry.getKey());
pstmtForUpdate.addBatch();
}
pstmtForUpdate.executeBatch();
康涅狄格州关闭();

在不了解数据库结构的情况下,很难推荐特定的解决方案。如果可以更改数据库,一个好的策略是对表进行分区,然后安排每个线程更新一个单独的分区。与其让多个线程更新一个大型数据库并相互冲突,不如让每个线程都更新自己的小型数据库

您还应该确保有效地批处理更新,而不是过于频繁地提交更新


如果您的表有大量索引,那么在更新后删除部分/全部并重建可能比持续更新更有效。类似地,您可能会考虑删除触发器、引用完整性约束等,然后再修补。

< P>不是问题的答案。用于更好的格式化

要捕获实际的DB2SQLCode,请使用以下技术。否则就不可能理解问题的根本原因

try {
  ...
} catch (SQLException ex) {
    while (ex != null) {
        if (ex instanceof com.ibm.db2.jcc.DB2Diagnosable) {
            com.ibm.db2.jcc.DB2Diagnosable db2ex = 
        (com.ibm.db2.jcc.DB2Diagnosable) ex;
            com.ibm.db2.jcc.DB2Sqlca sqlca = db2ex.getSqlca();
            if (sqlca != null) {
              System.out.println("SQLCODE: " + sqlca.getSqlCode());
              System.out.println("MESSAGE: " + sqlca.getMessage());
            } else {
            System.out.println("Error code: " + ex.getErrorCode());
            System.out.println("Error msg : " + ex.getMessage());
            }
        } else {
        System.out.println("Error code (no db2): " + ex.getErrorCode());
        System.out.println("Error msg  (no db2): " + ex.getMessage());
      }
        ex = ex.getNextException();
    }
    ...
}
至于ENCR_NUM字段。 是否可以在应用程序之外获得此列的实际值? 或者这些值只能由应用程序生成


您是否必须更新所有表行,或者需要更新的ID集上是否存在某些条件?

最好描述您使用的更新逻辑,并指定您是否能够在单个事务中执行此操作(您必须具有适当的事务日志大小)。此外,您还应描述操作要求。具体来说,是指运行批量更新时的并发性要求。确保对Hibernate生成的UPDATE(或MERGE)语句编制索引,并使用适当的隔离级别。如果要更新的列已编入索引,或是外键,或具有触发器,则可能会应用不同的建议。所以:您的问题太模糊,无法得到具体的答案。当您运行此代码时,Hibernate是否会在更新它之前先选择行?(如果还没有,请打开SQL日志记录。)您实际上没有从对象访问任何字段,因此无需读取它。一般来说,Hibernate是执行此类更新的糟糕方法;您最好只使用SQL。我也尝试了JDBC准备的语句。但是没有运气。更新代码以供参考。我们也可以在应用程序外部生成ENCR_NUM字段。我们需要为特定ID更新此值。需要在更短的时间内更新的问题超过1000000个,这就是我想要使用多线程的原因。那么,为什么不只使用一条语句,比如
updateinst1.ENCRYPT\u REF SET ENCR\u NUM=WHERE ID
?你用这个有什么错误?我很乐意这样做。问题是加载如此多的记录,并用最少的时间。如果我尝试多线程,它会导致锁定表。很难相信,与这样一个
update
语句相比,即使多个同时连接执行单行更新,您也可以更快地执行此操作。唯一值得关注的是,这样一次
更新
可能会为您的系统消耗大量日志空间。您能否建议一种方法,在较短的时间内更新DB2中的这么多记录。