【问题标题】:How to isolate transactions with hibernate如何使用休眠隔离事务
【发布时间】:2017-03-11 19:10:30
【问题描述】:

我已阅读有关isolation levelshibernate 文档,并在一个示例中使用PostgreSql 对其进行了尝试,以检查它们是否能保证并发执行同一数据集上的事务时的线程安全。我用最强的isolation levelSerializable为:

<property name="hibernate.connection.isolation">8</property>

这段代码是:

ExecutorService service = Executors.newFixedThreadPool(10);
    IntStream.range(0, 20).forEach(t -> {
        service.submit(() -> {
            updateSalary(2L);
        });
    });

static void updateSalary(long id) {

    Session s = sessionFactory.openSession();
    org.hibernate.Transaction tx = null;

    try {
        tx =  s.beginTransaction();
        Customer c = (Customer) s.load(Customer.class, id);
        c.setSalary(c.getSalary() + 10);

        tx.commit();
    }
    catch(Exception e) {
        e.printStackTrace();
        tx.rollback();
    }
    finally {
        s.close();
    }

}

但是抛出异常:

 org.postgresql.util.PSQLException: ERROR: could not serialize access due to concurrent update

如果我使用ReentrantLock 同步方法updateSalary()

static void updateSalary(long id) {
    lock.lock();
    Session s = sessionFactory.openSession();
    org.hibernate.Transaction tx = null;

    try {
        tx =  s.beginTransaction();
        Customer c = (Customer) s.load(Customer.class, id);
        c.setSalary(c.getSalary() + 10);

        tx.commit();
    }
    catch(Exception e) {
        e.printStackTrace();
        tx.rollback();
    }
    finally {
        s.close();
    }
    lock.unlock();
}

它可以工作并且是线程安全的。这是在休眠事务中实现线程安全的适当方法吗?如果没有,推荐的方法是什么?在这种情况下,如何使用Session.buildLockRequest() 实现线程安全?

【问题讨论】:

    标签: java multithreading hibernate transactions


    【解决方案1】:

    事务并非旨在使程序线程安全。它们用于保证对数据库的一组更改要么全部应用要么根本不应用,包括确保您读取的数据在事务期间没有更改。

    您看到的行为完全符合预期。数据库检测到并发更新并抛出异常通知您,因此您可以采取适当的措施(例如重试,或通知用户数据可能已更改)。

    【讨论】:

    • 如果在尝试修改同一组数据时有多个请求到达服务器会发生什么?隔离级别“Serializable”是否足以确保数据一致性?为什么它不适用于多线程?
    • 仅仅因为抛出异常警告您并发更新并不意味着数据变得不一致。实际上,该异常意味着可能会发生潜在的不一致更新,但 PostgreSQL 拒绝了它。您的数据仍然是一致的,或者您是否经历过不一致?
    • “update”只执行了5次而不是20次,这是线程数。
    • 是的,所以您预计工资总共增加了 50。其他 15 次更新失败,但没有因为计算错误而损坏工资数据。在没有事务的情况下运行您的代码,然后看看会发生什么……您会发现,尽管发生了所有更新,但即使您的程序打印了 20 倍,它使薪水增加了 10 倍,薪水也不会高出 200(换句话说,它不再一致了)。
    • 我不打算在没有事务的情况下运行它。我需要知道,如何正确执行所有事务以使数据库达到预期状态。
    【解决方案2】:

    正如 john16384 回答的那样,事务旨在确保一组语句是否一起执行。

    我不会在关键方法上加锁,因为它会影响性能和可伸缩性。我会让方法同时执行,但使用 Hibernates VERSION 列来确定数据在获取后是否已更新。您可以找到大量关于使用 Hibernate VERSION 列方法的资料。

    【讨论】:

      猜你喜欢
      • 2019-03-16
      • 1970-01-01
      • 2016-03-19
      • 2019-12-13
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 2015-08-30
      • 1970-01-01
      相关资源
      最近更新 更多