- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我目前正在开发一个用 Java 实现的中型、基于桌面的管理和配置工具,使用 JavaFx、google-guice 和 hibernate 来实现其 jpa。
到目前为止,我只是将一个 EntityManager
作为 @Singleton
注入(inject)。这意味着我让这个 EntityManager 从启动到关闭都是“打开”的。所有加载的实体在上下文中都是永久已知的,我对这种方法几乎没有任何问题。虽然我知道/相信这不是最好的解决方案(但很简单,而且我没有时间重新设计应用程序)。
现在应用程序得到扩展,我必须同时使用多个持久性单元。
我可以尝试让我当前的单例方法使用类似的东西:
@Inject
@PersistenceContext(name="JPA-Unit1")
@Singleton
private EntityManager em;
它从来没有感觉完美,但感觉“丑陋”。由于我在使用 guice 获取多个持久性上下文时遇到了严重的问题,因此我必须对这个主题进行大量研究。
我遇到了几个博客 SO 问题,要么提到 EntityManager 的实例应该只在需要时存在,要么提到一些扩展的持久性上下文。
由于我使用JavaFx,所以我使用*Property将数据直接绑定(bind)到 UI 的类。
简化的用户实体(基于属性的访问):
@Entity
@Table(name = "USERS")
@NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
public class User implements Serializable {
[...]
private final SimpleStringProperty loginProperty = new SimpleStringProperty();
public User() {
}
public String getLogin() {
return this.loginProperty.get();
}
public void setLogin(String login) {
this.loginProperty.set(login);
}
public SimpleStringProperty loginProperty() {
return this.loginProperty;
}
[...]
}
如果我开始在 UI 中编辑用户数据,它会直接在实体中更新:
this.login.textProperty().bindBidirectional(user.loginProperty());
不需要大量的“业务逻辑”。它全部通过(输入)验证来处理。如果所有输入都有效,我只需通过保存数据
userService.update(user);
UserService 的部分(确切地说:它的抽象父类(super class)):
public abstract class AbstractService<PK extends Serializable, Type> implements GenericService<PK, Type> {
protected Class<Type> clazz;
@PersistenceContext(name = "JPA-Unit1")
@Inject
protected Provider<EntityManager> emProvider;
public AbstractService(Class<Type> clazz) {
this.clazz = clazz;
}
@Transactional
@Override
public Type create(Type entity) {
this.emProvider.get().persist(entity);
return entity;
}
@Transactional
@Override
public Type update(Type entity) {
this.emProvider.get().persist(entity);
return entity;
}
}
如您所见:服务类非常简单。我什至可以删除所有这些“服务”类并直接在我的 UI Controller 中使用实体管理器。
在此服务中,您可以看到我编辑的用户之前通过其命名查询加载的“问题”并将其放入列表中。加载也是在 @Transactional 方法中完成的。但每次我调用 this.emProvider.get() 时,我都会得到一个带有空上下文的新实例。如果我想保存以前编辑的用户,我会遇到一个问题,即持久实际上执行插入(我假设因为它在上下文中未知[分离]),这会导致 PK 约束违规,或者如果我删除(null
)其 ID 属性,则会插入一个新的用户行。
我的实际问题是:1. 这种方法“OK”吗?如果是,我该如何处理这个“始终”新的持久性上下文?每次都调用包含并合并?
我应该摆脱我的服务类并直接在我的 UI Controller 中实现持久性操作吗?
我可以在用户 UI Controller 加载后执行 this.emProvider.get()
并在应用程序的整个生命周期中使用它吗?
完全不同的东西?
最佳答案
我的理解是您的应用程序使用 Guice Persist。
这个问题的答案取决于您的用例;但是,您绝对需要意识到一件事:
只要 EntityManager
打开,其底层持久性上下文就会跟踪每个持久性实体的每一个更改。
这意味着,如果您在应用程序期间保持实体管理器处于打开状态,则每当您调用例如User.setLogin()
,您刚刚所做的更改已经被视为持久的。现在,转到 update
方法,对已托管的实体调用 persist
没有任何效果;但是,由于您是从 @Transactional 方法调用它,Guice 会将调用包装在事务中,因此,一旦方法结束,所有更改都会被刷新到数据库中。
这意味着,如果您在应用中同时修改多个实体,然后对其中一个实体调用 AbstractService.update
,您实际上会同时保存您的应用对其他实体所做的所有更改,即使尚未显式调用 AbstractService.update
也是如此。
使用每个事务的实体管理器方法确实要安全得多。在事务之间,不会有开放的持久性上下文,因此所有实体都将分离,这将防止它们的任何更新意外刷新到数据库。
但是,出于同样的原因,您的 update
方法需要对要在数据库中更新的实体调用 em.merge
。合并基本上是告诉实体管理器“请将此实体放回到持久化上下文中,并使其具有所提供实体的确切状态”。调用persist
使它看起来好像是一个新实体,并且PK约束违规确实会随之而来。
关于java - 如何使用 "long living entities"或 "longer living persistence context"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44101043/
我找到了long int long和 int long long可以编译为变量类型。 long int long有什么区别吗, int long long , long long和 long long
我无法找出为什么“加密”函数仍然将“消息”读取为字符串,尽管我已经使用不同的方法将数据类型更改为字节。 错误消息是“Prince 类型中的方法 Encrypt(long, long, long, lo
这个问题在这里已经有了答案: Is "long long" = "long long int" = "long int long" = "int long long"? (4 个答案) 关闭 6 年
我正在从 Java 过渡到 C++,并且对 long 数据类型有一些疑问。在 Java 中,要保存大于 232 的整数,您只需编写 long x;。但是,在 C++ 中,long 似乎既是数据类型又是
clang-tidy 12.0.1 报告了一个相当奇怪的警告。在以下代码中: #include int main() { std::vector v1; const auto a =
我创建了一个 pair 和 long long int 的映射 - map,long long int >; 和一个交互器 - map, long long int >::iterator it1;
我想知道 unsigned long long 和 unsigned long long int 的主要区别。它们可以互换使用吗? 对于像 9223372036854775807 这样的大十进制数的计
我看到的大多数代码都使用缩写类型来声明变量,例如 long long x; // long long int x short y; // short int y 我浏览了 C++11 标准(第 3.9
common_type::type是 unsigned long因为关于积分提升后的操作数,标准说... [...] if the operand that has unsigned integer
long long int A = 3289168178315264; long long int B = 1470960727228416; double D = sqrt(5); long lon
这些新数据类型的目的是什么?我通常只使用“int”或“long”,但为什么会存在这些呢?它们带来了什么新功能或用途? 最佳答案 long int一直是long的全称,只是很少用而已。 long lon
我正在运行以下for循环 for(unsigned long long int i = N-1; i >= 0; i--){ cin>>L[i]; } 当程序到达这个代码段时,它停止响应。但是
最近问了一个关于递归导致这个问题的问题 注意-> count() 函数返回键 K 在 map 容器中出现的次数。如果键存在于容器中,则返回 1,因为映射仅包含唯一键。如果 map 容器中不存在键,则返
好的,所以我正在尝试实现客户端 - 服务器程序(套接字编程)。 我的客户发送一个嵌入字符串中的 long long int,如下所示: char copy[10]; sprintf(send_data
如果我有任务 Long c = a + b; 有没有一种简单的方法来检查 a + b 不大于/小于 Long.MAX_VALUE/Long.MIN_VALUE? 最佳答案 使用 Guava , 就这么
我需要制作一个 Comparator 来根据它的 long 类型的变量之一对我的对象列表进行排序。 public class ParticipantIndexComparator implements
假设我有这两种类型: typedef unsigned long long uint64; typedef signed long long sint64; 我有这些变量: uint64 a = ..
long long 和 long 有什么区别?而且它们都不适用于 12 位数字 (600851475143),我是不是忘记了什么? #include using namespace std; int
当结果将大于 C 中的 long long int 时,是否有可能对两个不同的 long long int 变量求和? 最佳答案 由于 OP 想要“在屏幕上打印结果”,因此将数字分成两部分:Most-
实际上我必须找到从源顶点到所有其他顶点的最短路径。为此,我获得了下面给出的代码模板。我想实现“Bellman–Ford algorithm”。 #include #include #include
我是一名优秀的程序员,十分优秀!