gpt4 book ai didi

java - session 关闭后,如何禁用或禁止使用Hibernate代理?

转载 作者:太空宇宙 更新时间:2023-11-04 09:37:22 24 4
gpt4 key购买 nike

因此,我现在正在研究一个RESTful API,该API充当客户端和我们的数据库之间的一个层,我目前正在使用Hibernate for ORM,并且我已经尝试了几天了,以找到解决问题的方法,无处不在搜索有用。

我不能发布我正在使用的实际代码,因为它太大了,但请想象一下:

我有一个类Employee映射为如下所示的Hibernate实体

@Entity
public class Employee {
@Id
Integer id;
String name;
Double salary;
String department;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "company_id")
Company company;

// Getters/Setters ommitted


@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", salary=" + salary +
", department='" + department + '\'' +
", company=" + company +
'}';
}
}


另一个实体类 Company如下所示:

@Entity
public class Company {

@Id
Integer id;
String name;
String address;
@OneToMany(mappedBy = "company", fetch = FetchType.LAZY)
List<Employee> employees;

// Getters and setters ommited


@Override
public String toString() {
return "Company{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", employees=" + employees +
'}';
}
}


该数据库如下所示:

Employee:
| id | name | salary | department | company_id |
|----|----------|--------|------------|------------|
| 1 | john doe | 3000 | Finance | 1 |
| 2 | mary sue | 3300 | HR | 1 |

Company:
| id | name | address |
|----|------|------------|
| 1 | ACME | St. Sesame |


现在假设我要从某个员工那里获取数据,如果以后需要公司数据,我只希望员工数据+公司ID(也只有ID)作为参考。它看起来像这样:

Session session = SessionManager.openSession();

Employee emp = session.get(Employee.class, 1);

session.close();


现在我要显示员工数据

System.out.println(emp);


预期(或至少预期)的输出如下所示:

Employee{id=1,name='john doe',salary=3000.0,department='Finance',company=Company{id=1,name=null,address=null,employees=null}}


这很简单,问题在于它将引发LazyInitializationException,因为在Employee的 toString()调用上需要Hibernate尝试使用代理对象来获取公司的数据时,该会话已经关闭。

关键是,如果我关闭了会话却没有获取更多数据,那就意味着,不需要更多数据了!如果打开一个会话,我将获取所有我需要的数据,并且仅获取我需要的数据。关闭它之后,这意味着我不再需要任何数据,谢谢您休眠,但休眠的代理对象保持活动状态即使会话关闭后。

我搜索了整个网络,甚至在StackOverflow上也是如此,并且有一些所谓的“解决方案”或“解决方法”,例如:


为什么不将HQL与构造函数一起使用?


好吧,在查询足够简单以使用HQL的情况下,我实际上在许多用例中都使用了那些。问题在于许多用例需要复杂的查询,具有大量的联接和计算,甚至使用未映射到Hibernate Entities的表,因此我需要一个本机查询来做到这一点。


您可以将HQL与构造函数一起使用,并为需要在查询中访问的每个数据库表创建实体


那将意味着映射我将在一个(也许是两个)用例上使用的数十个实体,并且再也不会映射,只是这样我就可以在构造函数中使用HQL。此外,其中一些查询使用本机函数,而HQL根本不支持其他复杂的计算。


然后使用本机查询,当您不希望该列数据时可以放置 NULL as columnName


我在某些用例上也这样做,问题是当该列是实体关系上的连接列时,Hibernate设置了一个代理对象,而我不希望使用代理对象,如果连接列的数据是AND,并且只有在代码的另一部分需要该数据时,我才能在其中打开一个新会话并检索所需的数据。


您为什么不使用视图模式的打开会话来保持会话打开?


不能做,那就是RESTful API,如果客户在第一个请求中要求雇员数据,然后又在另一个请求中要求该前雇员的公司数据,并在请求正文中传递公司ID,该怎么办? ?那是一个常见的用例。


session.detach()?


不起作用


无状态会话?


仍会创建代理对象,它仅禁用当前会话的第一级和第二级缓存。


您为什么不使用DTO?


并为我的API的部分数据请求的每个用例创建一个新类?哈哈哈!

您看到的,我使用像Hibernate这样的ORM解决方案的唯一原因是因为我对ResultSets DEATH的手动处理感到恐惧。忘记HQL,Criteria API等。如果我只能让Hibernate为我映射ResultSet到对象(或对象列表),那么我不介意从字符串创建本机查询。我希望Hibernate知道是否存在在会话关闭之前没有获取的实体关系,这意味着我不想获取它,因此没有代理对象。

我知道那里可能有另一个ORM解决方案不存在此问题,但是由于DEADLINES,我不能抽出时间来学习它,所以请有人帮助我。

编辑

因此,有些人将我的问题标记为 Converting Hibernate proxy to a real entity object的重复项,但有一些区别:


这个问题围绕着如何“取消代理”一个对象,就像如何触发一个Hibernate代理的初始化一样。
我的问题是关于如何使Hibernate不对未获取的关系对象使用代理,而是仅使用具有其ID的关系类的实例。


在我的上一个示例中,我希望休眠而不是使用代理在以后需要时懒惰地获取与 Company相关的 Employee对象,而希望休眠只创建一个 new Company(company_id)并保留它,即NO PROXY。

编辑2

我刚刚发现Jackson项目(用于在我的API中以JSON形式读取/写入数据)的模块可以在序列化对象时忽略Hibernate代理。

Maven依赖项:

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
<version>${jackson-version}</version>
</dependency>


然后只需在您的 Object Mapper实例上注册模块:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate5Module());

最佳答案

因此,看来我的EDIT 2确实是我的问题的“一种”解决方案。

jackson-datatype-hibernate5最初会忽略未获取的代理,在序列化对象时将其设置为null,但是类Hibernate5Module(或您要使用的任何Hibernate模块版本)具有非常方便的配置,使得Jackson仅序列化了未获取的ID。代理,这就是我想要的。

// Configuring `ObjectMapper` and module:
ObjectMapper mapper = new ObjectMapper();
Hibernate5Module module = new Hibernate5Module()
.configure(Hibernate5Module.Feature.SERIALIZE_IDENTIFIER_FOR_LAZY_NOT_LOADED_OBJECTS, true);

mapper.registerModule(module);


这样,您可以使用该 ObjectMapper为不会在序列化时尝试初始化代理对象的类创建 ObjectReaders,而仅序列化该对象的ID(当然,如果其是OneToOne或ManyToOne关系)。

我说这是“一种”解决方案,因为Hibernate仍在使用代理对象来处理未获取的关系(当我只希望代理对象的ID值供以后使用时),唯一的事情是我已配置Jackson来保留ID值并忽略代理对象。

关于java - session 关闭后,如何禁用或禁止使用Hibernate代理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56344351/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com