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 语句!
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!