跳轉至內容

Java 永續性/高階主題

來自 Wikibooks,開放世界中的開放書籍

高階主題

[編輯 | 編輯原始碼]

事件是系統中的一個鉤子,允許在事件發生時執行一些程式碼。事件可用於擴充套件、整合、除錯、審計或監控系統。

JPA 為Entity物件的持久生命週期定義了多個事件。JPA 事件透過註解或 orm.xml 定義。持久類中的任何方法都可以用事件註解進行註解,以便對該類所有例項進行呼叫。也可以使用 EntityListeners 註解或<entity-listeners> XML 元素為類配置事件監聽器。指定的監聽器類不需要實現任何介面(JPA 不使用 Java 事件模型),它只需要用所需的事件註解註解其方法即可。

JPA 定義了以下事件

  • PostLoad - 在將Entity載入到持久化上下文(EntityManager)中之後,或者在refresh操作之後呼叫。
  • PrePersist - 在對Entity呼叫persist操作之前呼叫。對於新例項,在merge期間也呼叫,以及在persist操作的級聯期間呼叫。物件的Id可能尚未分配,並且可以由事件分配程式碼。
  • PostPersist - 在將新例項持久化到資料庫之後呼叫。這發生在flushcommit操作期間,在資料庫INSERT發生之後,但在事務提交之前。它不會在persist操作期間發生。物件的Id應該分配。
  • PreUpdate - 在將例項更新到資料庫之前呼叫。這發生在flushcommit操作期間,在資料庫UPDATE發生之後,但在事務提交之前。它不會在merge操作期間發生。
  • PostUpdate - 在將例項更新到資料庫之後呼叫。這發生在flushcommit操作期間,在資料庫UPDATE發生之後,但在事務提交之前。它不會在merge操作期間發生。
  • PreRemove - 在對Entity呼叫remove操作之前呼叫。對於remove操作的級聯,也呼叫它。它還在 JPA 2.0 中的flushcommit期間為orphanRemoval呼叫。
  • PostRemove - 在將例項從資料庫中刪除之後呼叫。這發生在flushcommit操作期間,在資料庫DELETE發生之後,但在事務提交之前。它不會在remove操作期間發生。

實體事件註解示例

[編輯 | 編輯原始碼]
@Entity
public class Employee {
  @Id
  private String uid;
  @Basic
  private Calendar lastUpdated;
  ...

  @PrePersist
  public void prePersist() {
    this.uid = UIDGenerator.newUUI();
    this.lastUpdated = Calendar.getInstance();
  }

  @PreUpdate
  public void preUpdate() {
    this.lastUpdated = Calendar.getInstance();
  }
}

實體監聽器事件註解示例

[編輯 | 編輯原始碼]
@Entity
@EntityListeners(EmployeeEventListener.class)
public class Employee {
  @Id
  private String uid;
  @Basic
  private Calendar lastUpdated;
  ...
}


public class EmployeeEventListener {
  @PrePersist
  public void prePersist(Object object) {
    Employee employee = (Employee)object;
    employee.setUID(UIDGenerator.newUUI());
    employee.setLastUpdated(Calendar.getInstance());
  }

  @PreUpdate
  public void preUpdate(Object object) {
    Employee employee = (Employee)object;
    employee.setLastUpdated(Calendar.getInstance());
  }
}

實體事件 xml 示例

[編輯 | 編輯原始碼]
<entity name="Employee" class="org.acme.Employee" access="FIELD">
    <pre-persist method-name="prePersist"/>
    <pre-update method-name="preUpdate"/>
    <attributes>
        <id name="uid"/>
    </attributes>
</entity>

實體監聽器事件 xml 示例

[編輯 | 編輯原始碼]
<entity name="Employee" class="org.acme.Employee" access="FIELD">
    <entity-listeners>
        <entity-listener class="org.acme.EmployeeEventListener">
            <pre-persist method-name="prePersist"/>
            <pre-update method-name="preUpdate"/>
        </entity-listener>
    </entity-listeners>
    <attributes>
        <id name="uid"/>
    </attributes>
</entity>

預設實體監聽器

[編輯 | 編輯原始碼]

也可以配置預設的實體監聽器。此監聽器將接收持久化單元中所有實體類的事件。預設監聽器只能透過 XML 定義。

如果定義了預設的實體監聽器,而某個類想要定義自己的監聽器,或者不想使用預設監聽器,則可以使用 ExcludeDefaultListeners 註解或<exclude-default-listeners> XML 元素停用它。

預設實體監聽器 xml 示例

[編輯 | 編輯原始碼]
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.0"
        xmlns="http://java.sun.com/xml/ns/persistence/orm"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd">
    <persistence-unit-metadata>
        <persistence-unit-defaults>
            <entity-listeners>
                <entity-listener class="org.acme.ACMEEventListener">
                    <pre-persist method-name="prePersist"/>
                    <pre-update method-name="preUpdate"/>
                </entity-listener>
            </entity-listeners>
        </persistence-unit-defaults>
    </persistence-unit-metadata>
</entity-mappings>

事件和繼承

[edit | edit source]

實體監聽器是繼承的。如果子類不想繼承超類實體監聽器,則必須定義ExcludeSuperclassListeners註解或<exclude-superclass-listeners> XML 元素。

事件和嵌入式

[edit | edit source]

JPA 並沒有為Embeddable定義任何事件。一些 JPA 提供者可能允許為Embeddable物件定義事件。

擴充套件事件

[edit | edit source]

JPA 事件只定義了實體生命週期。沒有 EntityMangager 事件或系統級事件。

一些 JPA 提供者可能提供額外的事件。

TopLink / EclipseLink : 提供擴充套件事件機制。透過DescriptorEventListener API 定義了額外的Entity級事件。會話級事件機制也透過SessionEventListener API 提供。事件物件還提供了額外的資訊,包括資料庫行和物件更改集。

檢視

[edit | edit source]

資料庫VIEW 是表或查詢的虛擬檢視。檢視用於隱藏表、表集或資料集的複雜性。

在 JPA 中,您可以像對映表一樣對映到VIEW,使用@Table註解。然後,您可以將檢視中的每個列對映到物件的屬性。檢視通常是隻讀的,因此物件到檢視的對映通常也是隻讀的。在大多數資料庫中,檢視也可以是可更新的,這取決於它們封裝的查詢的複雜程度。即使對於複雜的查詢,資料庫觸發器通常也可以用於更新檢視。

檢視通常可以在 JPA 中用於解決對映限制。例如,如果 JPA 不支援表聯接,或者希望呼叫資料庫函式來轉換資料,這通常可以在檢視中完成,因此 JPA 就可以只對映到簡化的資料。

使用檢視確實需要資料庫專業知識,並且檢視的定義可能依賴於資料庫。

介面

[edit | edit source]

介面可以在模型中用於兩個主要目的。第一個是作為定義類公共 API 的公共介面。第二個是作為允許多個不同實現者的通用型別。

公共介面

[edit | edit source]

如果在 JPA 中有公共介面,您只需要對映實現類,大部分情況下就可以了。一個問題是,您需要使用實現類進行查詢,因為 JPA 不瞭解介面。對於 JPQL,預設別名也是實現類,但是您可以透過將Entityname設定為公共介面來重新定義它。

一些 JPA 提供者允許定義介面。

TopLink / EclipseLink : 支援使用DescriptorCustomizerInterfacePolicy 定義和查詢公共介面。

公共介面別名示例

[edit | edit source]
@Entity(name="Employee")
public class EmployeeImpl implements Employee {
  ...
}

如果您有一個使用公共介面而不是實現的關聯關係,那麼 JPA 將不知道如何正確對映它。您可以使用targetEntity屬性來定義關聯關係是到實現類(參見目標實體)。

公共介面關聯關係示例

[edit | edit source]
@Entity(name="Employee")
public class EmployeeImpl implements Employee {
  @ManyToOne(targetEntity=EmployeeImpl.class)
  private Employee manager;
}

介面型別

[edit | edit source]

如果您有一個具有多個不同實現者的通用介面,這可能會出現一些問題。如果您使用介面來定義可變關聯關係,那麼這很難對映。JPA 不直接支援介面或可變關聯關係。您可以將介面更改為abstract 類,然後使用TABLE_PER_CLASS 繼承來對映它。否則,您可以將關聯關係拆分為多個關聯關係,每個實現者一個,或者您可以只刪除關聯關係並查詢相關的物件。查詢介面也很困難,您需要查詢介面的每個實現者,然後在記憶體中聯合結果。

一些 JPA 提供者支援對映介面和可變關聯關係。

TopLink / EclipseLink : 支援使用SessionCustomizerRelationalDescriptorInterfacePolicy 對映介面。可變關聯關係可以使用@VariableOneToOne 註解或 XML 定義。

儲存過程

[edit | edit source]

儲存過程是駐留在資料庫中的過程或函式。儲存過程通常用類似於 SQL 的某些資料庫特定語言編寫,例如 Oracle 上的 PL/SQL。一些資料庫(例如 Oracle)還支援用 Java 編寫的儲存過程。

儲存過程可用於執行批處理資料處理任務。透過在資料庫中編寫任務,它可以避免將資料傳送到資料庫客戶端和從資料庫客戶端傳送資料的成本,因此可以更有效地執行。儲存過程還可以用於訪問只能在伺服器上訪問的資料庫特定功能。如果需要嚴格的安全要求,儲存過程也可以使用,以避免授予使用者訪問原始表或未經驗證的 SQL 操作的許可權。一些遺留應用程式也使用資料庫過程語言編寫,需要與它們整合。

使用儲存過程的缺點是它們不如使用 SQL 靈活,並且需要開發和維護通常用與應用程式開發人員可能習慣的語言不同的語言編寫的功能,並且難以開發和除錯,並且通常使用有限的過程程式語言。還有一種普遍的誤解,即使用儲存過程將提高效能,因為如果您將應用程式正在執行的相同 SQL 放入儲存過程,它將以某種方式變得更快。這是錯誤的,通常情況恰恰相反,因為儲存過程限制了持久層動態最佳化資料檢索的能力。只有當儲存過程使用比應用程式更最佳化的 SQL 時,儲存過程才會提高效能,通常是在它們在資料庫上執行整個任務時。要從應用程式中生成的 SQL 獲得最佳效能,您必須使用準備好的語句 - 否則資料庫每次提交查詢時都必須建立一個新的執行計劃。

JPA 2.1 StoredProcedureQuery

[edit | edit source]

JPA 2.1 支援使用StoredProcedureQuery@NamedStoredProcedureQuery 註解或<named-stored-procedure-query> XML 元素來呼叫資料庫儲存過程。JPA 支援元資料中定義的命名儲存過程呼叫和透過EntityManager.createNamedStoredProcedureQuery() 建立的命名儲存過程呼叫,以及透過EntityManager.createStoredProcedureQuery() 建立的動態儲存過程呼叫。

StoredProcedureQuery 是一個 JPA 查詢,它提供了額外的 API 用於設定儲存過程引數,以及用於訪問輸出引數和多個結果集。StoredProcedureQuery 可以返回實體物件或資料,類似於原生 SQL 查詢。ResultSetMapping 可用於將返回的欄位對映到實體列。

一些資料庫,如 MySQL、SQL Server 和 Sybase,支援返回結果集的儲存過程。一些資料庫,如 Oracle,不支援返回結果集,但支援返回遊標的輸出引數。如果儲存過程返回結果集或遊標輸出引數,則可以使用 getResultList()getSingleResult()。如果儲存過程具有多個結果集或多個遊標輸出引數,則再次呼叫 getResultList() 將返回下一個結果集或遊標輸出引數。如果儲存過程不返回任何內容,則可以使用 executeUpdate()StoredProcedureQuery 還定義了一個 execute() API,該 API 執行過程並返回一個 boolean 值,指示是否返回了結果集。執行後,可以使用 getOutputParameterValue() 訪問任何儲存過程的輸出引數。

儲存過程引數透過 @StoredProcedureParameter 註解或 <stored-procedure-parameter> XML 元素定義,或者對於動態儲存過程呼叫,透過 StoredProcedureQuery.registerStoredProcedureParameter() API 定義。引數可以命名或按索引,定義引數的相應 Java 型別,並透過 ParameterMode 定義引數的方向模式。模式可以是 ININOUTOUTREF_CURSOR 之一。對於 ref 遊標,可以使用 void.class 型別。

命名儲存過程註釋示例

[edit | edit source]
// This stored procedure returns a result set and has one input parameter.
@NamedStoredProcedureQuery(
    name = "ReadAddressById",
    resultClasses = Address.class,
    procedureName = "READ_ADDRESS",
    parameters = {
        @StoredProcedureParameter(mode=javax.persistence.ParameterMode.IN, name="P_ADDRESS_ID", type=Long.class)
    }
)
@Entity
public class Address {
  ...
}

呼叫命名儲存過程示例

[edit | edit source]
StoredProcedureQuery query = em.createNamedStoredProcedureQuery("ReadAddressById");
query.setParameter("P_ADDRESS_ID", 12345);
List<Address> result = query.getResultList();

命名遊標儲存過程註釋示例

[edit | edit source]
// This stored procedure returns a cursor output parameter, and has one input parameter.
@NamedStoredProcedureQuery(
    name = "ReadAddressById",
    resultClasses = Address.class,
    procedureName = "READ_ADDRESS",
    parameters = {
        @StoredProcedureParameter(mode=IN, name="P_ADDRESS_ID", type=Long.class),
        @StoredProcedureParameter(mode=REF_CURSOR, name="CUR_ADDRESS", type=void.class)
    }
)
@Entity
public class Address {
  ...
}

呼叫具有遊標輸出引數的命名儲存過程示例

[edit | edit source]
StoredProcedureQuery query = em.createNamedStoredProcedureQuery("ReadAddressById");
query.setParameter("P_ADDRESS_ID", 12345);
query.execute();
List<Address> result = (List<Address>)query.getOutputParameterValue("CUR_ADDRESS");

呼叫動態儲存過程示例

[edit | edit source]
StoredProcedureQuery query = em.createStoredProcedureQuery("VALIDATE_ADDRESS");
query.registerStoredProcedureParameter("P_COUNTRY", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("P_PROVINCE", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("P_CITY", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("P_STREET", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("P_POSTAL_CD", String.class, ParameterMode.IN);
query.registerStoredProcedureParameter("OUT_VALID", Boolean.class, ParameterMode.OUT);
query.registerStoredProcedureParameter("OUT_ID", Long.class, ParameterMode.OUT);

query.setParameter("P_COUNTRY", "Canada");
query.setParameter("P_PROVINCE", "ON");
query.setParameter("P_CITY", "Ottawa");
query.setParameter("P_STREET", "99 Bank");
query.setParameter("P_POSTAL_CD", "K2H8L2");

query.execute();
Boolean isValid = (Boolean)query.getOutputParameterValue("OUT_VALID");
Long id = (Long)query.getOutputParameterValue("OUT_ID");

JPA 2.0 中的儲存過程

[edit | edit source]

JPA 2.0 不直接支援儲存過程。某些型別的儲存過程可以透過使用原生查詢在 JPA 中執行。JPA 中的原生查詢允許執行任何不返回任何內容或返回資料庫結果集的 SQL。執行儲存過程的語法取決於資料庫。JPA 原生 SQL 查詢不支援使用 OUTPUTINOUT 引數的儲存過程。一些資料庫,如 DB2、Sybase 和 SQL Server,允許儲存過程返回結果集。Oracle 不允許返回結果集,只允許 OUTPUT 引數,但定義了一個可以作為 OUTPUT 引數返回的 CURSOR 型別。Oracle 還支援儲存函式,這些函式可以返回單個值。通常可以使用原生 SQL 查詢透過從 Oracle DUAL 表中選擇函式值來執行儲存函式。

一些 JPA 提供者擴充套件了對儲存過程的支援,一些提供者還支援使用儲存過程或自定義 SQL 重寫 Entity 的任何 CRUD 操作。一些 JPA 提供者支援 CURSOR OUTPUT 引數。

TopLink / EclipseLink : 使用 @NamedStoredProcedureQuery, @NamedStoredFunctionQuery 註解或 XML,或 StoredProcedureCall, StoredFunctionCall 類支援儲存過程和儲存函式。還支援使用 DescriptorCustomizerDescriptorQueryManager 類重寫類的或關係的任何 CRUD 操作。支援 IN、OUT、INOUT 和 CURSOR OUTPUT 引數。

在 Oracle 上執行儲存過程示例

[edit | edit source]
EntityManager em = getEntityManager();
Query query = em.createNativeQuery("BEGIN VALIDATE_EMP(P_EMP_ID=>?); END;");
query.setParameter(1, empId);
query.executeUpdate();

PL/SQL 儲存過程

[edit | edit source]

在 Oracle 中,儲存過程通常用 Oracle 的 PL/SQL 語言編寫。Oracle 中的 PL/SQL 支援一些其他資料型別,Oracle 不透過 SQL 或 JDBC 支援這些資料型別。這些型別包括 BOOLEANTABLERECORD 等型別。從 Java 訪問這些型別或過程很困難,因為 JDBC 不支援這些型別。一種解決方法是用普通的儲存過程包裝 PL/SQL 儲存過程,這些儲存過程將 PL/SQL 型別轉換為標準 SQL/JDBC 型別,如 INTVARRAY (Array) 和 OBJECT TYPE (Struct)。一些 JPA 提供者擴充套件了對呼叫 PL/SQL 儲存過程的支援。

TopLink / EclipseLink : 使用 @NamedPLSQLStoredProcedureQuery, @NamedPLSQLStoredFunctionQuery 註解或 XML,或 PLSQLStoredProcedureCall, PLSQLStoredFunctionCall 類支援 PL/SQL 儲存過程和函式。

結構化物件關係資料型別

[edit | edit source]

在面向物件資料庫 (OODBMS) 興起時,許多關係資料庫供應商決定將面向物件的概念新增到關係資料中。這些新的*混合* 資料庫被稱為物件關係資料庫,因為它們可以儲存物件和關係資料。這些物件關係資料型別在 SQL3 中被標準化,並且從 Java 中的 JDBC 2.0 API 中添加了對它們的 支援。儘管圍繞新的資料形式有很多炒作,但物件關係資料從未流行起來,因為人們似乎更喜歡他們的標準關係資料。通常不建議使用物件關係資料,因為關係資料更標準,但是如果處理非常複雜的資料,它可能是一個可以研究的內容。

一些常見的物件關係資料庫功能包括

  • 物件型別(結構)
  • 陣列和陣列型別
  • 巢狀表
  • 繼承
  • 物件 ID (OID)
  • 引用

支援物件關係資料的資料庫包括

  • Oracle
  • DB2
  • PostgreSQL

基本模型允許你定義結構或物件型別來表示你的資料,結構可以具有巢狀結構、基本資料的陣列或其他結構,以及對其他結構的引用。然後,你可以在一個普通的 關係表列中儲存結構,或者建立一個特殊表格來直接儲存結構。查詢是基本的 SQL,有一些擴充套件來處理遍歷特殊型別。

JPA 不支援物件關係資料型別,但一些 JPA 提供者可能會提供一些支援。

TopLink / EclipseLink : 透過它們的 @Struct, @Structure, @Array 註解和 XML,或它們的 ObjectRelationalDataTypeDescriptor 和對映類支援物件關係資料型別。還為 Oracle 空間資料庫 JGeometry 結構和其他結構化資料型別提供了自定義支援,使用 @StructConverter 註解或 XML。

另請參閱,

XML 資料型別

[edit | edit source]

隨著 XML 資料庫的出現,許多關係資料庫決定新增增強的 XML 支援。儘管始終可以使用 VARCHARCLOB 列在關係資料庫中儲存 XML,但讓資料庫意識到 XML 資料確實有其優點。主要優點是提供 XML 支援的資料庫允許使用 XPath 或 XQuery 語法查詢 XML 資料。一些資料庫還允許比 Lob 儲存更有效地儲存 XML 資料。

具有 XML 支援的資料庫包括

  • Oracle (XDB)
  • DB2
  • PostgreSQL

JPA 不擴充套件支援 XML 資料,儘管可以將 XML 字串儲存到資料庫中,只需將其對映為 Basic 即可。一些 JPA 提供者可能會提供擴充套件的 XML 資料支援。例如,查詢擴充套件,或允許對映 XML DOM。

如果你希望將 XML 資料對映到物件,可以使用 JAXB 規範。你甚至可以將它與 JPA 物件整合。

TopLink / EclipseLink : 支援 Oracle XDB XMLType 列,使用它們的 DirectToXMLTypeMapping。XMLType 可以對映為字串或 XML DOM(文件)。為 Expression 查詢中的 XPath 查詢提供查詢擴充套件。EclipseLink 還包含用於物件-XML 對映的 JAXB 實現。

過濾器

[編輯 | 編輯原始碼]

有時需要從所有查詢中過濾掉表中的一些內容。這通常是因為該表由多個型別、應用程式、租戶或區域共享,而 JPA 應用程式只對其中一部分行感興趣。也可能是因為該表包含 JPA 應用程式應忽略的歷史記錄或存檔行。

JPA 未提供任何專門用於過濾資料的支援,但有一些可用選項。繼承可用於在行的型別上進行型別檢查。例如,如果在 EMPLOYEE 表中有一個 STATUS 列,則可以定義 EmployeeCurrentEmployee 子類,其鑑別器 STATUSACTIVE,並且始終在應用程式中使用 CurrentEmployee。同樣,可以定義一個 ACMEEmployee 子類,該子類使用 TENANT 列作為其值為 ACME 的類鑑別器。另一個解決方案是使用資料庫檢視來過濾資料並將實體對映到這些檢視。

這些解決方案不適用於動態過濾,在這種過濾中,過濾條件引數在執行時之前未知(例如租戶或區域)。此外,無法透過繼承來建模複雜條件,儘管資料庫檢視仍然應該有效。一種解決方案是始終將條件追加到任何查詢中,例如將 JPQL 字串或 JPA 條件追加到應用程式程式碼中。

虛擬專用資料庫 (VPD) 支援也可能提供解決方案。一些資料庫(如 Oracle)支援 VPD,允許根據連線的使用者或代理證書對行進行基於上下文的過濾。

一些 JPA 提供程式對過濾資料有特定支援。

TopLink / EclipseLink : 透過其 @AdditionalCriteria 註解和 XML 支援過濾資料。這允許將任意 JPQL 片段追加到該實體的所有查詢中。該片段可以包含可以透過永續性單元或上下文屬性在執行時設定的引數。還支援 Oracle VPD,包括 Oracle 代理身份驗證和隔離資料。

歷史記錄

[編輯 | 編輯原始碼]

資料庫應用程式中的一種常見需求是維護資料庫更改的記錄和歷史記錄。這可用於跟蹤和審計目的,或允許撤消更改,或保留系統資料隨時間的記錄。許多資料庫都具有審計功能,允許對資料進行的更改進行一定程度的跟蹤。一些資料庫(如 Oracle 的 Flashback 功能)允許在行級別自動跟蹤歷史記錄,甚至允許查詢資料的過去版本。

應用程式也可以透過其資料模型來維護自己的歷史記錄。所需的一切是在表中新增一個 STARTEND 時間戳列。然後,當前 行是 END 時間戳為 null 的行。當插入一行時,其 START 時間戳將設定為當前時間。當更新一行時,系統將插入一個具有相同 id 和資料的新行,但具有不同的 START 時間戳,並將舊行更新為將其 END 時間戳設定為當前時間。該表的主鍵需要新增 START 時間戳。

歷史記錄還可以用於避免刪除。可以僅將 END 時間戳設定為當前時間,而不是刪除一行。另一個解決方案是向表中新增一個 DELETED 布林列,並在刪除一行時進行記錄。

歷史記錄資料可以儲存在修改後的表中,也可以將表保留為僅包含資料的當前版本,並新增一個映象歷史記錄表來儲存資料。在映象情況下,可以使用資料庫觸發器寫入歷史記錄表。對於就地情況,可以使用資料庫檢視來提供表在當前時間的檢視。

要從歷史記錄表中查詢當前資料,任何查詢都必須包含 ENDNULL 的子句。要查詢特定時間點,where 子句必須包含該時間點位於 STARTEND 時間戳之間的條件。

JPA 未定義任何特定的歷史記錄支援。

可以使用 JPA 使用 Oracle 回閃,但任何針對歷史資料的查詢都需要使用本機 SQL。

如果使用具有觸發器的映象歷史記錄表,JPA 仍然可以用於查詢當前資料。也可以將子類或兄弟類對映到歷史記錄表,以允許查詢歷史記錄資料。

如果使用資料庫檢視,則可以透過將 Entity 對映到該檢視來使用 JPA。

如果使用歷史記錄表,JPA 仍然可以用於對映到該表,並且可以向物件新增 startend 屬性。針對當前資料的查詢可以將當前時間追加到查詢中。關係更難處理,因為 JPA 要求關係按主鍵進行,而歷史記錄關係則不會。

一些 JPA 提供程式支援歷史記錄。

TopLink / EclipseLink : 支援 Oracle 回閃查詢以及應用程式特定的歷史記錄。可以使用查詢提示 "eclipselink.history.as-of"Expression 查詢來定義歷史查詢。還支援使用 HistoryPolicy API 自動跟蹤歷史記錄,該 API 支援維護和查詢映象歷史記錄表。

邏輯刪除

[編輯 | 編輯原始碼]

請參閱 審計和安全

資料複製可用於備份資料,以提高容錯能力和故障轉移,或用於負載均衡和擴充套件資料庫。

對於複製,更改將寫入多個數據庫,這些更改可以由應用程式、JPA 提供程式或資料庫後端進行。對於故障轉移,如果其中一個數據庫出現故障,則可以使用另一個數據庫,而不會丟失資料或應用程式停機時間。對於負載均衡,讀取請求可以在複製的資料庫之間進行負載均衡,以減少每個資料庫上的負載,並提高應用程式的可擴充套件性。

大多數企業資料庫都支援某種形式的自動備份或複製。諸如 Oracle RAC 之類的叢集資料庫還允許負載均衡、故障轉移和高可用性。如果您的資料庫支援複製或叢集,則它通常對 JPA 是透明的。可能需要使用專門的 DataSource(如 Oracle UCP 或 WebLogic GridLink)來處理負載均衡和故障轉移。

JPA 未定義任何特定的資料複製支援,但一些 JPA 提供程式提供複製支援。如果您的資料庫不支援複製,則可以透過擁有多個永續性單元並將物件持久化和合併到兩個資料庫中來自己實現複製。

TopLink / EclipseLink : 支援複製、負載均衡和故障轉移。複製和負載均衡透過 EclipseLink 的分割槽支援(使用 @ReplicationPartitioning@RoundRobinPartitioning 註解和 XML)來支援。

分割槽

[編輯 | 編輯原始碼]

資料分割槽可用於在多個數據庫機器上擴充套件應用程式,或與 Oracle RAC 之類的叢集資料庫一起使用。

分割槽將您的資料拆分到每個資料庫節點中。有水平分割槽和垂直分割槽。垂直分割槽通常是最容易實現的。您只需將一半類放在一個數據庫中,而另一半放在另一個數據庫中。理想情況下,這兩個集合彼此隔離,並且沒有任何跨資料庫關係。這可以透過 JPA 直接完成,方法是為每個資料庫建立兩個不同的永續性單元。

對於水平分割槽,您需要將資料拆分到多個數據庫節點中。每個資料庫節點將具有相同的表,但每個節點的表將僅儲存一部分資料。您可以按資料值對資料進行分割槽,例如範圍分割槽、值分割槽、雜湊分割槽,甚至迴圈分割槽。JPA 未定義任何資料分割槽支援,因此您要麼需要為每個分割槽定義一個不同的類,要麼使用 JPA 供應商特定的功能。

TopLink / EclipseLink : 支援水平和垂直資料分割槽。在會話、實體和查詢級別支援雜湊、值、範圍、固定和自定義分割槽。分割槽透過 @Partitioning, @HashPartitioning, @RangePartitioning, @ValuePartitioning, @PinnedPartitioning@Partitioned 註解和 XML 來支援。

另請參閱,

資料整合

[編輯 | 編輯原始碼]

NoSQL(以及 EIS、傳統、XML 和非關係型資料)

[編輯 | 編輯原始碼]

NoSQL

多租戶

[編輯 | 編輯原始碼]

動態資料

[編輯 | 編輯原始碼]
華夏公益教科書