我在我的一个项目中使用JPA 2.0和SpringBoot。由于应用程序需要大量只读查询,因此我决定将entityManager标记为的单例(Autowired)类 的 @PersistenceContext(类型= PersistenceContextType.EXTENDED)即可。
扩展实体管理器的这个实例又被众多DAO(可能在多个线程中)用于其只读请求。由于实体曾经在扩展的持久化上下文中,因此对实体进一步详细说明(如果你愿意的话,保留)的调用从未给出LazyInitializationException。此外,由于实体一旦加载,总是存在于扩展持久化上下文的活动内存中,用于获得优异的性能。
但是,随着时间的推移,我偶尔会在访问其中一个托管实体的某个字段时开始获取 NullPointerException 。这种行为是不确定的。
// .. earlier code skipped for brevity
Child child = refNode.getFirstChild();
if (child != null) {
// Print confirms that the object is managed. In fact, earlier merely
// inserting print statement would dissolve the error.
System.out.printf ("Child ID = %s %s\n", child.getChildID(), childDAO.getContext(child));
// NPE while accessing latestVersion attribute of 'Child'.
// Values does exist in DB.
Unode un = child.getLatestVersion().getuNode();
return un;
}
儿童的相关部分'实体如下:
public class Child implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int childID;
...
@ManyToOne(cascade={CascadeType.ALL})
@JoinColumn(name="latestVersionID")
private Version latestVersion;
是的,我也非常慷慨地收到了以下错误。
HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: possible non-threadsafe access to the session
最近我也得到了ConcurrentModificationException',不安全的线程访问,以及代码中所有类型的干净部分中的类似错误。我也尝试在所有访问中使用synchronized(互斥)来使我的扩展上下文实体管理器线程安全,但没有帮助。
我最担心的是一个托管实体(在扩展上下文中),提供null指向异常。虽然例外似乎是非确定性的,但它们似乎往往集中在“儿童”的地方。或者' Child.LatestVersion'被访问。
我试过,懒惰加载,急切加载等,但没有用。我的理解(到目前为止)是前向实体被急切地加载,反向实体被懒惰地加载,并且在管理实体时(在任何上下文中 - 扩展或事务性)从不出现空指向异常。
真诚地感谢任何帮助。
答案 0 :(得分:0)
答案很简单:EntityManager
不是线程安全的。参见例如在这里:https://docs.jboss.org/hibernate/entitymanager/3.6/reference/en/html/transactions.html#transactions-basics-issues
你应该做的是你应该停止尝试重复使用它。 EntityManager
与(EntityManagerFactory
相比)创建成本低廉。