【问题标题】:How to implement custom thread-safe sequence with hibernate 4?如何使用 hibernate 4 实现自定义线程安全序列?
【发布时间】:2014-08-25 17:14:06
【问题描述】:

我需要实现一个解决方案来为不同种类但相同类型的对象(相同的类,相同的表)生成序列号。更重要的是,序列生成的规则是在运行时定义的(起始序列、最大数量等)。 我正在使用 MySQL,休眠 MySQL5Dialect 不支持序列生成,因此我选择使用序列表来实现此功能,其中每一行是不同类型对象的序列:

+--------------------+--------------+------+-----+---------+-------+
| Field              | Type         | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------+-------+
| seqenceName        | varchar(255) | NO   | PRI | NULL    |       | 
| nextVal            | bigint(20)   | NO   |     | NULL    |       | 
+--------------------+--------------+------+-----+---------+-------+

我创建了一个增加值的 dao:

public synchronized long getNextValue(String seqenceName) throws MySequenceNotFoundException {

        MySequence seq = findByID(seqenceName);

        if (seq == null) {
            throw new MySequenceNotFoundException("Sequence does not exist with name: " + seqenceName);
        }//if not exists

        long nextVal = seq.getNextVal();
        getCurrentSession().saveOrUpdate(seq);

        return nextVal;
    }

这从服务层调用为:

@Transactional(readOnly=false, propagation=Propagation.REQUIRES_NEW, isolation=Isolation.SERIALIZABLE)
    public synchronized long incSequence(String seqName) throws MySequenceNotFoundException {

        getCurrentSession().getTransaction().begin();

        MySequence seq = sequenceDao.findByID(seqName);

        LockRequest lockRequest = getCurrentSession().buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_WRITE));
        lockRequest.lock(seq);

        long l = sequenceDao.getNextValue(seqName);
        getCurrentSession().getTransaction().commit();

        return l;
    }

我尝试了一切:将隔离级别设置为Isolation.SERIALIZABLE,以编程方式在方法内提交事务,向其中添加synchronized 关键字,还添加了锁定请求,但我认为它已经过时了,因为隔离级别已经设置。

如果我创建 100 个线程并从每个线程调用此方法 60 次,结果是 nextVal 列的值约为 4000 而不是 6000。

我怀疑我在这里遗漏了一些非常基本的东西,但不知道需要什么才能按预期工作。

感谢任何提示!

【问题讨论】:

  • 您好,您找到解决问题的方法了吗?我也面临同样的问题。

标签: java multithreading hibernate spring-transactions transaction-isolation


【解决方案1】:

使用select ... for update,Hibernate 支持它 - 请参阅我的answer here

【讨论】:

  • 感谢您的回答!是的,它也是一个可行的选择。我也将对此进行测试。
【解决方案2】:

它看起来像原子变量问题:) 请查看http://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html 并尝试使用 AtomicInterger 而不是 int。

【讨论】:

  • 感谢您的回答,但这与我的问题无关...从性能的角度来看,同步方法可能不是最佳的,但它们应该具有相同的效果。更重要的是,我认为理想情况下我不应该需要同步,因为它应该在数据库事务级别上得到保证......同步方法只是出于恐慌:)
【解决方案3】:

似乎答案在于一个相关的问题:how-to-use-hibernate-in-a-multi-threaded-application

我唯一错过的是每次增加计数器时都调用getCurrentSession().flush(),因为我没有考虑到我的服务层为测试客户端创建的每个线程使用单独的会话,因此没有刷新会话我无法在线程之间同步计数器。

【讨论】:

    猜你喜欢
    • 2012-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-24
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    相关资源
    最近更新 更多