@Stateless或@Singleton而不是静态助手类?

Tor*_*mer 5 multithreading unit-testing ejb java-ee

我正在维护一些运行良好的旧JEE代码但是正在使用一些静态辅助类,其中实体管理器从调用EJB传递方法,如下所示:

public class StaticHelper {

    public static void helpingOut(EntityManager entityManager, String value) {
        // i.e. insert value
    }
}
Run Code Online (Sandbox Code Playgroud)

由于这似乎不适合JEE并且对单元测试不好,我已经将这些助手转换为@StatelessEJB,如下所示:

@Stateless
public class StatelessHelper {

    @PersistenceContext(unitName="SuperUnit")
    private EntityManager entityManager;

    public void helpingOut(String value) {
        // i.e. insert value
    }
}
Run Code Online (Sandbox Code Playgroud)

就像我可以在使用CDI-Unit的调用EJB中注入一个模拟帮助器.

现在,根据负载,由这是不是在所有的问题我想说的容器中创建无状态帮手1-3实例,但无论如何,我想过一个@Singleton使用两种@ConcurrencyManagement(ConcurrencyManagementType.BEAN)@Lock(LockType.READ)使其多线程-不过这并未"似乎是一个好主意,因为EntityManager它不是线程安全的.或者这里解释的仍然适用?

"...容器序列化对每个有状态和无状态会话bean实例的调用.大多数容器将支持并发执行的会话bean的许多实例;但是,每个实例只能看到序列化的方法调用序列.因此,有状态或无状态会话bean不必编码为可重入..."

Erm*_*mal 0

我创建了一个简单的项目来检查/测试容器如何处理SLSB和中的事务Singleton。我所涉及的案例有:

  • @PersistenceContext EntityManager内部使用SLSB
  • 直接使用@Datasource内部SLSB
  • 使用 a@Datasource里面的 a@Singleton


下面是测试结论。

实体管理器(仪表板EM

  • EntityManager是可靠的。使用默认的隔离级别足以避免数据不一致。
  • 并发异常发生时,容器会回滚,因此请适当处理系统异常,以免丢失数据。在我们的例子中, aOptimisticLockException被抛出,因此我们将重新发送到仪表板
  • 容器将“副本EnityManager注入每个实例。SLSB然后负责EntityManager数据的一致性。
  • SLSB从某种意义上来说是安全的,容器保证一次只有一个线程可以执行单个实例(但不同的实例在单独的线程中同时运行)

@Singleton(DSSegmentSingleton

  • @Singleton仅当您直接使用时才有意义。随着Lock.WRITE您将线程/实例之间的隔离级别增加到SERIALIZABLE.
  • 它创建了一个瓶颈,所有线程(客户端)必须互相等待才能执行该方法。
  • 失去池中拥有多个无状态实例的好处(意味着多个客户端可以同时执行操作)。
  • 如果@Singleton执行时间会随着客户端的增加而增加,因为每个客户端都会互相等待。对于 100 个客户端,第 100 个客户端将等待 99 x单次执行时间
  • 如果@Singleton执行时间随着并发客户端数量的增加而增加。例如:如果 100 个客户端Singleton SLSB同时调用,最后一个客户端的执行时间将为 ( 99 x执行时间)。

当您没有 EntityManager 时的其他解决方案

  • 直接在DB中使用隔离级别( select ... for update)。请参阅仪表板 DSSelectForUpdate
  • 使用TransactionManagement(BEAN)和更改连接的隔离级别,例如conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);参见:DashboardDSTxBean

也可以看看