【问题标题】:How do I handle Lock wait timout exceeded in a correct manner?如何以正确的方式处理超过锁定等待超时?
【发布时间】:2012-05-21 14:07:25
【问题描述】:

我正在运行一项导入工作,该工作一直运行良好,直到几天前实体数量急剧增加。

发生的情况是,我得到了一个 Lock wait timeout 超出。然后应用程序重试并抛出异常,因为我再次调用 em.getTransaction().begin(); 一次。

为了解决这个问题,我将 innodb_lock_wait_timeout 更改为 120 并 将批处理方面降低到 50 个实体。

我不知道如何在代码中正确处理所有这些。我不希望整个导入因为锁定而失败。你会怎么处理这个?你有代码吗 例子?也许还有其他想法?请发疯!

我的 BatchPersister:

public class BatchPersister implements Persister {

    private final static Log log = getLog(BatchPersister.class);
    private WorkLogger workLog = WorkLogger.instance();

    private static final int BATCH_SIZE = 500;

    private int persistedObjects;
    private long startTime;
    private UpdateBatch batch;
    private String dataSource;


    public BatchPersister(String dataSource) {
        this.dataSource = dataSource;        
    }

    public void persist(Persistable obj) {

        persistedObjects++;
        logProgress(100);

        if (batch == null)
            batch = new UpdateBatch(BATCH_SIZE, dataSource);

        batch.add(obj);

        if (batch.isFull()) {
            batch.persist();
            batch = null;
        }
    }
}

UpdateBatch

public class UpdateBatch {

    private final static Log log = LogFactory.getLog(UpdateBatch.class);
    private WorkLogger workLogger = WorkLogger.instance();

    private final Map<Object, Persistable> batch;
    private final EntityManager em;
    private int size;

    /**
     * Initializes the batch and specifies its size.
     */
    public UpdateBatch(int size, String dataSource) {
        this.size = size;
        batch = new LinkedHashMap<Object, Persistable>();
        em = EmFactory.getEm(dataSource);
    }    

    public void persist() {
        log.info("Persisting " + this);
        em.getTransaction().begin();    
        persistAllToDB();
        em.getTransaction().commit();

        WorkLog batchLog = new WorkLog(IMPORT_PERSIST, IN_PROGRESS);
        batchLog.setAffectedItems(batch.size());
        workLogger.log(batchLog);
        em.close();
   }

/**
  * Persists all data in this update batch
  */
    private void persistAllToDB() {
        for (Persistable persistable : batch.values())
            em.persist(persistable);
        }

        @Override
        public String toString() {
            final ArrayList<Persistable> values = new ArrayList<Persistable>(batch.values());
            Persistable first = values.get(0);
            Persistable last = values.get(values.size() - 1);
            return "UpdateBatch[" +
                first.getClass().getSimpleName() + "(" + first.getId() + ")" +
                " - " +
                last.getClass().getSimpleName() + "(" + last.getId() + ")" +
                "]";
         }
    }
}

【问题讨论】:

    标签: java mysql hibernate jpa


    【解决方案1】:

    解决方案 1. 不要使用 JPA,它不是为处理大量数据库操作而设计的。由于您可以访问您的数据源并且您正在手动管理事务,因此没有什么可以阻止您使用普通的旧 SQL。

    解决方案 2。 可能存在与持久化上下文一级缓存相关的性能问题 - 每个持久化实体都保存在该缓存中,当该缓存变大时可能会损害性能(主要是内存)

    为了改善情况,将 hibernate.jdbc.batch_size 属性(或等效的,如果您不使用 JPA 的 Hibernate 实现)设置为或多或少 20 - 由于查询将在 20 个查询包中发送到数据库。

    每 20 次操作第二次清理持久化上下文,强制与数据库同步。

    private void persistAllToDB() {
        int counter = 0;
        for (Persistable persistable : batch.values())
            em.persist(persistable);
            counter++;
            if(counter % 20 == 0){
               em.flush();
               em.clear();
            }
        }
    }
    

    解决方案 3。 调整 MySQL InnoDB 引擎 [http://dev.mysql.com/doc/refman/5.1/en/insert-speed.html, http://dev.mysql.com/doc/refman/5.0/en/innodb-tuning .html]。如果您的表被大量索引,则可能会损害插入性能。

    这是我的猜测,希望对你有所帮助。

    【讨论】:

      【解决方案2】:

      Pitor 已经列出了几个选项。我要指出的是,他的“解决方案 2”的一个变体是利用 Hibernate StatelessSession api,而不是使用 Session 和清除。

      但是,您应该考虑的另一件事是,事务是一组预期会失败或成功的语句。如果您有一堆语句,而中间有一个语句失败,并且您希望前面的所有语句都是持久的,那么您不应该将它们组合在一个事务中。在事务中正确分组您的报表。一般来说,无论如何在 Hibernate 中启用 jdbc 批处理是一个好主意;它通常会导致更有效的数据库通信。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-16
        • 2011-01-07
        • 1970-01-01
        • 2019-11-20
        • 2017-02-01
        • 2011-12-25
        • 2018-03-29
        • 1970-01-01
        相关资源
        最近更新 更多