当前位置:网站首页>Use jOOQ to write vendor-agnostic SQL with JPA's native query or @Formula.
Use jOOQ to write vendor-agnostic SQL with JPA's native query or @Formula.
2022-07-31 11:16:00 【DebugUsery】
If you are traditionalJPAOccasionally applications using native queries orHibernate@Formula
或Spring Data@Query
注释,Embedded the vendor specific localSQL,你可以使用jOOQ的 The connection and parse data sourceBetween the dialect translation,Without having to go all out to usejOOQ--Although I think once you seejOOQ能为你做什么,这就是不可避免的.
现在,Let's design a to the table.
CREATE TABLE author (
id INT NOT NULL,
first_name TEXT,
last_name TEXT NOT NULL,
CONSTRAINT pk_author PRIMARY KEY (id)
);
复制代码
现在,You may want to use in the tableJPA的 [EntityManager.createNativeQuery()](https://jakarta.ee/specifications/persistence/3.0/apidocs/jakarta.persistence/jakarta/persistence/entitymanager#createNativeQuery(java.lang.String,java.lang.Class))
,Map it to the entity.你可以使用jOOQ的DSL API,But if you are not prepared to move tojOOQ,Or do you want to use byDBAProvide the actualSQL,而不是jOOQ的DSL.
所以,在MariaDB中,You may want to write something like that.
List<Author> result =
em.createNativeQuery(""" select a.id, nvl(a.first_name, 'N/A') as first_name, a.last_name from t_author as a order by a.id """, Author.class)
.getResultList();
复制代码
Which one of the defined entity is this.
@Entity
@Table(name = "author")
public class Author {
@Id
public int id;
@Column(name = "first_name")
public String firstName;
@Column(name = "last_name")
public String lastName;
// Constructors, getters, setters, equals, hashCode, etc
}
复制代码
The above methods run very well,并且在MariaDBOf all the author,它实现了对Oracle的 [NVL()](https://mariadb.com/docs/reference/mdb/functions/NVL/)
函数的支持.但是Oracle本身呢?查询在Oracle上失败了,因为.
ORA-00933:SQLWe do not have the right to end command
这是因为在Oracle中,你不能使用AS
Keyword to don't watch,Only don't finished.当然,你可以去掉这个,但是,NVL()
呢?You want it inMySQL和SQL ServerWork on,But they will complain about.
MySQL
SQL错误[1305] [42000].FUNCTION test.nvl不存在
SQL服务器
SQL Error [195] [S0010]: 'nvl' Is not a recognized built-in function name.
现在,你有这些选择.
- 使用jOOQTo generate for youSQL字符串,使用DSL
- 使用JPQLRather than native queries(But to a large number of rewriting,因为JPQL比SQLThe function of much less).
- 试试你的运气,Manually write the actual supplier has nothing to doSQL.
- 或者...
jOOQThe resolution of connection
你可以使用jOOQThe resolution of connection,It as your actual connection agent,在JDBCLevel to intercept eachSQL语句,To translate it into target language.
It's like your existingJDBCConnection
或DataSource
Packaged in the following as simple.
DataSource originalDataSource = ...
DataSource parsingDataSource = DSL
.using(originalDataSource, dialect)
.parsingDataSource();
复制代码
就是这样!我的意思是,你可以在dialect
After passing some additional configurationSettings
,But this is the simplest.新的DataSource
,Now you can run on all of these dialects of youSQL查询,例如,你可能会在你的DEBUG
Log in to see this.
在MySQL上.
-- org.hibernate.SQL
select a.id, nvl(a.first_name, 'N/A') as first_name, a.last_name
from t_author as a
order by a.id
-- org.jooq.impl.ParsingConnection Translating from:
select a.id, nvl(a.first_name, 'N/A') as first_name, a.last_name
from t_author as a
order by a.id
-- org.jooq.impl.ParsingConnection Translation cache miss:
select a.id, nvl(a.first_name, 'N/A') as first_name, a.last_name
from t_author as a
order by a.id
-- org.jooq.impl.ParsingConnection Translating to:
select a.id, ifnull(a.first_name, 'N/A') as first_name, a.last_name
from t_author as a
order by a.id
复制代码
在SQL Server上.
-- org.hibernate.SQL
select a.id, nvl(a.first_name, 'N/A') as first_name, a.last_name
from t_author as a
order by a.id
-- org.jooq.impl.ParsingConnection Translating from:
select a.id, nvl(a.first_name, 'N/A') as first_name, a.last_name
from t_author as a
order by a.id
-- org.jooq.impl.ParsingConnection Translation cache miss:
select a.id, nvl(a.first_name, 'N/A') as first_name, a.last_name
from t_author as a
order by a.id
-- org.jooq.impl.ParsingConnection] Translating to:
select a.id, coalesce(a.first_name, 'N/A') first_name, a.last_name
from author a
order by a.id
复制代码
Hibernate被jOOQ欺骗了!NVL
The function of translated intoMySQL的 [IFNULL](https://dev.mysql.com/doc/refman/8.0/en/flow-control-functions.html#function_ifnull)
或SQL Server [COALESCE](https://docs.microsoft.com/en-us/sql/t-sql/language-elements/coalesce-transact-sql?view=sql-server-ver15)
,并且从SQL ServerIn the query to deleteAS
关键字.这些只是简单的例子,你的实际SQLCould be much more complex.On the Internet to play the feature set,在这里.
另外, [Settings.cacheParsingConnectionLRUCacheSize](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/conf/Settings.html#cacheParsingConnectionLRUCacheSize)
标志,默认为8192,We can ensure that the same query translation would not have been to,所以你不会在jOOQThe parser spend too much time.
@Formula也是,Is not only a local query
在Hibernate中,When you want to project the additional value,A quick victory,类似于SQL自己的计算列,在许多SQLDialects are,这就是@Formula
注释,It can be added to any entity in the,就像这样.Suppose you have the extra column.
ALTER TABLE author ADD year_of_birth INT;
复制代码
We may have the following revised entity.
@Entity
@Table(name = "author")
public class Author {
@Id
public int id;
@Column(name = "first_name")
public String firstName;
@Column(name = "last_name")
public String lastName;
@Column(name = "year_of_birth")
public Integer yearOfBirth;
@Formula("year_of_birth between 1981 and 1996")
public Boolean millenial;
// Constructors, getters, setters, equals, hashCode, etc
}
复制代码
但不幸的是,There are still so manyRDBMSIn fact don't support Boolean type,而且@Formula
Annotations are purely static,Do not allow the specific vendor's cover.If we want to manually override theSQL查询,To ensure that there is aSQL-92的、Has nothing to do with the manufacturer's localSQLFragments of all the dialects can be use?
Or we just insert againjOOQThe resolution of connection?Let's try using the latter.
Author author = em.find(Author.class, 1);
复制代码
MySQLThe logs contain.
-- org.hibernate.SQL
select
jpaauthorw0_.id as id1_4_0_,
jpaauthorw0_.first_name as first_na2_4_0_,
jpaauthorw0_.last_name as last_nam3_4_0_,
jpaauthorw0_.year_of_birth between 1981 and 1996 as formula1_0_
from author jpaauthorw0_
where jpaauthorw0_.id=?
-- org.jooq.impl.ParsingConnection Translating from: [...]
-- org.jooq.impl.ParsingConnection Translation cache miss: [...]
-- org.jooq.impl.ParsingConnection Translating to:
select
jpaauthorw0_.id as id1_4_0_,
jpaauthorw0_.first_name as first_na2_4_0_,
jpaauthorw0_.last_name as last_nam3_4_0_,
jpaauthorw0_.year_of_birth between 1981 and 1996 as formula1_0_
from author as jpaauthorw0_
where jpaauthorw0_.id = ?
复制代码
正如你所看到的,jOOQ重新添加了AS
Keyword to aliasMySQL,Because we like clear alias,Also because it is aMySQL的默认值.Settings.renderOptionalAsKeywordForTableAliases
而SQL ServerThe logs contain.
-- org.hibernate.SQL
select
jpaauthorw0_.id as id1_4_0_,
jpaauthorw0_.first_name as first_na2_4_0_,
jpaauthorw0_.last_name as last_nam3_4_0_,
jpaauthorw0_.year_of_birth between 1981 and 1996 as formula1_0_
from author jpaauthorw0_
where jpaauthorw0_.id=?
-- org.jooq.impl.ParsingConnection Translating from: [...]
-- org.jooq.impl.ParsingConnection Translation cache miss: [...]
-- org.jooq.impl.ParsingConnection Translating to:
select
jpaauthorw0_.id id1_4_0_,
jpaauthorw0_.first_name first_na2_4_0_,
jpaauthorw0_.last_name last_nam3_4_0_,
case
when jpaauthorw0_.year_of_birth between 1981 and 1996
then 1
when not (jpaauthorw0_.year_of_birth between 1981 and 1996)
then 0
end formula1_0_
from author jpaauthorw0_
where jpaauthorw0_.id = ?
复制代码
一个NULL
-safeBOOLEAN
类型的模拟(因为如果YEAR_OF_BIRTH
是NULL
(即UNKNOWN
),那么MILLENIAL
也必须是NULL
,即UNKNOWN
).
Spring Data @Query注解
在JPAIntegration of localSQL的另一种情况是Spring Data JPA的 [@Query](https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query)
注解,特别是当与@Query(nativeQuery = true)
.就像Hibernate的@Formula
,This annotation is static at compile time,There is no way to cover the value of the local query at runtime,Maybe it's just in each dialect points was carried out on the repository type.
But why go through the trouble.Always the same thing.只要用jOOQThe connection or parse the data source to repairDataSource
,就可以了.
结论
即使你不使用jOOQ的DSL API,You can also in your existing based onJDBC、R2DBC、JPA、MyBatisApplications such as in a variety of ways fromjOOQ中获利,Method is the hookjOOQ解析连接,And your vendor specific input dialect translation into any number of dialects can be configured to output.
如果jOOQThe parser can't handle a feature,你有可能使用ParseListener
SPI来解决这个限制,例如,When you want to support a hypothesis ofLOGICAL_XOR
谓词时(MySQL原生支持).
Query query = configuration
.derive(ParseListener.onParseCondition(ctx -> {
if (ctx.parseFunctionNameIf("LOGICAL_XOR")) {
ctx.parse('(');
Condition c1 = ctx.parseCondition();
ctx.parse(',');
Condition c2 = ctx.parseCondition();
ctx.parse(')');
return CustomCondition.of(c -> {
switch (c.family()) {
case MARIADB:
case MYSQL:
c.visit(condition("{0} xor {1}", c1, c2));
break;
default:
c.visit(c1.andNot(c2).or(c2.andNot(c1)));
break;
});
}
// Let the parser take over if we don't know the token
return null;
})
.dsl()
.parser()
.parseQuery(
"select * from t where logical_xor(t.a = 1, t.b = 2)"
);
System.out.println(DSL.using(SQLDialect.MYSQL).render(query));
System.out.println(DSL.using(SQLDialect.ORACLE).render(query));
复制代码
The program will print out.
-- MYSQL:
select *
from t
where (t.a = 1 xor t.b = 2);
-- ORACLE:
select *
from t
where (t.a = 1 and not (t.b = 2)) or (t.b = 2 and not (t.a = 1));
复制代码
因此,无论是否使用jOOQ的DSL,都可以通过使用jOOQWill you supply application specificSQL从一个RDBMS迁移到另一个RDBMS,Or in an application to support multipleRDBMSProduct and profit.
题外话.查询转换
This is not the subject of this post,But once you makejOOQAnalyses the each of youSQL语句,你也可以用jOOQ来转换这些SQL,And tampering with expression trees,For example, by implementing the client row-level security.这种可能性是无穷无尽的.
边栏推荐
- windows平台下的mysql启动等基本操作
- 实现弹框组件
- 初始JDBC 编程
- St. Regis Takeaway Project: File Upload and Download
- 准确率(Accuracy)、精度(Precision)、召回率(Recall)和 mAP 的图解
- KVM virtualization job
- Summary of several defragmentation schemes for MySQL (to solve the problem of not releasing space after deleting a large amount of data)
- 一、excel转pdf格式jacob.jar
- Single sign-on principle and implementation
- MySQL row-level locks (row locks, adjacent key locks, gap locks)
猜你喜欢
随机推荐
三层架构service、dao、controller层
A Method for Ensuring Data Consistency of Multi-Party Subsystems
AtCoder—E - Σ[k=0..10^100]floor(X/10^k
How SQL intercepts specified characters from strings (three functions of LEFT, MID, RIGHT)
[Virtualization Ecological Platform] Platform Architecture Diagram & Ideas and Implementation Details
使用内存映射加快PyTorch数据集的读取
瑞吉外卖项目:新增菜品与菜品分页查询
Implement the popup component
内网渗透学习(四)域横向移动——SMB和WMI服务利用
ApiPost 真香真强大,是时候丢掉 Postman、Swagger 了
502 bad gateway原因、解决方法
「MySQL」- 基础增删改查
KVM虚拟化作业
Usage of exists in sql
力扣shell刷题
分布式事务——分布式事务简介、分布式事务框架 Seata(AT模式、Tcc模式、Tcc Vs AT)、分布式事务—MQ
【虚拟化生态平台】平台架构图&思路和实现细节
Experience innovation and iteration through the development of a lucky draw applet
What does "chmod 777-R filename" mean?
WSL2安装.NET 6