mas*_*san 51 java database orm jpa
我一直在阅读几篇文章是什么JPA (Java Persistent API)以及哪些供应商支持它(DataNucleus,JBoss Hibernate等)
我没有ORM(对象关系映射)的经验.
到目前为止我所做的是使用DTO和DAO编写自己的数据库类.到目前为止,我对我所拥有的内容感到高兴,但我想知道为什么人们使用JPA而不是包含SQL的Java文件.
对我来说,我觉得写DAO课程就像下面这样.
public class DAOUsers {
public void insertNewUser(DTO DtoUser) {
String query = "INSERT INTO users(username, address) " +
"VALUES(DtoUser.username , DtoUser.address)";
Executor.run(query);
}
}
Run Code Online (Sandbox Code Playgroud)
我已经了解到JPA使用JPQL,Java持久查询语言,它对实体对象而不是直接使用db表进行操作.
我的理解(纠正我,如果我错了)是这里的实体对象和我的DTO对象一样(有点像bean吗?)
但无论如何...... JPA真正有益于在我的文件中编写纯SQL吗?看起来像使用JPA所需的注释并使SQL不可读对我来说不是很有吸引力..
如果您需要更多说明,请告诉我,我是这个主题的新手,并希望听到一些意见.
Vin*_*lds 42
为什么使用JPA而不是直接在Java文件上编写SQL查询(即直接写入JDBC)?
某些项目要求工程师更多地关注对象模型,而不是用于访问数据存储的实际SQL查询.这个问题实际上可以解释为
为什么要使用ORM框架?
在不同的环境中可以有不同的答案.
大多数项目都可以从拥有域模型中受益,持久性是第二个问题.使用JPA(实现)或大多数其他ORM框架,可以将所有实体(即数据库中的表)建模为Java中的类.此外,还可以将行为嵌入到这些类中,从而实现行为丰富的域模型.此模型中的实体可以有多种用途,包括替换DTO以跨层传输数据的目的.
也就是说,有些地方的ORM框架可能不是直接适应问题的,特别是当数据模型已经建立时,或者正在使用遗留系统时,将数据库表映射到Java类是一项非常重要的工作.在某些情况下,如果需要绝对调整ORM框架生成的SQL,那么ORM框架通常是不合适的.
相关问题
Ste*_*n C 23
JPA在我的文件中编写纯SQL的真正好处是什么?
以下是一些好处:
JPA允许您避免在SQL的数据库特定方言中编写DDL.相反,您可以在XML中编写"映射",或使用Java注释.
JPA允许您避免在SQL的数据库特定方言中编写DML.
JPA允许您加载和保存Java对象和图形,而不需要任何DML语言.
当您确实需要执行查询时,JPQL允许您根据Java实体而不是(本机)SQL表和列来表达查询.
一般来说,JPA比JDBC + SQL +手写映射更简单,更清晰,劳动强度更低.数据模型越复杂,它就越有益.
但是,如果性能是最重要的考虑因素,JPA确实会通过在应用程序和数据库之间添加层来阻碍性能.如果您的应用程序要求您广泛手动优化本机数据库查询和模式以最大限度地提高性能,那么JPA可能不太合适.
如果你在同一个应用程序中更好地处理 Java,JDBC和SQL,那么JPA可能也不适合你,而不是让ORM处理凌乱的细节.(但如果你是,你可能是少数......)
Vla*_*cea 22
例如,这是插入一些记录的最常见方式:
int postCount = 100;
try (PreparedStatement postStatement = connection.prepareStatement("""
INSERT INTO post (
id,
title
)
VALUES (
?,
?
)
"""
)) {
for (int i = 1; i <= postCount; i++) {
int index = 0;
postStatement.setLong(
++index,
i
);
postStatement.setString(
++index,
String.format(
"High-Performance Java Persistence, review no. %1$d",
i
)
);
postStatement.executeUpdate();
}
} catch (SQLException e) {
fail(e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)
而且,当您意识到这表现不佳时,因为您忘记使用批处理,您必须更改之前的实现,如下所示:
int postCount = 100;
int batchSize = 50;
try (PreparedStatement postStatement = connection.prepareStatement("""
INSERT INTO post (
id,
title
)
VALUES (
?,
?
)
"""
)) {
for (int i = 1; i <= postCount; i++) {
if (i % batchSize == 0) {
postStatement.executeBatch();
}
int index = 0;
postStatement.setLong(
++index,
i
);
postStatement.setString(
++index,
String.format(
"High-Performance Java Persistence, review no. %1$d",
i
)
);
postStatement.addBatch();
}
postStatement.executeBatch();
} catch (SQLException e) {
fail(e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)
使用 JPA,一旦您映射了您的实体:
@Entity
@Table(name = "post")
public class Post {
@Id
private Long id;
private String title;
public Long getId() {
return id;
}
public Post setId(Long id) {
this.id = id;
return this;
}
public String getTitle() {
return title;
}
public Post setTitle(String title) {
this.title = title;
return this;
}
}
Run Code Online (Sandbox Code Playgroud)
并且,您设置以下 Hibernate 配置属性:
<property name="hibernate.jdbc.batch_size" value="50"/>
Run Code Online (Sandbox Code Playgroud)
这是插入这些post表记录的方法:
for (long i = 1; i <= postCount; i++) {
entityManager.persist(
new Post()
.setId(i)
.setTitle(
String.format(
"High-Performance Java Persistence, review no. %1$d",
i
)
)
);
}
Run Code Online (Sandbox Code Playgroud)
简单多了,对吧?
使用 JDBC,这是您执行 SQL 投影的方式:
int maxResults = 10;
List<Post> posts = new ArrayList<>();
try (PreparedStatement preparedStatement = connection.prepareStatement("""
SELECT
p.id AS id,
p.title AS title
FROM post p
ORDER BY p.id
LIMIT ?
"""
)) {
preparedStatement.setInt(1, maxResults);
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
int index = 0;
posts.add(
new Post()
.setId(resultSet.getLong(++index))
.setTitle(resultSet.getString(++index))
);
}
}
} catch (SQLException e) {
fail(e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)
这相当冗长,因为您必须将 转换为ResultSet您的应用程序正在使用的数据结构(例如,DTO、JSON Web 响应)。
使用JPA,您可以获取List的Post这样的记录:
int maxResults = 10;
List<Post> posts = entityManager.createQuery("""
select p
from post p
order by p.id
""", Post.class)
.setMaxResults(maxResults)
.getResultList();
Run Code Online (Sandbox Code Playgroud)
而且,不仅编写起来更简单,而且它适用于 Hibernate 支持的每个数据库,因为分页语法是根据底层数据库方言进行调整的。
hibernate.query.in_clause_parameter_padding.ResultSet为 JPA 实体或 DTO。使用 JPA 和 Hibernate 的缺点如下:
Java 生态系统最伟大的事情之一是大量高质量的框架。如果 JPA 和 Hibernate 不适合您的用例,您可以使用以下任何框架:
虽然 JPA 带来了许多优势,但如果 JPA 和 Hibernate 不能很好地满足您当前的应用程序需求,您还有许多其他高质量的替代品可供使用。因此,如今,除非您正在开发数据访问框架,否则您实际上并不需要使用普通的 JDBC。
Doc*_*val 16
虽然这是一个老问题,但我觉得它值得一个新的答案.我是JPA的后期使用者,我已经使用它几年了,虽然我有一些时间让我对于新应用程序的简单性感到印象深刻,但我已经变得毫无印象具有正确执行JPA所需的性能,复杂性和学习曲线.这个帖子的答案实际上强化了我的立场.
首先,@vineet建议"实体可以有多种用途"......我在生产中看到过这种情况,而且我会说ORM会鼓励它.凝聚力和单一的责任主体.根据我的经验,向数据库实体添加行为是一件麻烦事.我知道这是因为我已经做到了,并为此感到后悔.
其次,JPA的复杂性有一些简单的替代方案,它们能够使用具有RDBMS的类,而不会由于ORM尝试(不成功)解决的不匹配而导致的所有沉重(和性能问题).我们在具有超过1,000个表的应用程序中使用非JPA关系类映射工具已经十年了,我们根本看不到JPA是如何改进而不是更直接地访问数据库.JPA模糊了数据库的功能,同时将开销(以注释和JQL的形式)添加到类模型中...不应该以其他方式工作吗?
@water提出了许多在理论上属实但在现实中不切实际的事情.例如,已经三次切换后端数据库,我可以向读者保证,没有一些配置调整,你已经完成了.我建议,如果你花了很多时间维护你的持久层,你的数据库模型正在发展,你将在JPA中做相同或更多的工作.特别是当JPA中的非平凡查询需要使用JQL时!
几乎每个人都假装JPA开发人员不需要知道SQL.我在实践中看到的是,现在我们必须学习SQL 和 JQL.显然我们不需要做DDL - 但在任何非平凡的应用程序当然你需要知道DDL.Hibernate甚至不推荐使用自动DDL生成.显然我们不需要做DML,除非我们调用Native Query,这当然是非可移植的,破坏了缓存,并且与JDBC有着同样的问题......
最终,在一个结构合理的应用程序中,域模型独立于业务逻辑,JPA几乎没有为我发现的非常高的学习曲线提供功能 - 因为域模型实际上非常容易构建.我不会直接使用JDBC,但是像Apache DBUtils这样的东西在JDBC之上提供了一个简单的层,它将行映射到对象,并且通过一些努力可以提供JPA的大部分优点,没有任何隐藏,也没有任何开销.
我从JDBC 1.0开始使用各种库(以及JDBC之前的iODBC和ESQL)开发Java数据库应用程序,仅出于性能原因,我已经完成了JPA.但即使表现更好,学习曲线和不完整的抽象也会给我带来严重的停顿.JPA很复杂,并试图隐藏我认为开发人员真正需要关注的细节.作为一个例子,我们最近看到hibernate问题250删除命令到数据库时,一个就足够了.JPA本质上使这种错误变得容易.
我不是在倡导JDBC,我只是在提倡反对JPA.不能或不能在SQL中工作的开发人员可能不应该编写关系应用程序 - 除了我这样的开发人员,他们不能用矩阵代数来挽救我的生命,应该是编写3D游戏.那些使用SQL谋生的开发人员应该为扭曲的SQL而感到震惊,因为它会向服务器发送休眠状态,以避免一开始就不需要的往返.
众所周知,对象是我们生活中最重要的东西之一,在编程对象中很容易简化任何问题....如果对象可用,那么为什么我们使用整个东西而不是那个小部分事物意味着对象....
在持久性方面,==>不再需要JDBC API来进行结果集或数据处理.==>它有助于减少代码行,&&&&&&==>它将我们的应用程序从基础SQL数据库和sql方言中抽象出来.切换到其他SQL数据库需要在Hibernate配置文件中进行少量更改(一次写入/随处运行).