Eclipselink 3.0.2 学习记录01 - 低版本升级,了解各版本新特性

目前公司使用的还是Eclipselink 2.1.2的版本,版本比较老,很多特性不能使用。所以,希望升级一下,那么就需要了解之后的版本有哪些更新。

Eclipselink 各版本演变

EclipseLink 2.0

  • ER 248291 : JPA 2.0 Functionality
  • ER 221546: Performance and Concurrency
  • ER 277920: OXM XSD
  • ER 266912: JPA 2.0 Metamodel API
  • 259993: em.find() hangs on some tests in WebSphere 7.0.0.1

EclipseLink 2.1

  • ER 293925: MOXy: OXM XSD
  • ER 298985: Performance and Concurrency
  • ER 305331: JBoss 5.1.0 EAP support
  • ER 312503: JPA 2.0 Cache API Extensions
  • ER 296967: Dynamic MOXy - Bootstrapping from XML Schema
  • ER 296967: MOXy support for Dynamic Persistence

EclipseLink 2.2

  • ER 316513: Add JMX MBean support to JBoss 6, WebSphere 7 and GlassFish 3
  • ER 317962: MOXy Extensions: Additional MOXy annotation support required
  • ER 321152: Dynamic MOXy - Bootstrapping from EclipseLink Externalized Metadata (OXM)
  • ER 321763: Performance Monitor
  • ER 283430: Indexes
  • ER 324341: On Delete Cascade
  • ER 322008 : Additional criteria
  • ER 326663: JPA RESTful Service
  • ER 214519: Appending strings to CREATE TABLE statements
  • ER 328937 : Data Partitioning
  • ER 232063: Relationships between JPA 2.0 Cachable(false) and Cachable(true) Entities should be supported

具体内容见 - EclipseLink 2.2

EclipseLink 2.3

  • ER 275156: PLSQL Procedures and Functions
  • ER 340192: Descriptor Extensibility by Flex Columns
  • ER 328404: Persistence Unit Composition
  • ER 337323: Multi-Tenancy

具体内容见 - EclipseLink 2.3

EclipseLink 2.4.2 新特性

EclipseLink 2.4.2 - RESTFul Persistence

Java持久单元可以直接被REST暴露

准备环境
  • Java EE Server需要准备JPA配置以及JAX-RS1.0的实现:
    • EclipseLink 2.4 or later, configured as the persistence provider
    • Jersey, the reference implementation of the Java API for RESTful Web Services (JAX-RS) 1.0 specification
  • 准备 org.eclipse.persistence.jpars_version_num.jar ,比如org.eclipse.persistence.jpars_2.4.1.v20121003-ad44345.jar
  • 数据库MySQL或者其他
配置应用
配置build.gradle

主要做的事情包括:指定contextPath为testJpa,引入jersey、eclipselink、org.eclipse.persistence.jpars

plugins {
    id 'war'
    id "org.gretty" version "3.0.6"
}

group 'org.example'
version '1.0-SNAPSHOT'

repositories {
    maven { url "https://maven.aliyun.com/repository/central" }
    mavenCentral()
}

gretty {
    httpPort = 8081
    contextPath = "testJpa"
}

dependencies {
    implementation 'org.eclipse.persistence:eclipselink:2.4.2'
    implementation 'org.eclipse.persistence:org.eclipse.persistence.jpars:2.4.2'
    implementation 'mysql:mysql-connector-java:8.0.28'
    implementation 'com.sun.jersey:jersey-servlet:1.19.4'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2'
}
JPA配置文件:resources/META-INF/persistence.xml
<?xml version="1.0" encoding="windows-1252" ?>
<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_1_0.xsd"
             version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="testRest" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.test.entity.Person</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:13306/test"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="12345678"/>
            <property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
            <property name="eclipselink.logging.level" value="FINEST"/>
        </properties>
    </persistence-unit>
</persistence>
Entity 以及访问方式
@Entity
@Table(name = "t_person")
public class Person {
    @Id
    private String name;

    private int age;

    private String address;
    ...getter
    ...setter
}

基础访问路径: http://server:port/application-name/persistence/{version},其中,对EclipseLink 2.4.2来说,version固定为 v1.0

For base operations on the persistence unit, add the persistence unit name:
/persistence/{version}/{unit-name}
For specific types of operations, add the type of operation, for example:
Entity operations: /persistence/{version}/{unit-name}/entity
Query operations: /persistence/{version}/{unit-name}/query
Single result query operations: /persistence/{version}/{unit-name}/singleResultQuery
Persistence unit level metadata operations: /persistence/{version}/{unit-name}/metadata
Base operations: /persistence/{version}

测试下Entity operations
支持xml或json格式的相应内容,可以通过Accept或者Content-Type来指定请求头:

# testJpa.http
GET /testJpa/persistence/v1.0/testRest/entity/Person/zhangsan01 HTTP/1.1
Host: localhost:8081
Accept: application/xml

响应如下:

<?xml version="1.0" encoding="UTF-8"?>
<person>
  <address>Shanghai</address>
  <age>18</age>
  <name>zhangsan01</name>
</person>
# testJpa.http
GET /testJpa/persistence/v1.0/testRest/entity/Person/zhangsan01 HTTP/1.1
Host: localhost:8081
Content-Type: application/json

响应内容如下:

{
  "address": "Shanghai",
  "age": 18,
  "name": "zhangsan01"
}
EclipseLink 2.4.2 - Tenant Isolation (用来隔离数据)

租户隔离的主要@Multitenant来实现, MultitenantType 枚举有三个选择:SINGLE_TABLE、TABLE_PER_TENANT、VPD,默认是SINGLE_TABLE。

@Target({TYPE}) 
@Retention(RUNTIME)
public @interface Multitenant {
    /**
     * (Optional) Specify the multi-tenant strategy to use.
     */
    MultitenantType value() default MultitenantType.SINGLE_TABLE;
    
    /**
     * (Optional) Indicate if the database requires the tenant criteria to
     * be added to the SELECT, UPDATE, and DELETE queries. By default this is
     * done but when set to false the queries will not be modified and it will
     * be up to the application or database to ensure that the correct criteria 
     * is applied to all queries.
     */
    boolean includeCriteria() default true;
}
MultitenantType.SINGLE_TABLE

租户隔离主要通过指定的列名和context中的属性来区分,有@TenantDiscriminatorColumn负责控制:

@Target({TYPE}) 
@Retention(RUNTIME)
public @interface TenantDiscriminatorColumn {
    /**
     * (Optional) The name of column to be used for the tenant discriminator.
     */
    String name() default "TENANT_ID";

    /**
     * (Optional) The name of the context property to apply to the 
     * tenant discriminator column.
     */
    String contextProperty() default "eclipselink.tenant-id";

举个简单的例子,采用默认配置:

@Entity
@Multitenant
@Table(name = "t_person")
public class Person {
    @Id
    private String name;
    private int age;
    private String address;
    ... getter\setter

对应表结构如下,其中TENANT_ID是默认的列名:

FieldTypeNull
NAMEvarchar(255)NO
ADDRESSvarchar(255)YES
AGEintYES
TENANT_IDvarchar(31)YES

执行如下代码,插入一条数据:

 EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default");
 EntityManager entityManager = entityManagerFactory.createEntityManager();
 entityManager.getTransaction().begin();
 entityManager.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "OneCompany");
 TableTest tableTest = new TableTest();
 tableTest.setId(122);
 entityManager.persist(tableTest);
 entityManager.getTransaction().commit();

可以看到如下log:

INSERT INTO t_person (NAME, ADDRESS, AGE, TENANT_ID) VALUES (?, ?, ?, ?)
	bind => [lisi01, Nanjing, 19, OneCompany]

查询也会限制:

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default");
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "OneCompany");
Person person = entityManager.find(Person.class, "lisi01");
assertNotNull(person);
Person singleResult = entityManager.createQuery("select p from Person p where p.age = :age", Person.class)
        .setParameter("age", 19)
        .getSingleResult();
assertNotNull(singleResult);
[EL Fine]: sql: 2022-03-20 19:20:55.148--ServerSession(1998998800)--Connection(1761062783)--Thread(Thread[Test worker,5,main])--SELECT NAME, TENANT_ID, ADDRESS, AGE FROM t_person WHERE ((NAME = ?) AND (TENANT_ID = ?))
	bind => [lisi01, OneCompany]
[EL Fine]: sql: 2022-03-20 19:20:55.238--ServerSession(1998998800)--Connection(1761062783)--Thread(Thread[Test worker,5,main])--SELECT NAME, TENANT_ID, ADDRESS, AGE FROM t_person WHERE ((AGE = ?) AND (TENANT_ID = ?))
	bind => [19, OneCompany]

Eclipselink也支持多列配置,更多的配置方法可以看Eclipselink官网的demo:

/** Single tenant discriminator column **/
@Entity
@Table(name = "CUSTOMER")
@Multitenant
@TenantDiscriminatorColumn(name = "TENANT", contextProperty = "multi-tenant.id")
public Customer() {
  ...
}
 
/** Multiple tenant discriminator columns using multiple tables **/
@Entity
@Table(name = "EMPLOYEE")
@SecondaryTable(name = "RESPONSIBILITIES")
@Multitenant(SINGLE_TABLE)
@TenantDiscriminatorColumns({
    @TenantDiscriminatorColumn(name = "TENANT_ID", contextProperty = "employee-tenant.id", length = 20)
    @TenantDiscriminatorColumn(name = "TENANT_CODE", contextProperty = "employee-tenant.code", discriminatorType = STRING, table = "RESPONSIBILITIES")
  }
)
public Employee() {
  ...
}
 
/** Tenant discriminator column mapped as part of the primary key on the database **/
@Entity
@Table(name = "ADDRESS")
@Multitenant
@TenantDiscriminatorColumn(name = "TENANT", contextProperty = "tenant.id", primaryKey = true)
public Address() {
  ...
}
 
/** Mapped tenant discriminator column **/
@Entity
@Table(name = "Player")
@Multitenant
@TenantDiscriminatorColumn(name = "AGE", contextProperty = "tenant.age")
public Player() {
  ...
  
  @Basic
  @Column(name="AGE", insertable="false", updatable="false")
  public int age;
}
MultitenantType.TABLE_PER_TENANT

与TABLE_PER_TENANT关联的注解是@TenantTableDiscriminator

@Target({TYPE}) 
@Retention(RUNTIME)
public @interface TenantTableDiscriminator {
    /**
     * (Optional) The name of the context property to apply to as 
     * tenant table discriminator. Default is "eclipselink-tenant.id"
     */
    String contextProperty() default PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT;
    
    /**
     * (Optional) The type of tenant table discriminator to use with the tables
     * of the persistence unit.
     * Defaults to {@link TenantTableDiscriminatorType#SUFFIX TenantTableDiscriminatorType.SUFFIX}.
     */
    TenantTableDiscriminatorType type() default TenantTableDiscriminatorType.SUFFIX;
}

其中TenantTableDiscriminatorType有三个选择:SCHEMA、SUFFIX(默认值)、PREFIX。

TenantTableDiscriminatorType.SUFFIX
@Entity
@Table(name = "t_book")
@Multitenant(TABLE_PER_TENANT)
public class Book {
    @Id
    private int id;

    private String name;
    ...
}

真实的表名要加上_{eclipselink.tenant-id} 后缀:

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default");
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
// 注意这里的eclipselink.tenant-id的值为Customer01
entityManager.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, "Customer01");
Book book = new Book();
book.setId(122);
book.setName("Java技术");
entityManager.persist(book);
entityManager.getTransaction().commit();
Call: INSERT INTO t_book_Customer01 (ID, NAME) VALUES (?, ?)
	bind => [122, Java技术]
TenantTableDiscriminatorType.PREFIX

TenantTableDiscriminatorType.PREFIX 同 SUFFIX,只是改成前缀。

TenantTableDiscriminatorType.SCHEMA
@Entity
@Table(name = "t_book")
@Multitenant(TABLE_PER_TENANT)
@TenantTableDiscriminator(type = SCHEMA)
public class Book {
    @Id
    private int id;

    private String name;
    ...
}

新增记录代码不变,结果如下,可以看到对应的是指定的数据库名:

Call: INSERT INTO Customer01.t_book (ID, NAME) VALUES (?, ?)
	bind => [122, Java技术]
MultitenantType.VPD

VPD 全称是 Virtual Private Database, 目前没有找到MySQL对VPD支持的资料,待后续补充。

EclipseLink 2.4.2 - NoSQL

EclipseLink supports the following datasources:

  • MongoDB
  • Oracle NoSQL
  • XML Files
  • JMS
  • Oracle AQ

目前2.4.2 版本没有验证成功,等高版本再测试。当前的准备如下:
引入必要的包:

// build.gradle
implementation 'org.eclipse.persistence:org.eclipse.persistence.nosql:2.4.2'
implementation 'org.mongodb:mongo-java-driver:2.11.0'

配置文件如下:

    <persistence-unit name="testMongoDB" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.test.entity.nosql.Order</class>
        <class>com.test.entity.nosql.Customer</class>
        <class>com.test.entity.nosql.OrderLine</class>
        <class>com.test.entity.nosql.Address</class>
        <properties>
            <property name="eclipselink.target-database" value="org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform"/>
            <property name="eclipselink.nosql.connection-spec" value="org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec"/>
            <property name="eclipselink.nosql.property.mongo.port" value="27017"/>
            <property name="eclipselink.nosql.property.mongo.host" value="localhost"/>
            <property name="eclipselink.nosql.property.mongo.db" value="testdb"/>
            <property name="eclipselink.nosql.property.user" value="coltest"/>
            <property name="eclipselink.nosql.property.password" value="coltest123"/>
            <property name="eclipselink.logging.level" value="FINEST"/>
        </properties>
    </persistence-unit>

@NoSql注解有两个属性dateType可以指定collection名称,dataFormat 需要指定为DataFormatType.MAPPED

@Entity
@NoSql(dataType = "customers1", dataFormat = DataFormatType.MAPPED)
public class Customer {
    @Id
    @GeneratedValue
    @Field(name = "_id")
    private String customerId;

    @Basic
    @Field(name = "name")
    private String name;
EclipseLink 2.4.2 - JSON

将JSON转成对象或者将对象转成JSON字符

EclipseLink 2.5.2 新特性

最主要的变化是对JPA 2.1 的支持,新特性包括:

  • Full JPA 2.1 support
  • Maven Central support
  • New DB platforms: HANA and Pervasive
  • JPA-RS Enhancements
  • MOXy - NamedObjectGraphs
Full JPA 2.1 support

列举几个重要的功能:

Bulk Update/Delete

引入对应版本的Eclipselink库以及MySql驱动:

implementation 'org.eclipse.persistence:eclipselink:2.5.2'
implementation 'mysql:mysql-connector-java:8.0.28'

resources/META-INF/persistence.xml:

<?xml version="1.0" encoding="windows-1252" ?>
<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_1_0.xsd"
             version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.test.entity.Person</class>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:13306/test"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value="12345678"/>
            <property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
            <property name="eclipselink.logging.level" value="FINEST"/>
        </properties>
    </persistence-unit>
</persistence>

Person类以及对应的MetaModel如下:

@Entity
@Table(name = "t_person")
public class Person {
    @Id
    private String name;

    private int age;

    private String address;
	...
}
@StaticMetamodel(Person.class)
public class Person_ {
    public static volatile SingularAttribute<Person, String> name;
    public static volatile SingularAttribute<Person, Integer> age;
    public static volatile SingularAttribute<Person, String> address;
}

测试BulkUpdate:

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default");
EntityManager entityManager = entityManagerFactory.createEntityManager();

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaUpdate<Person> uq = cb.createCriteriaUpdate(Person.class);

Root<Person> r = uq.from(Person.class);
uq.set(r.get(Person_.age), cb.sum(r.get(Person_.age), 2));
uq.set(r.get(Person_.address), cb.concat(r.get(Person_.address), "_China"));
uq.where(cb.lt(r.get(Person_.age), 30));

entityManager.getTransaction().begin();
entityManager.createQuery(uq).executeUpdate();
entityManager.getTransaction().commit();

Log中的SQL如下:

UPDATE t_person SET ADDRESS = CONCAT(ADDRESS, ?), AGE = (AGE + ?) WHERE (AGE < ?)
	bind => [_China, 2, 30]

测试Bulk Delete:

EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default");
EntityManager entityManager = entityManagerFactory.createEntityManager();

CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaDelete<Person> cd = cb.createCriteriaDelete(Person.class);

Root<Person> r = cd.from(Person.class);
cd.where(cb.greaterThan(r.get(Person_.age), 30), cb.like(r.get(Person_.address), "%China_%"));

entityManager.getTransaction().begin();
entityManager.createQuery(cd).executeUpdate();
entityManager.getTransaction().commit();

Log中的SQL如下:

DELETE FROM t_person WHERE ((AGE > ?) AND ADDRESS LIKE ?)
	bind => [30, %China_%]
Stored Procedures

提供StoredProcedureQuery API 和Named Stored Procedure Queries 来支持对存储过程的调用。直接拿官网的例子:

-- Mysql 中的存储过程
CREATE PROCEDURE Read_Address_City (address_id_v INTEGER, OUT city_v VARCHAR(255))
BEGIN 
  SELECT CITY INTO city_v FROM ADDRESS WHERE (ADDRESS_ID = address_id_v); 
END
StoredProcedureQuery query = em.createStoredProcedureQuery("Read_Address_City");
query.registerStoredProcedureParameter("address_id_v", Integer.class, ParameterMode.IN);
query.registerStoredProcedureParameter("city_v", String.class, ParameterMode.OUT);

boolean resultSet = query.setParameter("address_id_v", "1").execute();

if (resultSet) {
   // Result sets must be processed first through getResultList() calls.
} 

// Once the result sets and update counts have been processed, output parameters are available for processing.
String city = (String) query.getOutputParameterValue("city_v");

更多例子可以查看 官网例子 - Stored_Procedures

JPQL function

JPQL 支持function调用

Treat

允许再查询时访问子类的状态或属性

Select p from Person p join fetch p.car join treat(p.car as SportsCar) s where s.maxSpeed = 200  

Criteria API Example:

CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery<Person> cq = qb.createQuery(Person.class);
Root<Person> root = cq.from(Person.class);
Join s = qb.treat(root.join("car"), SportsCar.class);
cq.select(s.get("maxSpeed"));
Converters

支持数据库类型与特定属性类型的转换,也是拿来主义,看官网例子:

 @Converter(autoApply=true)
 public class LongToStringConverter implements AttributeConverter<Long, String> {
 
     @Override
     public String convertToDatabaseColumn(Long attribute) {
         return (attribute == null) ? null : attribute.toString(); 
     }
 
     @Override
     public Long convertToEntityAttribute(String dbData) {
         return (dbData == null) ? null : new Long(dbData);
     }
 }
@Convert(converter = LongToStringConverter.class)
protected Long salary;

更复杂的例子看 官网例子 - Converters

DDL generation

主要是将DDL generation标准化了,相关的属性有:

  • javax.persistence.schema-generation.database.action
    specifies the action to be taken by the persistence provider with regard to the database artifacts
    Valid values for this property: none, create, drop-and-create, drop
  • javax.persistence.schema-generation.scripts.action
    specifies which scripts are to be generated by the persistence provider
    Valid values for this property: none, create, drop-and-create, drop
  • javax.persistence.schema-generation.create-source
    specifies whether the creation of database artifacts is to occur on the basis of the object/relational mapping metadata, DDL script, or a combination of the two.
    Valid values for this property: metadata, script, metadata-then-script, script-then-metadata
  • javax.persistence.schema-generation.drop-source
    specifies whether the dropping of database artifacts is to occur on the basis of the object/relational mapping metadata, DDL script, or a combination of the two.
    Valid values for this property: metadata, script, metadata-then-script, script-then-metadata
  • javax.persistence.schema-generation.create-database-schemas
    specifies whether the persistence provider is to create the database schema(s) in addition to creating database objects such as tables, sequences, constraints, etc.
  • javax.persistence.schema-generation.scripts.create-target
    specifies a java.IO.Writer configured for use by the persistence provider for output of the DDL script or a string specifying the file URL for the DDL script.
  • javax.persistence.schema-generation.scripts.drop-target
    specifies a java.IO.Writer configured for use by the persistence provider for output of the DDL script or a string specifying the file URL for the DDL script.
  • javax.persistence.database-product-name
    specified if scripts are to be generated by the persistence provider and a connection to the target database is not supplied.
    The value of this property should be the value returned for the target database by the JDBC DatabaseMetaData method getDatabaseProductName.
  • javax.persistence.database-major-version
    specified if sufficient database version information is not included from the JDBC DatabaseMetaData method getDatabaseProductName.
    This value of this property should contain the value returned by the JDBC getDatabaseMajor-Version method.
  • javax.persistence.database-minor-version
    specified if sufficient database version information is not included from the JDBC DatabaseMetaData method getDatabaseProductName.
    This value of this property should contain the value returned by the JDBC getDatabaseMinor-Version method.
  • javax.persistence.schema-generation.create-script-source
    specifies a java.IO.Reader configured for reading of the DDL script or a string designating a file URL for the DDL script.
  • javax.persistence.schema-generation.drop-script-source
    specifies a java.IO.Reader configured for reading of the DDL script or a string designating a file URL for the DDL script.
  • javax.persistence.schema-generation.connection
    specifies the JDBC connection to be used for schema generation. This is intended for use in Java EE environments, where the platform provider may want to control the database privileges that are available to the persistence provider.
  • javax.persistence.sql-load-script-source
    specifies a java.IO.Reader configured for reading of the SQL load script for database initialization or a string designating a file URL for the script.
Entity Graphs(很有用)

可以一次查询出entity关联的多个以及多级子属性,哪怕是Lazy load 的属性。
可以直接通过注解定义EntityGraph:

@NamedEntityGraph(
    name="ExecutiveProjects",
    attributeNodes={
        @NamedAttributeNode("address"),
        @NamedAttributeNode(value="projects", subgraph="projects")
    },
    subgraphs={
        @NamedSubgraph(
            name="projects",
            attributeNodes={@NamedAttributeNode("properties")}
        ),
        @NamedSubgraph(
            name="projects",
            type=LargeProject.class,
            attributeNodes={@NamedAttributeNode("executive")}
        )
    }
)

也可以动态创建:

EntityGraph employeeGraph = em.createEntityGraph(Employee.class);
employeeGraph.addAttributeNodes("address");
employeeGraph.addSubgraph("projects").addAttributeNodes("properties");
employeeGraph.addSubgraph("projects", LargeProject.class).addAttributeNodes("executive");

或修改现有的:

EntityGraph employeeGraph = em.createEntityGraph("ExecutiveProjects");
employeeGraph.addSubgraph("period").addAttributeNodes("startDate");

查询的时候可以通过Hint来使用EntityGraph ,比如:

EntityGraph employeeGraph = em.getEntityGraph("ExecutiveProjects");
Employee result = (Employee) em.createQuery("Select e from Employee e").setHint("javax.persistence.fetchgraph", employeeGraph).getResultList().get(0);
PersistenceUnitUtil util = em.getEntityManagerFactory().getPersistenceUnitUtil();
assertFalse(util.isLoaded(result, "firstName"));
assertFalse(util.isLoaded(result, "department"));
assertTrue(util.isLoaded(result, "projects"));

其中javax.persistence.fetchgraph 表明列出来的属性将被加载,未列出的都会变成fetchType=LAZY,也可以改成javax.persistence.loadgraph,列出来的属性将被加载,未列出的还按照fetchType配置来决定是否是懒加载。

Unsynchronized Persistence Contexts

在Java EE环境下,@PersistenceContext(synchronization=SynchronizationType.UNSYNCHRONIZED)
持久化上下文管理的实体变化后,在事务提交后,可以不立即写入数据库,而是要等明确调用EntityManager.joinTransaction() 时才会写入数据库。

EclipseLink 2.6 新特性

EclipseLink 2.6版本的主要重点是稳定性、Java EE 7集成和JPA-RS。

EclipseLink 2.7 新特性

EclipseLink 2.7版本的主要重点是稳定性、Java EE 8集成和JPA-RS。
并支持Java Persistence (JPA) 2.2

EclipseLink 3.0

EclipseLink 3.0版本的主要重点是切换到新的jakarta包命名空间并支持Jakarta EE 9 APIs:

  • Jakarta EE Platform 9 support
  • Java 8, 11 support
  • Thread dead-lock diagnostic features
  • Jakarta Persistence 3.0
  • Jakarta XML Binding 3.0

Jakarta Persistence 是以后的必然趋势,看下Spring Boot 目前新的版本变化可以到:
Spring- Boot 2.6.5 GA的依赖如下:

groupartifactversion
jakarta.persistencejakarta.persistence-api2.2.3
javax.persistencejavax.persistence-api2.2

而在Spring-boot 3.0.0-SNAPSHOT 中就只剩下了:jakarta.persistence

groupartifactversion
jakarta.persistencejakarta.persistence-api3.0.0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值