jpa的查询api

当您使用JPA时-有时-JPQL不能解决问题,您将不得不使用本机SQL。 从一开始,像Hibernate这样的ORM就为这些情况保留了开放的“后门”,并为Spring的JdbcTemplate , Apache DbUtils或jOOQ提供了类似的API,用于纯SQL 。 这很有用,因为您可以继续将ORM用作数据库交互的单个入口点。

但是,使用字符串连接编写复杂的动态SQL既繁琐又容易出错,并且是SQL注入漏洞的门户。 使用像jOOQ这样的类型安全的API会非常有用,但是您可能会发现仅在10-15个本机查询中就很难在同一应用程序中维护两个不同的连接,事务和会话模型。

但事实是:

您可以将jOOQ用于JPA本机查询!

确实如此! 有几种方法可以实现此目的。

提取元组(即Object [])

最简单的方法将不会利用JPA的任何高级功能,而只是为您获取JPA的本机Object[]形式的元组。 假设这个简单的实用方法:

public static List<Object[]> nativeQuery(EntityManager em, org.jooq.Query query
) {// Extract the SQL statement from the jOOQ query:Query result = em.createNativeQuery(query.getSQL());// Extract the bind values from the jOOQ query:List<Object> values = query.getBindValues();for (int i = 0; i < values.size(); i++) {result.setParameter(i + 1, values.get(i));}return result.getResultList();
}

使用API

这就是您以最简单的形式桥接这两个API所需要的,以通过EntityManager运行“复杂”查询:

List<Object[]> books =
nativeQuery(em, DSL.using(configuration).select(AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME, BOOK.TITLE).from(AUTHOR).join(BOOK).on(AUTHOR.ID.eq(BOOK.AUTHOR_ID)).orderBy(BOOK.ID));books.forEach((Object[] book) -> System.out.println(book[0] + " " + book[1] + " wrote " + book[2]));

同意的结果中没有很多类型安全性,因为我们只得到一个Object[] 。 我们期待着将来支持Scala或Ceylon之类的元组(甚至记录)类型的Java。

因此,更好的解决方案可能是以下方法:

获取实体

假设您具有以下非常简单的实体:

@Entity
@Table(name = "book")
public class Book {@Idpublic int id;@Column(name = "title")public String title;@ManyToOnepublic Author author;
}@Entity
@Table(name = "author")
public class Author {@Idpublic int id;@Column(name = "first_name")public String firstName;@Column(name = "last_name")public String lastName;@OneToMany(mappedBy = "author")public Set<Book> books;
}

并假设,我们将添加一个附加的实用程序方法,该方法还将Class引用传递给EntityManager

public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query,Class<E> type
) {// Extract the SQL statement from the jOOQ query:Query result = em.createNativeQuery(query.getSQL(), type);// Extract the bind values from the jOOQ query:List<Object> values = query.getBindValues();for (int i = 0; i < values.size(); i++) {result.setParameter(i + 1, values.get(i));}// There's an unsafe cast here, but we can be sure// that we'll get the right type from JPAreturn result.getResultList();
}

使用API

现在这相当灵活,只需将jOOQ查询放入该API并从中获取JPA实体-两者兼有,因为您可以轻松地从获取的实体中添加/删除嵌套集合,就好像您是通过JPQL来获取它们一样:

List<Author> authors =
nativeQuery(em,DSL.using(configuration).select().from(AUTHOR).orderBy(AUTHOR.ID)
, Author.class); // This is our entity class hereauthors.forEach(author -> {System.out.println(author.firstName + " " + author.lastName + " wrote");books.forEach(book -> {System.out.println("  " + book.title);// Manipulate the entities here. Your// changes will be persistent!});
});

获取实体结果

如果您比较敢于冒险并且对注释有一种奇怪的喜好 ,或者只想在休假前给同事开个玩笑,还可以使用JPA的javax.persistence.SqlResultSetMapping 。 想象以下映射声明:

@SqlResultSetMapping(name = "bookmapping",entities = {@EntityResult(entityClass = Book.class,fields = {@FieldResult(name = "id", column = "b_id"),@FieldResult(name = "title", column = "b_title"),@FieldResult(name = "author", column = "b_author_id")}),@EntityResult(entityClass = Author.class,fields = {@FieldResult(name = "id", column = "a_id"),@FieldResult(name = "firstName", column = "a_first_name"),@FieldResult(name = "lastName", column = "a_last_name")})}
)

本质上,以上声明将数据库列( @SqlResultSetMapping -> entities -> @EntityResult -> fields -> @FieldResult -> column )映射到实体及其对应的属性。 使用这项强大的技术,您可以从任何类型SQL查询结果中生成实体结果。

同样,我们将创建一个小的实用工具方法:

public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query,String resultSetMapping
) {// Extract the SQL statement from the jOOQ query:Query result = em.createNativeQuery(query.getSQL(), resultSetMapping);// Extract the bind values from the jOOQ query:List<Object> values = query.getBindValues();for (int i = 0; i < values.size(); i++) {result.setParameter(i + 1, values.get(i));}// This implicit cast is a lie, but let's risk itreturn result.getResultList();
}

请注意, 上面的API使用了anti-pattern ,在这种情况下可以使用,因为JPA首先不是类型安全的API。

使用API

现在,再次,您可以通过上述API将类型安全的jOOQ查询传递给EntityManager ,并传递SqlResultSetMapping的名称,如下SqlResultSetMapping

List<Object[]> result =
nativeQuery(em,DSL.using(configuration.select(AUTHOR.ID.as("a_id"),AUTHOR.FIRST_NAME.as("a_first_name"),AUTHOR.LAST_NAME.as("a_last_name"),BOOK.ID.as("b_id"),BOOK.AUTHOR_ID.as("b_author_id"),BOOK.TITLE.as("b_title")).from(AUTHOR).join(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)).orderBy(BOOK.ID)), "bookmapping" // The name of the SqlResultSetMapping
);result.forEach((Object[] entities) -> {JPAAuthor author = (JPAAuthor) entities[1];JPABook book = (JPABook) entities[0];System.out.println(author.firstName + " " + author.lastName + " wrote " + book.title);
});

在这种情况下,结果仍然是Object[] ,但是这一次, Object[]并不表示具有单独列的元组,而是表示由SqlResultSetMapping注释声明的实体。

这种方法很吸引人,当您需要从查询中映射任意结果但仍需要托管实体时,可能会用到它。 如果您想了解更多信息,我们只能推荐Thorben Janssen关于这些高级JPA功能的有趣博客系列:

  • 结果集映射:基础
  • 结果集映射:复杂映射
  • 结果集映射:构造函数结果映射
  • 结果集映射:Hibernate特定功能

结论

在ORM和SQL之间(特别是在Hibernate和jOOQ之间)进行选择并不总是那么容易。

  • 当涉及到应用对象图持久性时,即当您有很多复杂的CRUD(涉及复杂的锁定和事务策略)时,ORM会闪耀。
  • 当运行批量SQL(用于读取和写入操作),运行分析,报告时,SQL大放异彩。

当您“幸运”时(例如,工作很简单),您的应用程序仅位于安全栅的一侧,您可以在ORM和SQL之间进行选择。 当您“幸运”时(例如– ooooh,这是一个有趣的问题),您将不得不同时使用两者。 ( 另请参阅Mike Hadlow关于该主题的有趣文章 )

这里的信息是:可以! 使用JPA的本机查询API,您可以利用RDBMS的全部功能运行复杂的查询,并且仍然可以将结果映射到JPA实体。 您不限于使用JPQL。

边注

尽管过去我们一直在批评JPA的某些方面(有关详细信息,请阅读JPA 2.1如何成为新的EJB 2.0 ),但我们的批评主要集中在JPA对注释的滥用上。 当使用jOOQ之类的类型安全API时,可以轻松地向编译器提供所有必需的类型信息以构造结果。 我们坚信,将来的JPA版本将更积极地使用Java的类型系统,从而可以更流畅地集成SQ​​L,JPQL和实体持久性。

翻译自: https://www.javacodegeeks.com/2015/05/type-safe-queries-for-jpas-native-query-api.html

jpa的查询api

jpa的查询api_为JPA的本机查询API键入安全查询相关推荐

  1. 为JPA的本机查询API键入安全查询

    当您使用JPA时-有时-JPQL无法解决问题,您将不得不使用本机SQL. 从一开始,像Hibernate这样的ORM就为这些情况保留了一个开放的"后门",并为Spring的Jdbc ...

  2. jpa分页查询_spring data jpa 居然提供了这么多查询方式!

    spring data jpa提供了多种查询方式,如下: 方法名称查询 继承Repository接口 测试代码 方法名称中支持的关键字(官方文档提供) 使用JPA命名查询 在User实体中定义jpql ...

  3. 在每个运行中运行多个查询_Spring Data JPA的运行原理及几种查询方式

    Spring Data JPA的运行原理: @PersistenceContext(name="entityManagerFactory") private EntityManag ...

  4. jpa jql 时间范围查询_SpringBoot整合JPA案例

    本节主要学习SpringBoot + JPA(底层使用Hibernate实现)集成案例. 1.JPA概述 1.1 JPA简介 JPA是Java Persistence API的简称,中文名Java持久 ...

  5. vue+node多条件查询 分页_SpringBoot+JPA框架分页、带条件查询等操作

    前言 最近研究JPA框架,初学SpringBoot时也简单学过,但是不是很深入,所以这次主要是说一些进阶且常用.实用的操作! 前置准备 创建两张表或者让JPA自动建表,任意选择!学生表 package ...

  6. JPA 2.0 中的动态类型安全查询(如何通过 Criteria API 构建动态查询并减少运行时失败)...

    简介:  如果编译器能够对查询执行语法正确性检查,那么对于 Java 对象而言该查询就是类型安全的.Java™Persistence API (JPA) 的 2.0 版本引入了 Criteria AP ...

  7. JPA教程:JPA概述、JPA实体生命周期、JPA实体映射关系、JPA查询语言

    JPA定义了Java ORM及实体操作API的标准.本文摘录了JPA的一些关键信息以备查阅. 如果有hibernate的基础,通过本文也可以快速掌握JPA的基本概念及使用. 1 JPA概述 JPA(J ...

  8. JPA休眠替代方案。 如果JPA或Hibernate对于我的项目而言不够好,该怎么办?

    你好!你好吗? 今天,我们将讨论不建议使用JPA / Hibernate的情况. 在JPA领域之外,我们还有哪些选择? 我们将谈论的是: JPA /休眠问题 解决一些JPA /休眠问题的方法 选择此处 ...

  9. ORM框架之Spring Data JPA(二)spring data jpa方式的基础增删改查

    上一篇主要在介绍hibernate实现jpa规范,如何实现数据增删改查,这一篇将会着重spring data jpa 一.Spring Data JPA 1.1 Spring Data JPA介绍: ...

最新文章

  1. 第十三篇:上下文无关语法 Context-Free Grammar
  2. c语言从键盘输入千米数,第二章 C语言编程基础.ppt
  3. 计算两个日期之间有多少天多少小时多少分钟
  4. 数据中心变得更加灵活和可靠的五种方式
  5. 黑马java代码04-05.docx
  6. (34)css光标属性cursor
  7. sourcetree提示无效路径_关于今明可转债申购的温馨提示
  8. 一次网站登录慢故障排查
  9. 算法: 最大矩形面积85. Maximal Rectangle
  10. 某中学校校园网络方案设计(课程设计)
  11. iOS 10越狱设备终于有越狱移除工具了!
  12. linux cpu使用率 理解,深入理解Linux的CPU使用率
  13. Si512 支持 NFC 协议超低功耗检卡能非接触式读卡芯片
  14. SparkRDD优化(二)之SparkRDD共享变量(广播变量,累加器)
  15. 收藏 | 堪称神器的42款Chrome插件
  16. 算法证明题 8.9 HITTING SET
  17. 招银网络2018笔试分享
  18. JS--页面加载完毕后执行
  19. warning: TCG doesn‘t support requested feature: CPUID.01H:ECX.vmx [bit 5]Could not initialize SDL
  20. chrony配置外部时钟源后stratum=16

热门文章

  1. CF1054D-Changing Array【贪心】
  2. nssl1454-最短路【并查集,贪心】
  3. POJ1006-Biorhythms【中国剩余定理】
  4. nssl1322,jzoj(初中)2109-清兵线【dp】
  5. 亿些模板【字符串+其他】
  6. jzoj3914-人品问题【树形dp】
  7. P1315,jzoj3029-观光公交【费用流】
  8. ssl2342-打击犯罪【并查集】
  9. 2021牛客暑期多校训练营2 B-Cannon(组合+推式子)
  10. 【网络流】人员雇佣(luogu 1791)