JavaRush /Blog Java /Random-VI /JPA: Giới thiệu công nghệ
Viacheslav
Mức độ

JPA: Giới thiệu công nghệ

Xuất bản trong nhóm
Thế giới phát triển hiện đại có đầy đủ các thông số kỹ thuật khác nhau được thiết kế để giúp cuộc sống dễ dàng hơn. Biết các công cụ, bạn có thể chọn một công cụ phù hợp. Nếu không biết, bạn có thể khiến cuộc sống của mình trở nên khó khăn hơn. Đánh giá này sẽ vén bức màn bí mật về khái niệm JPA - Java Persistence API. Tôi hy vọng rằng sau khi đọc bạn sẽ muốn đi sâu hơn nữa vào thế giới bí ẩn này.
JPA : Giới thiệu công nghệ - 1

Giới thiệu

Như chúng ta đã biết, một trong những nhiệm vụ chính của chương trình là lưu trữ và xử lý dữ liệu. Ngày xưa, mọi người chỉ lưu trữ dữ liệu trong các tập tin. Nhưng ngay khi cần quyền truy cập đọc và chỉnh sửa đồng thời, khi có tải (tức là có nhiều yêu cầu đến cùng lúc), việc lưu trữ dữ liệu đơn giản trong tệp sẽ trở thành một vấn đề. Để biết thêm thông tin về những vấn đề mà cơ sở dữ liệu giải quyết và cách giải quyết, tôi khuyên bạn nên đọc bài viết “ Cơ sở dữ liệu được cấu trúc như thế nào ”. Điều này có nghĩa là chúng tôi quyết định lưu trữ dữ liệu của mình trong cơ sở dữ liệu. Từ lâu, Java đã có thể làm việc với cơ sở dữ liệu bằng API JDBC (Kết nối cơ sở dữ liệu Java). Bạn có thể đọc thêm về JDBC tại đây: “ JDBC hoặc nơi tất cả bắt đầu .” Nhưng thời gian trôi qua và các nhà phát triển mỗi lần đều phải đối mặt với nhu cầu viết cùng một loại và mã “bảo trì” không cần thiết (còn gọi là mã Boilerplate) cho các hoạt động tầm thường là lưu các đối tượng Java trong cơ sở dữ liệu và ngược lại, tạo các đối tượng Java bằng cách sử dụng dữ liệu từ cơ sở dữ liệu. Và sau đó, để giải quyết những vấn đề này, một khái niệm như ORM đã ra đời. ORM - Ánh xạ quan hệ đối tượng hoặc được dịch sang ánh xạ quan hệ đối tượng tiếng Nga. Nó là một công nghệ lập trình liên kết cơ sở dữ liệu với các khái niệm về ngôn ngữ lập trình hướng đối tượng. Để đơn giản hóa, ORM là kết nối giữa các đối tượng Java và các bản ghi trong cơ sở dữ liệu: JPA: Giới thiệu công nghệ - 2ORM về cơ bản là khái niệm rằng một đối tượng Java có thể được biểu diễn dưới dạng dữ liệu trong cơ sở dữ liệu (và ngược lại). Nó được thể hiện dưới dạng đặc tả JPA - Java Persistence API. Đặc tả này đã là một mô tả về API Java thể hiện khái niệm này. Thông số kỹ thuật cho chúng tôi biết những công cụ nào chúng tôi phải được cung cấp (tức là những giao diện nào chúng tôi có thể làm việc thông qua) để hoạt động theo khái niệm ORM. Và cách sử dụng số tiền này. Đặc tả không mô tả việc thực hiện các công cụ. Điều này giúp có thể sử dụng các cách triển khai khác nhau cho một thông số kỹ thuật. Bạn có thể đơn giản hóa nó và nói rằng đặc tả là mô tả về API. Văn bản của đặc tả JPA có thể được tìm thấy trên trang web của Oracle: " JSR 338: JavaTM Persistence API ". Do đó, để sử dụng JPA, chúng tôi cần một số triển khai mà chúng tôi sẽ sử dụng công nghệ này. Việc triển khai JPA còn được gọi là Nhà cung cấp JPA. Một trong những triển khai JPA đáng chú ý nhất là Hibernate . Vì vậy, tôi đề nghị xem xét nó.
JPA: Giới thiệu về Công nghệ - 3

Tạo một dự án

Vì JPA là về Java nên chúng ta sẽ cần một dự án Java. Chúng tôi có thể tự tạo cấu trúc thư mục theo cách thủ công và tự thêm các thư viện cần thiết. Nhưng sẽ thuận tiện và chính xác hơn nhiều khi sử dụng các hệ thống để tự động hóa việc lắp ráp các dự án (tức là về bản chất, đây chỉ là một chương trình sẽ quản lý việc lắp ráp các dự án cho chúng ta. Tạo thư mục, thêm các thư viện cần thiết vào đường dẫn lớp, v.v. .). Một hệ thống như vậy là Gradle. Bạn có thể đọc thêm về Gradle tại đây: " Giới thiệu tóm tắt về Gradle ". Như chúng ta đã biết, chức năng của Gradle (tức là những việc nó có thể làm) được triển khai bằng nhiều Plugin cho Gradle khác nhau. Hãy sử dụng Gradle và plugin " Gradle Build init Plugin ". Hãy chạy lệnh:

gradle init --type java-application
Gradle sẽ thực hiện cấu trúc thư mục cần thiết cho chúng ta và tạo mô tả khai báo cơ bản về dự án trong tập lệnh xây dựng build.gradle. Vì vậy, chúng tôi có một ứng dụng. Chúng ta cần suy nghĩ về những gì chúng ta muốn mô tả hoặc mô hình hóa bằng ứng dụng của mình. Hãy sử dụng một số công cụ lập mô hình, ví dụ: app.quickdatabasediagrams.com JPA: Giới thiệu công nghệ - 4 Ở đây cần nói rằng những gì chúng tôi đã mô tả là “mô hình miền” của chúng tôi. Tên miền là một “lĩnh vực chủ đề”. Nói chung, tên miền trong tiếng Latin là “sở hữu”. Vào thời Trung cổ, đây là tên được đặt cho những khu vực thuộc sở hữu của các vị vua hoặc lãnh chúa phong kiến. Và trong tiếng Pháp, nó trở thành từ "domaine", dịch đơn giản là "khu vực". Vì vậy, chúng tôi đã mô tả “mô hình miền” = “mô hình chủ đề” của mình. Mỗi phần tử của mô hình này là một loại “bản chất” nào đó, một thứ gì đó từ cuộc sống thực. Trong trường hợp của chúng tôi, đây là các thực thể: Danh mục ( Category), Chủ đề ( Topic). Hãy tạo một gói riêng cho các thực thể, ví dụ như với mô hình tên. Và hãy thêm các lớp Java mô tả các thực thể vào đó. Trong mã Java, các thực thể như vậy là POJO thông thường , có thể trông giống như sau:
public class Category {
    private Long id;
    private String title;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
Hãy sao chép nội dung của lớp và tạo một lớp bằng cách tương tự Topic. Anh ta sẽ chỉ khác nhau ở những gì anh ta biết về loại mà anh ta thuộc về. Do đó, hãy thêm Topictrường danh mục và các phương thức để làm việc với nó vào lớp:
private Category category;

public Category getCategory() {
	return category;
}

public void setCategory(Category category) {
	this.category = category;
}
Bây giờ chúng ta có một ứng dụng Java có mô hình miền riêng. Bây giờ là lúc bắt đầu kết nối với dự án JPA.
JPA: Giới thiệu công nghệ - 5

Thêm JPA

Vì vậy, như chúng ta nhớ, JPA có nghĩa là chúng ta sẽ lưu thứ gì đó vào cơ sở dữ liệu. Vì vậy, chúng ta cần một cơ sở dữ liệu. Để sử dụng kết nối cơ sở dữ liệu trong dự án của chúng tôi, chúng tôi cần thêm thư viện phụ thuộc để kết nối với cơ sở dữ liệu. Như chúng tôi nhớ, chúng tôi đã sử dụng Gradle để tạo tập lệnh xây dựng cho chúng tôi build.gradle. Trong đó chúng tôi sẽ mô tả các phần phụ thuộc mà dự án của chúng tôi cần. Phần phụ thuộc là những thư viện mà nếu không có thì mã của chúng tôi không thể hoạt động được. Hãy bắt đầu với phần mô tả sự phụ thuộc vào việc kết nối với cơ sở dữ liệu. Chúng tôi thực hiện điều này giống như cách chúng tôi sẽ làm nếu chúng tôi chỉ làm việc với JDBC:

dependencies {
	implementation 'com.h2database:h2:1.4.199'
Bây giờ chúng tôi có một cơ sở dữ liệu. Bây giờ chúng ta có thể thêm một lớp vào ứng dụng của mình, lớp này chịu trách nhiệm ánh xạ các đối tượng Java của chúng ta vào các khái niệm cơ sở dữ liệu (từ Java sang SQL). Như chúng ta nhớ, chúng ta sẽ sử dụng cách triển khai đặc tả JPA có tên Hibernate cho việc này:

dependencies {
	implementation 'com.h2database:h2:1.4.199'
	implementation 'org.hibernate:hibernate-core:5.4.2.Final'
Bây giờ chúng ta cần cấu hình JPA. Nếu chúng ta đọc thông số kỹ thuật và phần "Đơn vị bền vững 8.1", chúng ta sẽ biết rằng Đơn vị bền vững là một loại kết hợp giữa cấu hình, siêu dữ liệu và thực thể. Và để JPA hoạt động, bạn cần mô tả ít nhất một Persistence Unit trong tệp cấu hình, được gọi là persistence.xml. Vị trí của nó được mô tả trong chương thông số kỹ thuật "8.2 Đóng gói đơn vị bền vững". Theo phần này, nếu chúng ta có môi trường Java SE thì phải đặt nó vào thư mục gốc của thư mục META-INF.
JPA: Giới thiệu công nghệ - 6
Hãy sao chép nội dung từ ví dụ được đưa ra trong đặc tả JPA trong 8.2.1 persistence.xml filechương " ":
<persistence>
	<persistence-unit name="JavaRush">
        <description>Persistence Unit For test</description>
        <class>hibernate.model.Category</class>
        <class>hibernate.model.Topic</class>
    </persistence-unit>
</persistence>
Nhưng điều này là không đủ. Chúng tôi cần cho biết Nhà cung cấp JPA của chúng tôi là ai, tức là. người thực hiện đặc tả JPA:
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
Bây giờ hãy thêm cài đặt ( properties). Một số trong số chúng (bắt đầu bằng javax.persistence) là cấu hình JPA tiêu chuẩn và được mô tả trong đặc tả JPA trong phần "thuộc tính 8.2.1.9". Một số cấu hình dành riêng cho nhà cung cấp (trong trường hợp của chúng tôi, chúng ảnh hưởng đến Hibernate với tư cách là Nhà cung cấp Jpa. Khối cài đặt của chúng tôi sẽ trông như thế này:
<properties>
    <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
    <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE" />
    <property name="javax.persistence.jdbc.user" value="sa" />
    <property name="javax.persistence.jdbc.password" value="" />
    <property name="hibernate.show_sql" value="true" />
    <property name="hibernate.hbm2ddl.auto" value="create" />
</properties>
Bây giờ chúng ta đã có config tương thích với JPA persistence.xml, có Hibernate nhà cung cấp JPA và có cơ sở dữ liệu H2, ngoài ra còn có 2 lớp là mô hình miền của chúng ta. Cuối cùng chúng ta hãy làm cho tất cả điều này hoạt động. Trong danh mục /test/java, Gradle của chúng tôi đã tạo một mẫu cho các bài kiểm tra Đơn vị và gọi nó là AppTest. Hãy sử dụng nó. Như đã nêu trong chương "7.1 Bối cảnh liên tục" của đặc tả JPA, các thực thể trong thế giới JPA sống trong một không gian được gọi là Bối cảnh liên tục. Nhưng chúng tôi không trực tiếp làm việc với Persistence Context. Đối với điều này, chúng tôi sử dụng Entity Managerhoặc "người quản lý thực thể". Chính anh ta là người biết về bối cảnh và những thực thể sống ở đó. Chúng tôi tương tác với Entity Manager'om. Sau đó, tất cả những gì còn lại là hiểu chúng ta có thể lấy cái này ở đâu Entity Manager? Theo chương "7.2.2 Lấy Trình quản lý thực thể được quản lý ứng dụng" của đặc tả JPA, chúng ta phải sử dụng EntityManagerFactory. Do đó, chúng ta hãy trang bị cho mình đặc tả JPA và lấy một ví dụ từ chương “7.3.2 Lấy một nhà máy quản lý thực thể trong môi trường Java SE” và định dạng nó dưới dạng một bài kiểm tra Đơn vị đơn giản:
@Test
public void shouldStartHibernate() {
	EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
	EntityManager entityManager = emf.createEntityManager();
}
Thử nghiệm này sẽ hiển thị lỗi "Phiên bản XSD JPA Persence.xml không được nhận dạng". Lý do là persistence.xmlbạn cần xác định chính xác lược đồ sẽ sử dụng, như đã nêu trong đặc tả JPA ở phần “8.3 Persence.xml Schema”:
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
             version="2.2">
Ngoài ra, thứ tự của các yếu tố là quan trọng. Vì vậy, providernó phải được chỉ định trước khi liệt kê các lớp. Sau đó, thử nghiệm sẽ chạy thành công. Chúng ta đã hoàn thành việc kết nối JPA trực tiếp. Trước khi tiếp tục, chúng ta hãy nghĩ về các bài kiểm tra còn lại. Mỗi bài kiểm tra của chúng tôi sẽ yêu cầu EntityManager. Hãy đảm bảo rằng mỗi bài kiểm tra đều có bài kiểm tra riêng EntityManagerkhi bắt đầu thực hiện. Ngoài ra, chúng tôi muốn cơ sở dữ liệu luôn mới. Do chúng tôi sử dụng inmemorytùy chọn nên chỉ cần đóng EntityManagerFactory. Sáng tạo Factorylà một hoạt động tốn kém. Nhưng đối với các bài kiểm tra thì điều đó là hợp lý. JUnit cho phép bạn chỉ định các phương thức sẽ được thực thi trước (Trước) và sau (Sau) khi thực hiện mỗi bài kiểm tra:
public class AppTest {
    private EntityManager em;

    @Before
    public void init() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
        em = emf.createEntityManager();
    }

    @After
    public void close() {
        em.getEntityManagerFactory().close();
        em.close();
    }
Bây giờ, trước khi thực hiện bất kỳ thử nghiệm nào, một thử nghiệm mới sẽ được tạo EntityManagerFactory, điều này sẽ đòi hỏi phải tạo cơ sở dữ liệu mới, bởi vì hibernate.hbm2ddl.autocó ý nghĩa create. Và từ nhà máy mới, chúng ta sẽ có một nhà máy mới EntityManager.
JPA: Giới thiệu công nghệ - 7

Thực thể

Như chúng tôi nhớ, trước đây chúng tôi đã tạo các lớp mô tả mô hình miền của mình. Chúng tôi đã nói rằng đây là những “bản chất” của chúng tôi. Đây là Thực thể mà chúng tôi sẽ quản lý bằng cách sử dụng EntityManager. Hãy viết một bài kiểm tra đơn giản để lưu lại bản chất của một danh mục:
@Test
public void shouldPersistCategory() {
	Category cat = new Category();
	cat.setTitle("new category");
	// JUnit обеспечит тест свежим EntityManager'ом
	em.persist(cat);
}
Nhưng bài kiểm tra này sẽ không có kết quả ngay lập tức, bởi vì... chúng tôi sẽ nhận được nhiều lỗi khác nhau giúp chúng tôi hiểu thực thể là gì:
  • Unknown entity: hibernate.model.Category
    Tại sao Hibernate không hiểu Categoryđây là gì entity? Vấn đề là các thực thể phải được mô tả theo tiêu chuẩn JPA.
    Các lớp thực thể phải được chú thích bằng chú thích @Entity, như đã nêu trong chương "2.1 Lớp thực thể" của đặc tả JPA.

  • No identifier specified for entity: hibernate.model.Category
    Các thực thể phải có một mã định danh duy nhất có thể được sử dụng để phân biệt bản ghi này với bản ghi khác.
    Theo chương "2.4 Khóa chính và nhận dạng thực thể" của đặc tả JPA, "Mọi thực thể phải có khóa chính", tức là. Mọi thực thể đều phải có một "khóa chính". Khóa chính như vậy phải được chỉ định bằng chú thích@Id

  • ids for this class must be manually assigned before calling save()
    ID phải đến từ đâu đó. Nó có thể được chỉ định thủ công hoặc có thể được lấy tự động.
    Do đó, như đã chỉ ra trong các chương "11.2.3.3 GenerationdValue" và "11.1.20 GenerationdValue Annotation", chúng ta có thể chỉ định chú thích @GeneratedValue.

Vì vậy, để lớp danh mục trở thành một thực thể, chúng ta phải thực hiện những thay đổi sau:
@Entity
public class Category {
    @Id
    @GeneratedValue
    private Long id;
Ngoài ra, chú thích @Idcòn cho biết nên sử dụng cái nào Access Type. Bạn có thể đọc thêm về loại truy cập trong đặc tả JPA, trong phần "2.3 Loại truy cập". Nói một cách ngắn gọn, bởi vì... chúng ta đã chỉ định @Idở trên trường ( field), thì loại truy cập sẽ là mặc định field-basedchứ không phải property-based. Do đó, nhà cung cấp JPA sẽ đọc và lưu trữ giá trị trực tiếp từ các trường. Nếu chúng tôi đặt @Idphía trên getter thì property-basedquyền truy cập sẽ được sử dụng, tức là. thông qua getter và setter. Khi chạy thử nghiệm, chúng ta cũng xem được những yêu cầu nào được gửi tới cơ sở dữ liệu (nhờ vào tùy chọn hibernate.show_sql). Nhưng khi lưu lại thì chúng ta không thấy cái nào cả insert. Hóa ra chúng ta thực sự không lưu được gì cả? JPA cho phép bạn đồng bộ hóa bối cảnh lưu giữ và cơ sở dữ liệu bằng phương thức flush:
entityManager.flush();
Nhưng nếu chúng ta thực hiện nó ngay bây giờ, chúng ta sẽ gặp lỗi: không có giao dịch nào đang diễn ra . Và bây giờ là lúc tìm hiểu về cách JPA sử dụng các giao dịch.
JPA: Giới thiệu công nghệ - 8

Giao dịch JPA

Như chúng ta nhớ, JPA dựa trên khái niệm bối cảnh bền vững. Đây là nơi các thực thể sinh sống. Và chúng tôi quản lý các thực thể thông qua EntityManager. Khi chúng ta thực thi lệnh persist, chúng ta đặt thực thể vào ngữ cảnh. Chính xác hơn, chúng tôi nói với EntityManagerbạn rằng việc này cần phải được thực hiện. Nhưng bối cảnh này chỉ là một khu vực lưu trữ nào đó. Nó thậm chí đôi khi còn được gọi là "bộ nhớ đệm cấp một". Nhưng nó cần được kết nối với cơ sở dữ liệu. Lệnh flushtrước đây bị lỗi do lỗi, đồng bộ hóa dữ liệu từ bối cảnh lưu giữ lâu dài với cơ sở dữ liệu. Nhưng điều này đòi hỏi phải có sự vận chuyển và sự vận chuyển này là một giao dịch. Các giao dịch trong JPA được mô tả trong phần "7.5 Kiểm soát giao dịch" của thông số kỹ thuật. Có một API đặc biệt để sử dụng các giao dịch trong JPA:
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
Chúng tôi cần thêm quản lý giao dịch vào mã của mình, mã này chạy trước và sau khi kiểm tra:
@Before
public void init() {
	EntityManagerFactory emf = Persistence.createEntityManagerFactory( "JavaRush" );
	em = emf.createEntityManager();
	em.getTransaction().begin();
}
@After
public void close() {
	if (em.getTransaction().isActive()) {
		em.getTransaction().commit();
        }
	em.getEntityManagerFactory().close();
	em.close();
}
Sau khi thêm, chúng ta sẽ thấy trong nhật ký chèn một biểu thức trong SQL mà trước đây không có:
JPA: Giới thiệu công nghệ - 9
Những thay đổi tích lũy trong EntityManagergiao dịch đã được cam kết (xác nhận và lưu) trong cơ sở dữ liệu. Bây giờ chúng ta hãy cố gắng tìm ra bản chất của chúng ta. Hãy tạo một thử nghiệm để tìm kiếm một thực thể theo ID của nó:
@Test
public void shouldFindCategory() {
	Category cat = new Category();
	cat.setTitle("test");
	em.persist(cat);
	Category result = em.find(Category.class, 1L);
	assertNotNull(result);
}
Trong trường hợp này, chúng tôi sẽ nhận được thực thể mà chúng tôi đã lưu trước đó, nhưng chúng tôi sẽ không thấy các truy vấn CHỌN trong nhật ký. Và mọi thứ đều dựa trên những gì chúng tôi nói: “Người quản lý thực thể, vui lòng tìm cho tôi thực thể Danh mục có ID=1.” Và trình quản lý thực thể trước tiên sẽ xem xét ngữ cảnh của nó (sử dụng một loại bộ đệm) và chỉ khi không tìm thấy nó, nó mới đi tìm trong cơ sở dữ liệu. Cần thay đổi ID thành 2 (không có trường hợp nào như vậy, chúng tôi chỉ lưu 1 trường hợp) và chúng tôi sẽ thấy SELECTyêu cầu xuất hiện. Bởi vì không tìm thấy thực thể nào trong ngữ cảnh và EntityManagercơ sở dữ liệu đang cố gắng tìm kiếm một thực thể nên có nhiều lệnh khác nhau mà chúng ta có thể sử dụng để kiểm soát trạng thái của một thực thể trong ngữ cảnh. Sự chuyển đổi của một thực thể từ trạng thái này sang trạng thái khác được gọi là vòng đời của thực thể - lifecycle.
JPA : Знакомство с технологией - 10

Vòng đời thực thể

Vòng đời của các thực thể được mô tả trong đặc tả JPA ở chương "3.2 Vòng đời của thực thể thực thể". Bởi vì các thực thể sống trong một bối cảnh và được kiểm soát bởi EntityManager, khi đó họ nói rằng các thực thể đó được kiểm soát, tức là. được quản lý. Chúng ta hãy nhìn vào các giai đoạn trong vòng đời của một thực thể:
// 1. New or Transient (временный)
Category cat = new Category();
cat.setTitle("new category");
// 2. Managed or Persistent
entityManager.persist(cat);
// 3. Транзакция завершена, все сущности в контексте detached
entityManager.getTransaction().begin();
entityManager.getTransaction().commit();
// 4. Сущность изымаем из контекста, она становится detached
entityManager.detach(cat);
// 5. Сущность из detached можно снова сделать managed
Category managed = entityManager.merge(cat);
// 6. И можно сделать Removed. Интересно, что cat всё равно detached
entityManager.remove(managed);
Và đây là sơ đồ để củng cố nó:
JPA : Знакомство с технологией - 11
JPA : Знакомство с технологией - 12

Lập bản đồ

Trong JPA chúng ta có thể mô tả mối quan hệ của các thực thể với nhau. Hãy nhớ rằng chúng ta đã xem xét mối quan hệ của các thực thể với nhau khi xử lý mô hình miền của mình. Sau đó, chúng tôi sử dụng tài nguyên quickdatabasediagrams.com :
JPA : Знакомство с технологией - 13
Việc thiết lập kết nối giữa các thực thể được gọi là ánh xạ hoặc liên kết (Assocation Mappings). Các loại liên kết có thể được thiết lập bằng JPA được trình bày dưới đây:
JPA : Знакомство с технологией - 14
Hãy nhìn vào một thực thể Topicmô tả một chủ đề. Chúng ta có thể nói gì về thái độ Topicđối với Category? Nhiều người Topicsẽ thuộc về một loại. Vì vậy, chúng ta cần một hiệp hội ManyToOne. Hãy thể hiện mối quan hệ này trong JPA:
@ManyToOne
@JoinColumn(name = "category_id")
private Category category;
Để nhớ nên đặt chú thích nào, bạn có thể nhớ rằng phần cuối cùng chịu trách nhiệm về trường phía trên mà chú thích được chỉ định. ToOne- trường hợp cụ thể ToMany- bộ sưu tập. Bây giờ kết nối của chúng tôi là một chiều. Hãy biến nó thành một cuộc giao tiếp hai chiều. Hãy bổ sung thêm Categorykiến ​​thức về tất cả những người Topicthuộc danh mục này. Nó phải kết thúc bằng ToMany, vì chúng ta có một danh sách Topic. Đó là thái độ “Đối với nhiều” chủ đề. Câu hỏi vẫn còn - OneToManyhoặc ManyToMany:
JPA : Знакомство с технологией - 15
Bạn có thể đọc câu trả lời hay về cùng chủ đề tại đây: " Giải thích mối quan hệ ORM oneToMany, manyToMany giống như tôi năm ". Nếu một danh mục có mối liên hệ với ToManycác chủ đề thì mỗi chủ đề này chỉ có thể có một danh mục, nếu Onekhông thì Many. Vì vậy, Categorydanh sách tất cả các chủ đề sẽ trông như thế này:
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "topic_id")
private Set<Topic> topics = new HashSet<>();
Và về cơ bản đừng quên Categoryviết một getter để có danh sách tất cả các chủ đề:
public Set<Topic> getTopics() {
	return this.topics;
}
Mối quan hệ hai chiều là điều rất khó theo dõi một cách tự động. Vì vậy, JPA chuyển trách nhiệm này cho nhà phát triển. Điều này có ý nghĩa đối với chúng tôi là khi chúng tôi thiết lập Topicmối quan hệ thực thể với Category, chúng tôi phải tự đảm bảo tính nhất quán của dữ liệu. Điều này được thực hiện đơn giản:
public void setCategory(Category category) {
	category.getTopics().add(this);
	this.category = category;
}
Hãy viết một bài kiểm tra đơn giản để kiểm tra:
@Test
public void shouldPersistCategoryAndTopics() {
	Category cat = new Category();
	cat.setTitle("test");
	Topic topic = new Topic();
	topic.setTitle("topic");
	topic.setCategory(cat);
 	em.persist(cat);
}
Lập bản đồ là một chủ đề hoàn toàn riêng biệt. Mục đích của việc xem xét này là để hiểu các phương tiện đạt được điều này. Bạn có thể đọc thêm về lập bản đồ ở đây:
JPA : Знакомство с технологией - 16

JPQL

JPA giới thiệu một công cụ thú vị - truy vấn bằng Ngôn ngữ truy vấn liên tục Java. Ngôn ngữ này tương tự như SQL nhưng sử dụng mô hình đối tượng Java thay vì bảng SQL. Hãy xem một ví dụ:
@Test
public void shouldPerformQuery() {
	Category cat = new Category();
	cat.setTitle("query");
	em.persist(cat);
	Query query = em.createQuery("SELECT c from Category c WHERE c.title = 'query'");
 	assertNotNull(query.getSingleResult());
}
Như chúng ta có thể thấy, trong truy vấn, chúng ta đã sử dụng tham chiếu đến một thực thể Categorychứ không phải bảng. Và cả trên lĩnh vực của thực thể này title. JPQL cung cấp nhiều tính năng hữu ích và xứng đáng có bài viết riêng. Thông tin chi tiết có thể được tìm thấy trong đánh giá:
JPA : Знакомство с технологией - 17

API tiêu chí

Và cuối cùng, tôi muốn đề cập đến API Tiêu chí. JPA giới thiệu một công cụ xây dựng truy vấn động. Ví dụ về việc sử dụng API tiêu chí:
@Test
public void shouldFindWithCriteriaAPI() {
	Category cat = new Category();
	em.persist(cat);
	CriteriaBuilder cb = em.getCriteriaBuilder();
	CriteriaQuery<Category> query = cb.createQuery(Category.class);
	Root<Category> c = query.from(Category.class);
	query.select(c);
	List<Category> resultList = em.createQuery(query).getResultList();
	assertEquals(1, resultList.size());
}
Ví dụ này tương đương với việc thực hiện yêu cầu " SELECT c FROM Category c". API tiêu chí là một công cụ mạnh mẽ. Bạn có thể đọc thêm về nó ở đây:

Phần kết luận

Như chúng ta có thể thấy, JPA cung cấp một số lượng lớn các tính năng và công cụ. Mỗi người trong số họ đòi hỏi kinh nghiệm và kiến ​​​​thức. Ngay cả trong khuôn khổ cuộc rà soát của JPA cũng không thể đề cập hết được, chưa nói đến việc lặn chi tiết. Nhưng tôi hy vọng rằng sau khi đọc nó, bạn sẽ hiểu rõ hơn ORM và JPA là gì, nó hoạt động như thế nào và có thể làm gì với nó. Chà, đối với một bữa ăn nhẹ, tôi cung cấp nhiều nguyên liệu khác nhau: #Viacheslav
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION