Fork me on GitHub

JPA

JPA是事实上的Java持久性标准,Ninja为JPA 2.0提供了现成的支持. JPA支持由Hibernate实现,事务处理由Guice Persist促进.

Quickstart

我们准备了一个原型来帮助您入门和运行. 只需执行:

mvn archetype:generate -DarchetypeGroupId=org.ninjaframework -DarchetypeArtifactId=ninja-servlet-jpa-blog-archetype

并击中

mvn package ninja:run

您可以在以下位置访问该应用程序

注意:该应用程序可与内存数据库(h2)一起使用. 如果您想更改为另一个数据库,例如Postgresql或MySQL,只需查看下面的" 配置"部分.

此时,您可以使用现有实体作为示例来创建自己的实体,从而以这种方式扩展模型和应用程序.

Models

按照惯例,模型应放在"模型"包下. 典型模型如下:

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class GuestbookEntry {
    
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    Long id;

    private String text;
    private String email;
    
    public GuestbookEntry() {}
    
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }

}

In essence the model is a POJO with some annotations. This is already enough to tell JPA where and what to save.

请参考https://docs.oracle.com/javaee/7/tutorial/persistence-intro.htm以获得对该主题的详尽介绍.

好. 我们配置了东西-我们知道如何编写模型. 但是我们可以用这些模型做什么?

Saving and querying

老实说. Ninja只是在重复使用出色的库来为您提供JPA. 在这种情况下,它就是Guice,尤其是Guice Persist( https://github.com/google/guice/wiki/GuicePersist ).

Ninja只是提供了一种方便的开箱即用配置,并将模式映射到持久性单元.

让我们看一下执行一些查询的控制器:

@Inject 
Provider<EntityManager> entitiyManagerProvider;

@UnitOfWork
public Result getIndex() {

    EntityManager entityManager = entitiyManagerProvider.get();

    Query q = entityManager.createQuery("SELECT x FROM GuestbookEntry x");
    List<GuestbookEntry> guestbookEntries = (List<GuestbookEntry>) q.getResultList();

    String postRoute = router.getReverseRoute(ApplicationController.class, "postIndex");

    return Results
            .html()
            .render("guestbookEntries", guestbookEntries).
            render("postRoute", postRoute);


}

这里有两点很重要:

  • 为EntityManager注入的Provider
  • @UnitOfWork注释的方法

实体管理器是使您能够基于模型更新/保存和查询数据的关键组件. 但是JPA必须打开连接,保存数据,维护缓存-如果您必须自己为每种控制器方法进行管理,那么您可能会发疯. 这就是@UnitOfWork的用途. 只需使用该注释对方法进行注释,Guice Persists将为您处理所有样板.

但是@UnitOfWork只处理连接,而不能帮助您进行事务处理. 这就是@Transactional的用途. @Transactional会自动打开和关闭带注释方法的事务. 确保您正在使用import com.google.inject.persist.Transactional;@Transactional .

保存也很简单:

import com.google.inject.persist.Transactional;

@Transactional
public Result postIndex(GuestbookEntry guestbookEntry) {

    logger.info("In postRoute");        

    EntityManager entityManager = entitiyManagerProvider.get();

    entityManager.persist(guestbookEntry);


    return Results.redirect(router.getReverseRoute(ApplicationController.class, "getIndex"));

}

保存实际上只是对entityManager.perist(…)的调用. 它再简单不过了. 但是,再次提醒您-不要忘记使用@Transactional注释您的方法.

加起来:

  1. 对于只读查询,您应该使用@UnitOfWork (它可能会更快,因为没有启动任何事务). 您可以包装控制器方法或服务类的方法.
  2. 要保存/更新和删除数据,请始终使用@Transactional . 此处相同:您可以包装控制器方法或服务类的方法.
  3. 对于一个HTTP请求或调度程序调用中的多个事务:
  • 一种. 在控制器或服务方法周围使用@UnitOfWork ,并使用EntityManager的 @Transactional或编程API来划分同一@UnitOfWork中的事务
  • b. 使用EntityManager的 @Transactional或程序化API来在同一请求或调度程序调用中划分事务,而无需@UnitOfWork

Configuration

在配置JPA时,有两点很重要.

  • 在application.conf上设置数据库和持久性单元
  • META-INF / persistence.xml

首先,您必须在application.conf中设置数据库凭据:

您还必须像这样设置数据库连接字符串,用户名和密码:

db.connection.url=jdbc:postgresql://localhost:5432/ra
db.connection.username=ra
db.connection.password=

当然,您可以利用Ninja的不同模式并在测试和生产中指定其他数据库:

# development database
db.connection.url=jdbc:postgresql://localhost:5432/ra
db.connection.username=ra
db.connection.password=password

# testing database
%test.db.connection.url=jdbc:postgresql://localhost:5432/test
%test.db.connection.username=ra
%test.db.connection.password=password

# production database
%prod.db.connection.url=jdbc:postgresql://myserver:5432/production_db
%prod.db.connection.username=user
%prod.db.connection.password=password

要激活JPA,您已经设置了一个名为ninja.jpa.persistence_unit_name的变量.

ninja.jpa.persistence_unit_name=mypersistenceunit

这告诉Ninja从persitence.xml中选择哪个持久性单元. 当然,您可以为不同的模式再次指定不同的持久性单元:

ninja.jpa.persistence_unit_name=dev_unit
%test.ninja.jpa.persistence_unit_name=test_unit
%prod.ninja.jpa.persistence_unit_name=prod_unit

这会使忍者在dev中使用dev_unit,在test中使用test_unit,在prod中使用prod_unit. 然后,您可以使用例如db进行测试,使用另一个常规PostgreSQL数据库进行开发以及在生产环境中使用经过高度调整的连接池PostgreSQL. 当然,它们全部具有不同的连接字符串.

为了使它最终生效,您必须配置第二个JPA组件-名为META-INF / persistence.xml的文件,看起来像:

<?xml version="1.0" encoding="UTF-8"?>

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0">

    <!-- Database settings for development and for tests -->
    <persistence-unit name="dev_unit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <properties>
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />

            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" /> 
            
            <!-- Connection Pooling settings -->
            <property name="hibernate.connection.provider_class"
                value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />

            <property name="hibernate.c3p0.max_size" value="100" />
            <property name="hibernate.c3p0.min_size" value="0" />
            <property name="hibernate.c3p0.acquire_increment" value="1" />
            <property name="hibernate.c3p0.idle_test_period" value="300" />
            <property name="hibernate.c3p0.max_statements" value="0" />
            <property name="hibernate.c3p0.timeout" value="100" />      
        </properties>
    </persistence-unit>

    <!-- production database - with sensible connect strings optimized for the real servers. -->
    <persistence-unit name="prod_unit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

        <properties>
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />

            <property name="hibernate.show_sql" value="false" />
            <property name="hibernate.format_sql" value="false" /> 
            
             <!-- Connection Pooling settings -->
            <property name="hibernate.connection.provider_class"
                value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" />

            <property name="hibernate.c3p0.max_size" value="100" />
            <property name="hibernate.c3p0.min_size" value="0" />
            <property name="hibernate.c3p0.acquire_increment" value="1" />
            <property name="hibernate.c3p0.idle_test_period" value="300" />
            <property name="hibernate.c3p0.max_statements" value="0" />
            <property name="hibernate.c3p0.timeout" value="100" />      
        </properties>
    </persistence-unit>
</persistence>

该文件将位于META-INF / persistence.xml下.

More

操作持久性单元的默认方法是使用transaction-type = RESOURCE_LOCAL. 它使您对正在发生的事情以及何时保存内容有了更多的控制和可预测性. Ninja在该模式下工作效果最佳,因为该框架负责设置/关闭JPA的EntityManagerFactoryEntityManager ,而与JTA模式相反,在JTA模式中,事务和EntityManager由JEE容器注入/管理.

如果您想了解有关JPA的更多信息,请参考以下官方文档: https : //docs.oracle.com/javaee/7/tutorial/persistence-intro.htm .


by  ICOPY.SITE