@Stateless or @Singleton instead of a static helper class?

I support some old JEE code that works fine, but uses some static helper classes in which the entity manager is passed in methods from the calling EJB (s) as follows:

public class StaticHelper { public static void helpingOut(EntityManager entityManager, String value) { // ie insert value } } 

Since this does not seem to be very suitable for JEE and not suitable for unit-test, I converted these helpers to @Stateless EJB as:

 @Stateless public class StatelessHelper { @PersistenceContext(unitName="SuperUnit") private EntityManager entityManager; public void helpingOut(String value) { // ie insert value } } 

Similarly, I can insert a mocking helper in the calling EJB with the CDI-Unit .

Now, depending on the load, 1-3 instances of this helper without saving are created by the container, which is not a problem at all, I would say, but in any case I was thinking about @Singleton using either @ConcurrencyManagement(ConcurrencyManagementType.BEAN) or @Lock(LockType.READ) to make it multithreaded, but this does not seem to be a good idea, since EntityManager not thread safe. Or is the explanation here still applied?

"... A container serializes calls for each state and an idle session bean instance. Most containers will support many bean sessions at the same time; however, each instance only sees a serialized sequence of method calls. Therefore, a state or session without a bean should not be encoded as reentrant ... "

+5
source share
1 answer

I created a simple project to test / test how the container handles transactions in SLSB and Singleton . I reviewed the following cases:

  • Using @PersistenceContext EntityManager inside SLSB
  • Using directly @Datasource inside SLSB
  • Using @Datasource inside a @Singleton


Below are the findings of the test.

EntityManager ( DashboardEM )

  • EntityManager is reliable. With the default isolation level, this is enough to avoid data inconsistency.
  • When a parallel exception occurs, the container is rolled back, so handle the appropriate system exceptions so as not to lose data. In our case, a OptimisticLockException thrown, so we forward the point to the panel.
  • An "instance" of EnityManager is injected into each instance of the SLSB container. Subsequently, the EntityManager is responsible for data consistency.
  • SLSB is safe in the sense that a container ensures that only one thread can execute one instance at a time (but different instances run simultaneously in separate threads)

@Singleton ( DSSegmentSingleton )

  • It makes sense to use @Singleton only when directly using the source. With Lock.WRITE you increase isolation levels between threads / instances to SERIALIZABLE .
  • It creates a bottleneck, all threads (clients) must wait one after another to execute this method.
  • Lose the advantage of having multiple instances without considering the state in the pool (implies that multiple clients can do things at the same time).
  • In the case of @Singleton , the execution time will increase with an increase in the number of clients, because everyone will be waiting for each other. For 100 clients, the 100th client will wait for 99 x one runtime.
  • With @Singleton , runtime increases as the number of concurrent clients increases. For example: if 100 clients call Singleton SLSB at the same time, the last client will have a runtime (99 x runtime).

Other solutions if you do not have EntityManager

  • Use the isolation level directly in the database ( select ... for update ). See DashboardDSSelectForUpdate
  • Using TransactionManagement(BEAN) and changing the isolation level of a connection of type conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); See DashboardDSTxBean

see also

0
source

Source: https://habr.com/ru/post/1272468/


All Articles