@PersistenceContext不适用于参数。如何通过构造函数注入EntityManager?

时间:2019-02-01 11:51:26

标签: java spring hibernate spring-boot jpa

使用构造函数注入是最佳实践。但是我无法通过@PersistenceContext来实现。

我想要以下构造函数:

private final EntityManager entityManager;

@Autowired
public MyService(@PersistenceContext EntityManager entityManager) {
    this.entityManager = entityManager;
}

但是我不能,因为@PersistenceContext仅适用于TYPEMETHODFIELD

问::如何通过构造函数注入来注入一个容器管理的 EntityManager

2 个答案:

答案 0 :(得分:1)

您似乎正在使用spring,因此您的解决方案将很容易:

@Component
@Scope("prototype")
public class MyPersistenceContainer
{
@PersistenceContext
private EntityManager em;

public EntityManager getEntityManager()
{
return em;
}
}

现在您可以简单地在构造函数中注入此类的实例,它将始终持有有效的EntityManager(由于bean作用域)。提醒您:在网络环境中,您可能应该使用@SessionScope甚至@RequestScope而不是原型,这样可以节省资源


但是有一些要考虑的问题:

  

使用依赖于以下对象的单例作用域的bean时,   仅限原型,请注意依赖项是   在实例化时间解决。这意味着如果您依赖   将原型范围内的bean注入一个单一范围内的bean,一个品牌   新的原型bean将被实例化,然后注入依赖项   到单例豆中...但是仅此而已。完全一样的原型   实例将是曾经提供给的唯一实例   单身范围的bean,如果您想要的话,这很好。

     

但是,有时您真正想要的是单例作用域   bean能够获得一个全新的实例   在运行时,原型范围内的bean一次又一次。在那里面   情况下,仅依赖项注入一个原型作用域的bean是没有用的   放入您的Singleton bean中,因为如上所述,   当Spring容器实例化单例时发生一次   Bean并解析并注入其依赖项。如果你在   您需要获取(原型)的全新实例的场景   bean在运行时一次又一次地被引用   标题为第4.3.7节“方法注入”的部分

因此,如果要将“ entity manager container-bean”注入到Singleton bean中,(这是默认范围),请查看https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-method-injection


正确设置作用域非常重要,否则您可能(并且将会)有数据库不一致,死锁或更严重的情况

答案 1 :(得分:0)

使用 Spring Data 应该是可能的。但是,如果您出于某种原因不想在您的项目中使用 Spring Data(例如,您只是将遗留项目做得更好),您可以创建以下 FactoryBean 以使 EntityManager 通过构造函数注入:

/**
 * Makes the {@link EntityManager} injectable via <i>@Autowired</i>,
 * so it can be injected with constructor injection too.
 * (<i>@PersistenceContext</i> cannot be used for constructor injection.)
 */
public static class EntityManagerInjectionFactory extends AbstractFactoryBean<EntityManager> {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Class<?> getObjectType() {
        return EntityManager.class;
    }

    @Override
    protected EntityManager createInstance() {
        return entityManager;
    }

}

请注意,因为我们在内部使用 @PersistenceContext 注释,返回的 EntityManager 将是一个适当的线程安全代理,因为它会直接在使用字段注入的地方注入.