与 Hibernate 一起使用时,HSQLDB mvlocks 并发模型会阻止读取

问题描述 投票:0回答:1

将 HSQLDB 与 Hibernate 和 Spring 结合使用时,我遇到了并发问题。我有两个线程访问同一个表。一个线程有一个长时间运行的读写事务,另一个线程经常以只读方式访问表,但只有一个短事务。主要问题是长时间运行的事务阻塞了较快的事务。

当检查 HSQLDB 的文档时,我发现了不同的并发模型。在这种情况下,MVLOCKS 或 MVCC 似乎应该对我有所帮助。

使用 MVLOCKS 时,这个问题似乎仍然普遍存在,而使用 MVCC 时,这个问题实际上是有效的。我的假设是,使用 MVLOCKS 也应该可以工作,我想了解为什么在这种情况下它不能工作?

我准备了一个显示问题的示例应用程序https://github.com/fridewald/hsqldb-test 它使用普通的休眠会话,因为否则我无法重现问题。

在这里你可以看到我如何在

application.properties
文件中将设置更改为mvlocks或mvcc

# this does not work, it blocks the reads. Why?
spring.datasource.url=jdbc:hsqldb:mem:testdb;hsqldb.tx=mvlocks
# this works
#spring.datasource.url=jdbc:hsqldb:mem:testdb;hsqldb.tx=mvcc

在这里您可以看到长期运行事务的部分

@Component
@Service
public class SlowUpdates {

    ...
    @Scheduled(fixedRate = 10000)
    public void slowlyUpdatingLamps() {
        new Thread(new Runnable() {
            public void run() {
                log.info("try to slow update");
                try (

                        Session session = sessionFactory.openSession();) {
                    session.beginTransaction();

                    long now = System.currentTimeMillis();

                    CriteriaBuilder lCriteriaBu = session.getCriteriaBuilder();
                    CriteriaQuery<Lamp> lQuery = lCriteriaBu.createQuery(Lamp.class);
                    Root<Lamp> lRoot = lQuery.from(Lamp.class);
                    lQuery.select(lRoot).where(lCriteriaBu.equal(lRoot.get("numberOfLamps"), 3));
                    log.info("Lamp read with findById(1L):");
                    List<Lamp> lamps = session.createQuery(lQuery).getResultList();

                    for (Lamp l : lamps) {
                        l.setLastUpdated(now);
                        session.persist(l);
                        log.info(l.toString());
                    }
                    session.flush();
                    // Wait 5 seconds and keep transaction open
                    Thread.sleep(5000);
                    List<Lamp> lamps2 = session.createQuery(lQuery).getResultList();
                    for (Lamp l : lamps2) {
                        l.setLastUpdated(now);
                        session.persist(l);
                        log.info(l.toString());
                    }
                    session.getTransaction().commit();
                    log.info("Session end");
                } catch (Exception e) {
                    log.error("Error in slowlyUpdatingLamps", e);
                }
            }
        }).start();
    }
}

这里是尝试从表中读取的部分

public class FastReads {

    ...

    @Scheduled(fixedRate = 500)
    public void readLamps() {
        log.info("try to fast read");
        try (
                Session session = sessionFactory.openSession();) {
            session.beginTransaction();
            session.setDefaultReadOnly(true);
            log.info("Lamp read with findById(1L):");
            Lamp lamp = session.get(Lamp.class, 1L);
            log.info(lamp.toString());
            session.getTransaction().commit();
        } catch (Exception e) {
            log.error("Error in readLamps", e);
        }
    }
}

我已经尝试为读取事务设置

session.setDefaultReadOnly(true);
,但这没有任何效果。是否有另一种方法告诉 hibernate 事务或会话是只读的,将被正确转发到 hsqldb?

在 hsqldb 数据库上尝试使用两个 sql 控制台的类似示例时,mvlocks 的行为符合预期。

java spring hibernate concurrency hsqldb
1个回答
0
投票

Hibernate的只读模式不影响数据库事务。这是 Hibernate 级别的内部优化,可让您避免浪费资源来跟踪从数据库加载的对象的更改。交易最好尽可能短。如果您需要处理大量数据,那么进行多笔短交易比进行一笔长交易更有意义。

© www.soinside.com 2019 - 2024. All rights reserved.