如何正确处理并发?

How to correctly deal with concurrency?

我正在使用 JavaEE 构建 REST API。我正在使用 TomEE 作为应用程序服务器。我有一个 Singleton JPA DAO 来处理 Postgres 数据库和 Stateless 服务来为我的 RESTfull class 提供方法,它有 GETPOSTDELETE 方法。到目前为止,我一直在使用 rest assured 来测试我的 url 路线。一切正常,但我想强调我的系统,所以我这样做了:

  Runnable r1 = () -> {
        for (int i = 0; i < 10; i++) {
            RegisterAndLogService service = new RegisterAndLogService();
            //lots of service calls
        }
    };

    Runnable r2 = () -> {
        for (int i = 0; i < 10; i++) {
            RegisterAndLogService service2 = new RegisterAndLogService();
            //lots of service calls
        }
    };
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);
    t1.start();
    t2.start();

但是当我的一个线程开始第二次迭代时,我得到了这个:

java.lang.IllegalStateException: Transaction already active

我怎样才能堆积 Dao 请求并一次一个地正确处理它们,等待当前事务完成? EJB/JPA 能以某种方式参与其中吗?保存请求并尽快处理它们?

很难理解你在这里做什么,你问的问题是在测试代码中还是在测试中的API ...或者[=48=后面的东西].

但是如果你得到一个 "Transaction already active",这意味着 某事 正在做类似的事情:

  • 尝试使用具有多个线程的单个 JPA 事务管理器(不要),
  • 尝试在同一个线程上同时进行多个事务(不要),或者
  • 不清理(提交或回滚)事务。

在最后一种情况下,寻找可以通过异常从负责事务的代码区域"escape"而不回滚的情况。

我建议您查看您一直在使用的 JPA 文档,以确保您了解事务、事务管理器和线程之间的关系。


I believe my case is the first one - trying to use a single JPA transaction manager with multiple threads. Is there any design pattern or good practice about keeping a single JPA transaction manager while have lots of instances of stateless beans being requested?

唯一可行的方法是让每个线程都有自己的事务管理器。要么每个线程必须以编程方式创建(和释放)自己的 TM,要么您依赖框架来执行此操作;例如按照各种注释的指示。

TM 对象设计为轻量级(即实例化成本低)和非线程安全。你不应该跨线程共享它们1,你不应该需要回收它们。


1 - ...除非您有一个 需要 跨多个线程的 JPA 事务。为此,有 "ways to do it".