用CDI做这样的事情是否安全?
@Named
@ApplicationScoped
public class DAO {
@PersistenceContext
private EntityManager entityManager;
}
Run Code Online (Sandbox Code Playgroud)
我知道它EntityManager本身不是线程安全的,因此不应该在共享的全局上下文中使用@ApplicationScoped.但是,由于注入的对象@PersistenceContext实际上是底层的线程感知包装EntityManager,这是否可以使这个好?
我已经看过关于这个主题的其他帖子,但未能找到这个具体案例的权威答案.例如:
Java CDI @PersistenceContext和线程安全
例如,看起来使用它是安全的@Stateless- 但我不确定这是因为工作方式@Stateless,还是因为@PersistenceContext它本身固有的东西.
编辑
我的困惑的来源是@PersistenceContext注入的EntityManager包装器似乎知道当前的线程,以便弄清楚是否已经有一个正在进行的事务.所以也许我将线程感知与线程安全混淆,它们是两个不同的东西.
EntityManager根据定义,它不是线程安全的.Servlets规范说,在非分布式环境中,如果没有实现SingleThreadModel,每个定义只有一个servlet实例.
因此,在Java EE中,当您EntityManager通过@PersistenceContextServlet的字段注入时- 它不是线程安全的:
public class MyServlet extends HttpServlet {
// Not thread-safe, should be using EMF instead.
@PersistenceContext
private EntityManager em;
}
Run Code Online (Sandbox Code Playgroud)
这是正确的说,即使Spring bean的默认范围是单例,它EntityManager是线程安全的,因为Spring ThreadLocal用来绑定它的事务和EntityManager它?
上面的Servlets示例在Spring中仍然有效吗?它仍然不是线程安全的吗?
该ThreadLocal方法是否仅适用于Spring托管bean,而普通servlet不是其中之一?
据我所知,注入的是容器的责任EntityManager.在Glassfish Java EE实现中,应用程序服务器发现了@PersistenceContextas注入点.
它在Spring中看起来如何?Spring Framework是否负责发现这些注释或JPA实现者的责任?
我在说这里的基本用法:
@Stateless
public class BookServiceBean implements BookService {
@PersistenceContext EntityManager em;
public void create(Book book) { this.em.persist(book);}
}
Run Code Online (Sandbox Code Playgroud)
谷歌上面的问题,StackOverflow说是的,但没有 - 接受的答案是肯定的,但后续的是否定的; Spring.io说是和不,而且似乎是Java EE专家的Adam Bien给出了一个不合格的是.
我对一个简单的预定bean的经验表明答案是否定的:
@Stateless
public class TimerTick implements TimerTickAbs, Runnable {
@PersistenceContext private EntityManager entityManager;
@Override
public void run() {
Query q = entityManager.createQuery("SELECT blah...");
}
@Override
public Runnable runner() {
return this;
}
}
Run Code Online (Sandbox Code Playgroud)
抽象界面:
@Local
public interface TimerTickAbs {
public Runnable runner();
}
Run Code Online (Sandbox Code Playgroud)
开始于:
@Resource ManagedScheduledExecutorService managedExecutorService;
@EJB TimerTick myRunner;
public …Run Code Online (Sandbox Code Playgroud) 基于这个例子:
@Service
public class Purchase {
@PersistenceContext
private EntityManager em;
@Autowired
private PurchaseDAO dao;
private String normalField;
.... // methods, operations, etc
}
Run Code Online (Sandbox Code Playgroud)
如果我错了,请帮助纠正我:
谢谢 !