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

时间:2017-10-09 21:35:26

标签: multithreading unit-testing java-ee ejb

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

public class StaticHelper {

    public static void helpingOut(EntityManager entityManager, String value) {
        // i.e. insert value
    }
}

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

@Stateless
public class StatelessHelper {

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

    public void helpingOut(String value) {
        // i.e. insert value
    }
}

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

现在,根据负载,容器会创建1-3个无状态助手的实例,这根本不是问题,但无论如何,我想到@Singleton使用@ConcurrencyManagement(ConcurrencyManagementType.BEAN) 1}}或@Lock(LockType.READ)使其成为多线程 - 但这似乎不是一个好主意,因为EntityManager不是线程安全的。或者这explained here仍适用吗?

  

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

1 个答案:

答案 0 :(得分:0)

我创建了一个simple project来检查/测试容器如何处理SLSBSingleton中的事务。我提到的案例是:

  • @PersistenceContext EntityManager
  • 中使用SLSB
  • 直接在@Datasource
  • 内使用SLSB
  • @Datasource
  • 中使用@Singleton


低于测试结论。

EntityManager(DashboardEM

  • EntityManager可靠。使用默认隔离级别,足以避免数据不一致。
  • 当发生并发异常时,容器将回滚,因此请妥善处理系统异常,以免丢失数据。在我们的情况下,会抛出OptimisticLockException,因此我们将重新发送到信息中心
  • A" copy " EnityManager的{​​{1}}被容器注入到每个SLSB个实例中。之后,EntityManager负责数据一致性。
  • SLSB 安全意味着容器一次只保证一个线程可以执行单个实例(但不同的实例在不同的线程中并发运行)< / LI>

@Singleton(DSSegmentSingleton

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

当您没有EntityManager

时的其他解决方案
  • 直接在DB(select ... for update)中使用隔离级别。请参阅DashboardDSSelectForUpdate
  • 使用TransactionManagement(BEAN)并更改连接的隔离级别,例如conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);请参阅:DashboardDSTxBean

另见