gpt4 book ai didi

java - 我应该如何处理 dao 层中延迟初始化的 Hibernate 实体以及在不同层中共享状态

转载 作者:行者123 更新时间:2023-11-30 01:51:50 25 4
gpt4 key购买 nike

我正在编写一个Web应用程序(基于服务器的应用程序),其中有一个dao层、服务层和应用程序层。我应该如何接管惰性初始化异常,该异常是由于从 dao 层返回的实体与返回它的方法内部打开的 session 有关并且也在那里关闭而导致的,这使得实体分离。接下来的事情是可以安全地跨不同层共享 hibernate 实体。是什么让我问这个问题是场景:例如假设我有一个 hibernate 实体与某个其他实体具有一对一的关联。假设dao将其传递给服务层到应用层。现在,如果我尝试通过传递的实体 getter 方法在应用程序层获取此关联实体,则会触发数据库查询,我认为这会扰乱“关注点分离”,因为数据库相关操作应限制在 dao 层。我说得对吗?

我在通过内存数据库对我的 dao 层进行单元测试时发现了上述问题。我的场景是,我有一个名为 RegisteredUser 的 pojo 类,其字段为:(id、用户名、名字、姓氏、passwHash、电子邮件、StudyCentre)。 StudyCentre 是另一个实体,它通过一对一映射与 RegistereUser 关联,用户名是naturalid。我想要的是两种类型的读取操作,第一种是我需要通过自然ID在没有学习中心的情况下获取用户详细信息,第二种是通过自然ID再次获取完整的用户字段。在这里制作两个单独的 DTO 并跨层传递它们是一个好主意。

注册用户实体:

package com.ignoubadhega.pojos;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;

import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.NaturalId;

@Entity
@Table(name = "registered_user")
@DynamicUpdate
public class RegisteredUser {

private Long dbUserId;
private String userName;
private String passwHash;
private String firstName;
private String lastName;
private String email;
private StudyCentre studyCentre;

RegisteredUser() {
}

public RegisteredUser(
String userName, String passwHash, String firstName,
String lastName, String email
) {
super();
this.userName = userName;
this.passwHash = passwHash;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "db_user_id")
public Long getDbUserId() {
return dbUserId;
}

@Override
public String toString() {
return "RegisteredUser [dbUserId="
+ dbUserId
+ ", userName="
+ userName
+ ", passwHash="
+ passwHash
+ ", firstName="
+ firstName
+ ", lastName="
+ lastName
+ ", email="
+ email
+ "]";
}

public void setDbUserId(Long dbUserId) {
this.dbUserId = dbUserId;
}

@Column(name = "username", nullable = false, unique = true)
@NaturalId
public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}

@Column(name = "passw_hash", nullable = false)
public String getPasswHash() {
return passwHash;
}

public void setPasswHash(String passwHash) {
this.passwHash = passwHash;
}

@Column(name = "first_name", nullable = false)
public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

@Column(name = "last_name", nullable = false)
public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

@Column(name = "email", nullable = false, unique = true)
public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "db_study_centre_id", nullable = false)
public StudyCentre getStudyCentre() {
return studyCentre;
}

public void setStudyCentre(StudyCentre studyCentre) {
this.studyCentre = studyCentre;
}

}

Dao 实现者:

package com.ignoubadhega.dao.impl;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;

import com.ignoubadhega.dao.RegisteredUserDAO;
import com.ignoubadhega.pojos.RegisteredUser;

public class RegisteredUserDAOImpl implements RegisteredUserDAO {

private SessionFactory sessionFactory;

public RegisteredUserDAOImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}

@Override
public void addUser(RegisteredUser user) {
try (Session session = sessionFactory
.openSession()) {
session.beginTransaction();
session.persist(user);
session.getTransaction().commit();
} catch (HibernateException except) {
except.printStackTrace();
}
}

@Override
public RegisteredUser getUserByUserName(String username, boolean doesStudyCentereNeeded) {
try (Session session = sessionFactory
.openSession()) {
RegisteredUser user = session
.bySimpleNaturalId(RegisteredUser.class).load(username);
if (doesStudyCentereNeeded) {
user.setStudyCentre(user.getStudyCentre());
}
return user;
} catch (HibernateException except) {
except.printStackTrace();
}
return null;
}

@Override
public void deleteUser(RegisteredUser user) {
try (Session session = sessionFactory
.openSession()) {
session.beginTransaction();
session.delete(user);
session.getTransaction().commit();
} catch (HibernateException except) {
except.printStackTrace();
}
}

@Override
public void updateUser(RegisteredUser user) {
try (Session session = sessionFactory
.openSession()) {
session.beginTransaction();
session.update(user);
session.getTransaction().commit();
} catch (HibernateException except) {
except.printStackTrace();
}
}

}

发现延迟初始化问题的TestCase:

@Test
@DisplayName(
"User through its natural id 'username' assuming the user"
+ " is persistent in the database is successful"
)
void test_fetching_a_persistent_user_through_username_is_successful() {
try (Session session = sessionFactory.openSession()) {
session.beginTransaction();
session.persist(user);
session.getTransaction().commit();
RegisteredUser retrievedUser =
dao.getUserByUserName("prav", true);
assertNotNull(retrievedUser);
assert_actual_user_and_retrieved_user_fields_are_equal(user,
retrievedUser);
} catch (HibernateException except) {
except.printStackTrace();
}
}

private static void assert_actual_user_and_retrieved_user_fields_are_equal(
RegisteredUser actualUser, RegisteredUser userRetrieved
) throws MultipleFailuresError {
assertAll("user fields",
() -> assertEquals(actualUser.getUserName(),
userRetrieved.getUserName()),
() -> assertEquals(actualUser.getPasswHash(),
userRetrieved.getPasswHash()),
() -> assertEquals(actualUser.getFirstName(),
userRetrieved.getFirstName()),
() -> assertEquals(actualUser.getLastName(),
userRetrieved.getLastName()),
() -> assertEquals(actualUser.getEmail(),
userRetrieved.getEmail()),
() -> {
StudyCentre retrievedCentre =
userRetrieved.getStudyCentre();
assertNotNull(retrievedCentre);
assertAll("user study centre assosciated",
() -> assertEquals(
actualUser.getStudyCentre().getData()
.getStudyCentreName(),
retrievedCentre.getData()
.getStudyCentreName()),
() -> assertEquals(
actualUser.getStudyCentre().getData()
.getRegionalCentreCode(),
retrievedCentre.getData()
.getRegionalCentreCode()));
});
}

我希望保持我的服务层(尚未实现)与 Hibernate 特有的事物(如 session 和数据库相关操作(CRUD))隔离。我怎样才能实现它。我应该遵循什么设计模式吗?我是 hibernate 新手。如果我在任何地方做错了什么,请指导我。我尝试在谷歌上找到类似的帖子,但未能获得有关该问题的任何见解。

最佳答案

how should i take over the lazy initialization exception, caused due to the fact that entity returned from dao layer is concerned with the session opened inside the method from where it is returned and also closed there which makes the entity detached.

您可以通过在服务或应用程序层中打开和关闭 session ,并在单个事务中完成所有工作来处理该问题。

is it safe to share the hibernate entities across different layer

是的。不安全的是跨多个线程使用实体实例,因为实体不是线程安全的。

a database query is fired which i think is messing up with the "seperation of concerns" as database related operation should be constrained to the dao layer. am i right?

没有。服务层不包含任何触发此数据库查询的代码。它是透明发生的,服务层不必关心它,因为您选择使关联变得惰性。

is making two seperate DTOs a good idea here and passing them across layers.

没有。 DTO 对于在不同的应用程序之间传输数据非常有用。在您的应用程序中,使用托管实体是正确的方法。

i want to keep my service layer(not yet implemented) to be isolated from things specific to hibernate like sessions and database related operations(CRUD). how can i achieve it.

通过使用 Spring 或 Java EE(或任何其他具有此功能的框架),它们允许使用声明性事务,并在调用事务方法时为您处理打开/关闭 session 和事务的任务。

您还应该避免使用专有的 Session API,而使用标准的 JPA API。

关于java - 我应该如何处理 dao 层中延迟初始化的 Hibernate 实体以及在不同层中共享状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55740190/

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