Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jpa @将@Stateless bean注入@Singleton/@ApplicationScoped bean_Jpa_Jakarta Ee_Thread Safety_Ejb - Fatal编程技术网

Jpa @将@Stateless bean注入@Singleton/@ApplicationScoped bean

Jpa @将@Stateless bean注入@Singleton/@ApplicationScoped bean,jpa,jakarta-ee,thread-safety,ejb,Jpa,Jakarta Ee,Thread Safety,Ejb,我将Java EE@无状态-bean注入到@Singleton/@ApplicationScoped-bean中: @Stateless public class MyStateless { @PersistenceContext private EntityManager em; public void persist(User u){ // for each thread the emProxy is the same log.

我将Java EE
@无状态
-bean注入到
@Singleton
/
@ApplicationScoped
-bean中:

@Stateless
public class MyStateless {

    @PersistenceContext
    private EntityManager em;

    public void persist(User u){ 

        // for each thread the emProxy is the same
        log.info("emProxy={0}", em.toString());

        // for each thread the emDelegate is differently
        log.info("emDelegate={0}", em.getDelegate().toString());

        // this is definitly thread-safe !
        em.persist(u);

    }
}
第1版:

@javax.ejb.Singleton
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@ApplicationScoped
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this hread safe ?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
public class MySingleton {

    @Resource private ManagedScheduledExecutorService managedExecutor;

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        for(int i=0; i<=4;i++){
            managedExecutor.scheduleWithFixedDelay(() 
            -> stateless.persist(new User("hello_" + i)) , 0, 5, TimeUnit.SECONDS);
        }
    }
}
第2版:

@javax.ejb.Singleton
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@ApplicationScoped
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this hread safe ?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
public class MySingleton {

    @Resource private ManagedScheduledExecutorService managedExecutor;

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        for(int i=0; i<=4;i++){
            managedExecutor.scheduleWithFixedDelay(() 
            -> stateless.persist(new User("hello_" + i)) , 0, 5, TimeUnit.SECONDS);
        }
    }
}
第3版:

@javax.ejb.Singleton
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@ApplicationScoped
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this hread safe ?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
public class MySingleton {

    @Resource private ManagedScheduledExecutorService managedExecutor;

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        for(int i=0; i<=4;i++){
            managedExecutor.scheduleWithFixedDelay(() 
            -> stateless.persist(new User("hello_" + i)) , 0, 5, TimeUnit.SECONDS);
        }
    }
}
我有以下声明:

@javax.ejb.Singleton
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@ApplicationScoped
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this hread safe ?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
public class MySingleton {

    @Resource private ManagedScheduledExecutorService managedExecutor;

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        for(int i=0; i<=4;i++){
            managedExecutor.scheduleWithFixedDelay(() 
            -> stateless.persist(new User("hello_" + i)) , 0, 5, TimeUnit.SECONDS);
        }
    }
}
“如果我向任何类型的
@Singleton
@ApplicationScoped
-bean中注入一个
@Stateless
-bean,那么对于
persistUser()
的每次调用,容器池将提供另一个(不一定相同)
MyStateless
的实例。因此,
@Stateless
-bean和
@Singleton
/
@ApplicationScoped
-bean之间没有1:1的关系。这也意味着,容器管理的
EntityManager
注入到我的
@Stateless
-bean中,我的
@Singleton
-bean间接使用它>/
@ApplicationScoped
-bean通过方法
persistUser()
是线程安全的

上述语句是否适用于所有3个版本,或者它们在我的无状态bean中的行为是否会有所不同?

请查看以下特殊情况(第4版):

@javax.ejb.Singleton
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@ApplicationScoped
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this hread safe ?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
public class MySingleton {

    @Resource private ManagedScheduledExecutorService managedExecutor;

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        for(int i=0; i<=4;i++){
            managedExecutor.scheduleWithFixedDelay(() 
            -> stateless.persist(new User("hello_" + i)) , 0, 5, TimeUnit.SECONDS);
        }
    }
}
但每个步骤的委托不同(委托给基础持久性提供程序hibernate):

如果我使用
@ApplicationScoped
,那么所有同时运行的线程都具有相同的
entityManager
-代理,但不同的
entityManager
-代理。因此,我看不出有任何理由选择
@Stateless
而不是
@ApplicationScoped

结论:

@javax.ejb.Singleton
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@ApplicationScoped
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
public class MySingleton{

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this hread safe ?
        stateless.persist(new User("hello"));
    }
}
@javax.ejb.Singleton
public class MySingleton {

    @Resource private ManagedScheduledExecutorService managedExecutor;

    @Inject
    private MyStateless stateless;

    public void persistUser(){
        // is this thread safe?
        for(int i=0; i<=4;i++){
            managedExecutor.scheduleWithFixedDelay(() 
            -> stateless.persist(new User("hello_" + i)) , 0, 5, TimeUnit.SECONDS);
        }
    }
}
上述情况不存在任何问题:

“相同的代理可以在同时运行的线程中使用,只要它们的代理不同。”这些代理是什么(entityManager、无状态Bean等并不重要。)

来自JPA规范(版本2.1,第7.2章):

实体管理器不能在多个并发执行的线程之间共享,因为实体管理器和持久性上下文不需要是线程安全的。只能以单线程方式访问实体管理器

MyStateless
bean可以被许多客户机使用,因为应用服务器负责注入的
EntityManager
。因此,
MyStateless
对于外部世界是线程安全的;从容器中手动生成的线程访问其
EntityManager
(即,不使用应用程序服务器的工具创建的线程,如
ManagedExecutorService
)将是不安全的。我甚至不确定使用相同的
EntityManager
,即使是从容器管理的线程,是否安全。当然,从对应于多个客户端的线程并发使用它是安全的。另请参见EJB规范(版本3.2,第4.8.5章):

在单例会话bean实例状态中存储不支持并发访问(例如,对Java持久性实体管理器或有状态会话bean的引用)的Java EE对象是合法的。但是,Bean提供者有责任确保一次不被多个线程访问这些对象

记住这一点,访问MyStateless的版本1、2、3是可以的,只要它们不出现在手动生成的线程中。版本4可以,因为这只是因为(a)线程是容器管理的,因此容器将确保在每个线程中使用不同的
EntityManager
,(b)每个线程的工作负载是独立的-可以在不同的事务中运行


实际上,注入“客户机”和
MyStateless
注入bean之间没有1-1关系。实际上,容器应该只向每个注入点注入一个代理,代理负责解析要使用的适当实例。

这是否意味着在@Singleton中执行的以下代码不是线程安全的?:
@Resource private ManagedScheduledExecutor Service managedExecutor;。。。public void task(){managedExecutor.scheduleWithFixedDelay(()->stateless.persist(新用户(“hello”)}..,0,5,TimeUnit.SECONDS)ManagedExecutorService中的
无状态.persist(新用户(“hello”)
必须是每个定义的线程安全的,因为我使用的是
无状态的
-bean,在每个
无状态的
-bean中都有一个线程安全的
entityManager
。因此,它总体上是线程安全的。我说得对吗?我不确定容器管理的线程会发生什么情况(正如我上面所写的)。显然,根据您的观察,容器管理的线程得到了一个正确的、单独的
EntityManager
实例。如果每个线程的工作负载独立于其他线程,那么这很可能会起作用。但是EMs不同这一事实也意味着不同的事务,因此如果线程需要在相同的数据上进行协作,那么我认为EM应该被视为非线程安全的。代理只有一个职责:找到bean的适当的真实实例(您提到的委托)并调用它。所以不用担心,注入的“作用域代理”是同一个实例是绝对正常的。关于
无状态
@ApplicationScoped
的区别,有很多参考资料,我建议进行一些独立于此问题的搜索和阅读(因为我们正在慢慢偏离主题)。作为一个例子,我想到的一个区别是会话EJB和CDIBean如何处理事务(默认值:对于EJB为ON,对于CDI为OFF)。还有更微妙的差异,可能会也可能不会影响你的具体情况。