栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

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

Eclipselink 各版本演变 Eclipselink 2.0

ER 248291 : JPA 2.0 FunctionalityER 221546: Performance and ConcurrencyER 277920: OXM XSDER 266912: JPA 2.0 metamodel API259993: em.find() hangs on some tests in WebSphere 7.0.0.1 Eclipselink 2.1

ER 293925: MOXy: OXM XSDER 298985: Performance and ConcurrencyER 305331: JBoss 5.1.0 EAP supportER 312503: JPA 2.0 Cache API ExtensionsER 296967: Dynamic MOXy - Bootstrapping from XML SchemaER 296967: MOXy support for Dynamic Persistence Eclipselink 2.2

ER 316513: Add JMX MBean support to JBoss 6, WebSphere 7 and GlassFish 3ER 317962: MOXy Extensions: Additional MOXy annotation support requiredER 321152: Dynamic MOXy - Bootstrapping from Eclipselink Externalized metadata (OXM)ER 321763: Performance MonitorER 283430: IndexesER 324341: On Delete CascadeER 322008 : Additional criteriaER 326663: JPA RESTful ServiceER 214519: Appending strings to CREATE TABLE statementsER 328937 : Data PartitioningER 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 FunctionsER 340192: Descriptor Extensibility by Flex ColumnsER 328404: Persistence Unit CompositionER 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 providerJersey, 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


    
        org.eclipse.persistence.jpa.PersistenceProvider
        com.test.entity.Person
        
            
            
            
            
            
            
        
    

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

响应如下:



  
Shanghai
18 zhangsan01
# 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 {
    
    MultitenantType value() default MultitenantType.SINGLE_TABLE;
    
    
    boolean includeCriteria() default true;
}
MultitenantType.SINGLE_TABLE

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

@Target({TYPE}) 
@Retention(RUNTIME)
public @interface TenantDiscriminatorColumn {
    
    String name() default "TENANT_ID";

    
    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;
    ... gettersetter

对应表结构如下,其中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:

@Entity
@Table(name = "CUSTOMER")
@Multitenant
@TenantDiscriminatorColumn(name = "TENANT", contextProperty = "multi-tenant.id")
public Customer() {
  ...
}
 

@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() {
  ...
}
 

@Entity
@Table(name = "ADDRESS")
@Multitenant
@TenantDiscriminatorColumn(name = "TENANT", contextProperty = "tenant.id", primaryKey = true)
public Address() {
  ...
}
 

@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 {
    
    String contextProperty() default PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT;
    
    
    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:

MongoDBOracle NoSQLXML FilesJMSOracle 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'

配置文件如下:

    
        org.eclipse.persistence.jpa.PersistenceProvider
        com.test.entity.nosql.Order
        com.test.entity.nosql.Customer
        com.test.entity.nosql.OrderLine
        com.test.entity.nosql.Address
        
            
            
            
            
            
            
            
            
        
    

@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 supportMaven Central supportNew DB platforms: HANA and PervasiveJPA-RS EnhancementsMOXy - 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:



    
        org.eclipse.persistence.jpa.PersistenceProvider
        com.test.entity.Person
        
            
            
            
            
            
            
        
    

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 name;
    public static volatile SingularAttribute age;
    public static volatile SingularAttribute address;
}

测试BulkUpdate:

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

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

Root 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 cd = cb.createCriteriaDelete(Person.class);

Root 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 cq = qb.createQuery(Person.class);
Root 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 {
 
     @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, dropjavax.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, dropjavax.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-metadatajavax.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-metadatajavax.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。

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/778169.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号