POJO
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
只要您的应用程序不是真正的分层,或者只要您仍然在 DAO 层中编写代码,以记录形式获取数据是可以的。但是,如果您有一个更高级的应用程序架构,您可能不希望 jOOQ 工件泄漏到其他层中。您可以选择编写 POJO(Plain Old Java Objects)作为您的主要 DTO(数据传输对象),而不依赖于 jOOQ 的 org.jooq.Record
类型,这些类型甚至可能持有对 Configuration 的引用,从而持有 JDBC java.sql.Connection
。像 Hibernate/JPA 一样,jOOQ 允许您使用 POJO 进行操作。与 Hibernate/JPA 不同,jOOQ 不会“附加”这些 POJO 或使用任何魔法创建代理。
如果您正在使用 jOOQ 的 代码生成器,您可以配置它来为您生成 POJO,但您不需要使用这些生成的 POJO。您可以使用自己的。请参阅手册中关于带有自定义 RecordMapper 的 POJO部分,了解如何修改 jOOQ 的标准 POJO 映射行为。
虽然 POJO 没有与 jOOQ API 的连接,但它们也没有脏标志和其他有用的基于记录的功能的概念。它们是哑 POJO。虽然有些人喜欢“干净”的关注点分离,但这并不总是必要的。在 UI 层中,大部分时间使用 jOOQ 的 org.jooq.UpdatableRecord
也是完全可以的!
equals() 和 hashCode()
生成的 POJO 默认提供完全基于值的 equals()
和 hashCode()
语义,因为 jOOQ 以类似于 SQL 的方式操作数据,当行是“NOT DISTINCT”时,它们是“相等”的。自定义构建的 POJO 或 DTO 可以对 equals()
和 hashCode()
的实现有不同的看法,包括 POJO 更类似于 JPA 实体的方法(如果存在主键:仅使用该主键进行比较,如果不存在,则所有实例都不同)。 jOOQ 不会强制采用一种方法来替代另一种方法。
使用 JPA 注解的 POJO
jOOQ 尝试在您的 POJO 类型上查找 JPA 注解。如果找到任何注解,它们将用作映射元信息的主要来源。 jOOQ 仅使用和理解 jakarta.persistence.Column
注解。一个例子
// A JPA-annotated POJO class public class MyBook { @Column(name = "ID") public int myId; @Column(name = "TITLE") public String myTitle; } // The various "into()" methods allow for fetching records into your custom POJOs: MyBook myBook = create.select().from(BOOK).fetchAny().into(MyBook.class); List<MyBook> myBooks = create.select().from(BOOK).fetch().into(MyBook.class); List<MyBook> myBooks = create.select().from(BOOK).fetchInto(MyBook.class);
与任何其他 JPA 实现一样,您可以将 jakarta.persistence.Column
注解放在任何类成员上,包括属性、setter 和 getter。有关更多详细信息,请参阅 Record.into()
Javadoc。
使用简单的 POJO
如果 jOOQ 没有找到任何 JPA 注解,则列将映射到“最佳匹配”构造函数、属性或 setter。一个例子说明了这一点
// A "mutable" POJO class public class MyBook1 { public int id; public String title; } // The various "into()" methods allow for fetching records into your custom POJOs: MyBook1 myBook = create.select().from(BOOK).fetchAny().into(MyBook1.class); List<MyBook1> myBooks = create.select().from(BOOK).fetch().into(MyBook1.class); List<MyBook1> myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);
有关更多详细信息,请参阅 Record.into()
Javadoc。
使用“不可变”的 POJO
如果 jOOQ 没有找到任何默认构造函数,则列将映射到“最佳匹配”构造函数。这允许使用 jOOQ 的“不可变” POJO。一个例子说明了这一点
// An "immutable" POJO class public class MyBook2 { public final int id; public final String title; public MyBook2(int id, String title) { this.id = id; this.title = title; } } // With "immutable" POJO classes, there must be an exact match between projected fields and available constructors: MyBook2 myBook = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchAny().into(MyBook2.class); List<MyBook2> myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook2.class); List<MyBook2> myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook2.class); // An "immutable" POJO class with a java.beans.ConstructorProperties annotation public class MyBook3 { public final String title; public final int id; @ConstructorProperties({ "title", "id" }) public MyBook3(String title, int id) { this.title = title; this.id = id; } } // With annotated "immutable" POJO classes, there doesn't need to be an exact match between fields and constructor arguments. // In the below cases, only BOOK.ID is really set onto the POJO, BOOK.TITLE remains null and BOOK.AUTHOR_ID is ignored MyBook3 myBook = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchAny().into(MyBook3.class); List<MyBook3> myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetch().into(MyBook3.class); List<MyBook3> myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchInto(MyBook3.class);
有关更多详细信息,请参阅 Record.into()
Javadoc。
使用可代理类型
jOOQ 还允许将数据提取到抽象类或接口中,或者换句话说,提取到“可代理”类型中。这意味着 jOOQ 将返回一个包装在 java.lang.reflect.Proxy
中的 java.util.HashMap
,该代理实现您的自定义类型。这里给出了一个例子
// A "proxyable" type public interface MyBook3 { int getId(); void setId(int id); String getTitle(); void setTitle(String title); } // The various "into()" methods allow for fetching records into your custom POJOs: MyBook3 myBook = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchAny().into(MyBook3.class); List<MyBook3> myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook3.class); List<MyBook3> myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook3.class);
有关更多详细信息,请参阅 Record.into()
Javadoc。
将 POJO 加载回记录以存储它们
以上示例显示了如何将数据提取到您自己的自定义 POJO / DTO 中。当您修改了 POJO 中包含的数据时,您可能希望将这些修改存储回数据库。这里给出了一个例子
// A "mutable" POJO class public class MyBook { public int id; public String title; } // Create a new POJO instance MyBook myBook = new MyBook(); myBook.id = 10; myBook.title = "Animal Farm"; // Load a jOOQ-generated BookRecord from your POJO BookRecord book = create.newRecord(BOOK, myBook); // Insert it (implicitly) book.store(); // Insert it (explicitly) create.executeInsert(book); // or update it (ID = 10) create.executeUpdate(book);
注意:由于您手动设置了 ID = 10,jOOQ 的 store() 方法将假定您要插入新记录。 有关此方面的更多详细信息,请参见手册中有关使用 UpdatableRecords 进行 CRUD的部分。
与 DAO 交互
如果您正在使用 jOOQ 的 代码生成器,则可以将其配置为为您生成 DAO。 这些 DAO 在生成的 POJO上运行。 这里给出了使用此类 DAO 的一个示例
// Initialise a Configuration Configuration configuration = new DefaultConfiguration().set(connection).set(SQLDialect.ORACLE); // Initialise the DAO with the Configuration BookDao bookDao = new BookDao(configuration); // Start using the DAO Book book = bookDao.findById(5); // Modify and update the POJO book.setTitle("1984"); book.setPublishedIn(1948); bookDao.update(book); // Delete it again bookDao.delete(book);
虽然这些org.jooq.DAO
类型对于琐碎的操作看起来很有用,但随着您的 SQL 交互变得越来越复杂,它们很快就会变得不那么有趣了。就像 POJO 本身一样,DAO 非常简单。可以直接使用org.jooq.UpdatableRecord
或 SQL 语句!
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!