【问题标题】:Hibernate session thread safety休眠会话线程安全
【发布时间】:2013-12-07 15:26:09
【问题描述】:

我知道会话不是线程安全的。我的第一个问题:将实体传递给另一个线程是否安全,对其进行一些工作,然后将其传递回原始线程并进行更新。

public class Example1 {
    MyDao dao;
    ...
    public void doWork() {
        MyEntity entity = dao.getEntity();
        Runnable job = new Job(entity);
        Thread t = new Thread(job);
        t.run();
        t.join();
        dao.merge(entity);
    }

}

我的第二个问题:在一个线程中新建一个实体并将其保存在另一个线程中是否安全?

public class Example2 {
    MyDao dao;
    ...
    public void doWork() {
        MyEntity entity = new Entity();
        new Thread(new Job(dao, entity)).run();
    }
}

public class Job implements Runnable {
    private MyDao dao;
    private MyEntity entity;
    ...
    @Override
    public void run() {
        dao.save(entity);
    }
}

编辑我忘了提到实体是专门为预先加载而配置的

【问题讨论】:

  • 第二个例子肯定是不安全的——我想你也会得到一个异常,因为你在 DAO 中使用的会话绑定到另一个线程而不是你的 Job。关于第一个我不确定。
  • 我实现它的方式,MyDao.merge() 本质上是sessionFactory.getCurrentSession.merge(entity); 所以它使用会话绑定到调用它的线程。
  • 您为什么对创建自己的主题感兴趣?
  • 我正在“外包”给其他线程,因为这项工作很容易并行化,并且每个单独任务的瓶颈是网络延迟。这个的真实版本使用线程池

标签: java multithreading hibernate


【解决方案1】:
  1. 没有。该实体附加到会话并包含链接到会话的代理(为了延迟加载自己)。因此,这样做会使用来自多个线程的会话。由于会话不是线程安全的,因此这不是一个好主意。

  2. 虽然实体是瞬态的(即您刚刚使用 new 创建了它),但它没有附加到会话,Hibernate 不知道它,并且实体是一个普通的旧 Java 对象。所以这样做没问题。不过,我没有你的 DAO 的所有细节。如果您的 DAO 的方法应该作为现有事务的一部分被调用,那将不起作用,因为该事务与当前线程相关联。

【讨论】:

  • 对不起,我忘了说一切都在急切地加载。事务边界不应该成为问题,所以我认为您对 2 的回答适用。急切加载是否会将您的答案更改为 1?
  • 广告2:不取决于使用哪个线程创建会话和启动事务吗?
  • 如果你能保证会话永远不会被使用,我不明白为什么它不起作用,但是这样的保证很难提供(现在和将来)。将所需的状态复制到其他对象并传递该对象会更安全。或者在生成的线程中按 ID 重新加载实体。
  • @isnot2bad:是的,准确地说。如果在派生线程中调用的 DAO 方法获得一个新会话、启动一个事务、保存实体、提交事务并关闭会话,那么瞬态实体来自另一个线程的事实并不重要。如果 DAO 应该保存实体,并且保存应该是第一个线程创建的事务的一部分,那将不起作用。
  • @JBNizet 好的。我假设 DAO 在构建时得到了它的会话。但你是对的 - 我们并不确切知道......
猜你喜欢
  • 2015-04-11
  • 1970-01-01
  • 2012-05-29
  • 1970-01-01
  • 1970-01-01
  • 2011-06-08
  • 1970-01-01
  • 2012-06-29
  • 2012-06-02
相关资源
最近更新 更多