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
Java Guice提供者<;实体管理器>;vs实体管理器_Java_Jpa_Guice_Guice Servlet_Guice Persist - Fatal编程技术网

Java Guice提供者<;实体管理器>;vs实体管理器

Java Guice提供者<;实体管理器>;vs实体管理器,java,jpa,guice,guice-servlet,guice-persist,Java,Jpa,Guice,Guice Servlet,Guice Persist,我试图让简单的webapp在Jetty上使用Guice和JPA,使用持久性和servlet Guice扩展 我编写了以下服务实现类: public class PersonServiceImpl implements PersonService { private EntityManager em; @Inject public PersonServiceImpl(EntityManager em) { this.em = em; } @Override @Transactiona

我试图让简单的webapp在Jetty上使用Guice和JPA,使用持久性和servlet Guice扩展

我编写了以下服务实现类:

public class PersonServiceImpl implements PersonService {

private EntityManager em;

@Inject
public PersonServiceImpl(EntityManager em) {
    this.em = em;
}

@Override
@Transactional
public void savePerson(Person p) {
    em.persist(p);
}

@Override
public Person findPerson(long id) {
    return em.find(Person.class, id);
}

@Override
@Transactional
public void deletePerson(Person p) {
    em.remove(p);
}
}

这是我的servlet(用@Singleton注释):

当我运行它时,它工作了,我得到了发送给客户端的名称,但是当我查看日志时,我看到没有为插入生成DML,并且postgresql中的选择没有返回任何结果,这意味着它没有真正持久化

我对代码进行了调试,发现
JpaLocalTxnInterceptor
调用了
txn.commit()

然后我更改了
PersonServiceImpl
,并使用了
Provider
,而不仅仅是
EntityManager
,它按预期工作。现在我真的不明白为什么,可能是因为我真的不明白提供商背后的想法。 上面写着:

请注意,如果您将MyService设置为@Singleton,那么您应该插入Provider

然而,我的PersonServiceImpl不是@Singleton,所以我不知道为什么它适用,也许是因为Servlet

如果您能帮我解决这个问题,我将不胜感激。

您需要
提供程序
,因为Guice内置的持久性和servlet扩展要求EntityManager具有请求范围。通过从单例servlet中保存的服务注入请求范围的EntityManager,您正在进行范围扩展注入,Guice将不会存储来自过时的、不匹配的EntityManager的数据

提供者 Provider是一个方法接口,它公开一个
get()
方法。如果您插入一个
提供程序
,然后调用
get()
,它将返回一个以与直接插入Foo相同的方式创建的实例。但是,注入提供程序允许您控制创建了多少对象以及创建对象的时间

  • 仅在实际需要时创建实例,特别是在创建需要大量时间或内存的情况下
  • 从同一组件中创建两个或多个独立实例
  • 将创建延迟到初始化方法或单独的线程
  • 混合范围,如下所述
对于绑定
X
提供程序
@提供的X
,Guice将自动允许您直接插入
X
提供程序
。您可以在不调整任何绑定的情况下使用提供程序,并且提供程序可以很好地使用

作用域和作用域加宽注入 广义地说,定义对象的生存期。默认情况下,Guice为每次注入创建一个新对象;通过将对象标记为@Singleton,可以指示Guice为每次注入注入相同的实例。Guice的servlet扩展还支持@RequestScope和@SessionScoped注入,这会导致在一个请求(或会话)中一致地注入相同的对象,但为不同的请求(或会话)注入新对象。Guice还允许您定义自定义作用域,例如(每个线程一个实例,但在同一线程中跨注入的同一实例)

如果直接从@Singleton组件中注入请求范围的对象,会发生什么?创建singleton时,它会尝试注入与当前请求相关的实例。请注意,可能没有当前请求,但如果有,则实例将保存到singleton中的一个字段中。随着请求的来来去去去,单例永远不会被重新创建,字段也永远不会被重新分配——因此在第一次请求之后,组件就停止正常工作

将窄范围对象(@RequestScoped)注入宽范围(@Singleton)称为范围加宽注入。并不是所有的范围扩大注射都会立即出现症状,但所有注射都可能在以后引入挥之不去的bug

供应商如何提供帮助 PersonService没有用@Singleton注释,但因为您正在@Singleton servlet中注入并存储一个实例,所以它也可能是一个Singleton本身。这意味着出于同样的原因,EntityManager也有单例行为

根据,EntityManager是短暂的,只存在于会话或请求中。这允许Guice在会话或请求结束时自动提交事务,但重用同一个EntityManager可能会阻止在第一个会话或请求结束后的任何时间存储数据。切换到提供者允许您通过在每个请求上创建一个新的EntityManager来缩小范围

(您还可以让PersonService成为一个提供者,这也可能会解决问题,但我认为最好观察Guice的最佳实践,并让EntityManager的范围与提供者明确地缩小。)

@Inject
PersonService personService;

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    String name = req.getParameter("name");
    String password = req.getParameter("password");
    String email = req.getParameter("email");
    int age = Integer.valueOf(req.getParameter("age"));


    Person p = new Person();
    p.setAge(age);
    p.setName(name);
    p.setEmail(email);
    p.setPassword(password.toCharArray());

    logger.info("saving person");

    personService.savePerson(p);
    logger.info("saved person");

    logger.info("extracting person");
    Person person = personService.findPerson(p.getId());
    resp.getWriter().print("Hello " + person.getName());
}
@Singleton public class YourClass {
  @Inject HttpServletRequest request;  // BAD IDEA
}