gpt4 book ai didi

hibernate - 如何避免在调用 toString() 时初始化 HibernateProxy?

转载 作者:行者123 更新时间:2023-12-01 14:09:57 27 4
gpt4 key购买 nike

我有以下映射:

作者:

@Entity
@Getter
@Setter
public class Author {
@Id
@GeneratedValue(strategy = IDENTITY)
@Access(PROPERTY)
private Long id;
}

书:

@Entity
@Getter
@Setter
public class Book {
@Id
@GeneratedValue(strategy = IDENTITY)
@Access(PROPERTY)
private Long id;

@ManyToOne(fetch = LAZY)
private Author author;
}

以下代码演示了这个问题:

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
@Autowired
private EntityManagerFactory emf;

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

@Override
public void run(String... args) throws Exception {
saveBookAndAuthor();


EntityManager em = emf.createEntityManager();
Book book = em.find(Book.class, 1L);
Author author = book.getAuthor();
System.out.println(author.getClass());
author.toString();
}

private void saveBookAndAuthor() {
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
Author author = new Author();
Book book = new Book();
book.setAuthor(author);
entityManager.persist(author);
entityManager.persist(book);
entityManager.getTransaction().commit();
entityManager.close();
}
}

部分日志如下:

class com.example.demo.Author_$$_jvst5e0_0
2017-11-22 22:12:56.671 DEBUG 9426 --- [ main] org.hibernate.internal.SessionImpl : Initializing proxy: [com.example.demo.Author#1]
2017-11-22 22:12:56.671 DEBUG 9426 --- [ main] org.hibernate.SQL : select author0_.id as id1_0_0_ from author author0_ where author0_.id=?

author.toString(); 行会导致 Author 实体初始化,即使 toString() 方法未被覆盖。有办法避免吗?

Spring Boot 版本:1.5.8.RELEASE

hibernate 版本:5.0.12.Final

最佳答案

使 toString() final 解决了这个问题。

背景:

我花了一些时间来弄清楚到底发生了什么。这是我发现的

Hibernate 使用 Javassist 生成运行时代理。

生成的代理执行javassist.util.proxy.ProxyObject具有 Hibernate 用于设置 org.hibernate.proxy.pojo.javassist.JavassistLazyInitializersetHandler(MethodHandler) 方法的接口(interface)(反过来拦截方法调用(包括 toString())。

toString() 被调用时,原始方法应该继续(JavassistLazyInitializer.invoke(Object, Method, Method,Object[]):

if ( result == INVOKE_IMPLEMENTATION ) {
Object target = getImplementation();
...

但在 Hibernate 初始化代理之前(AbstractLazyInitializer):

@Override
public final Object getImplementation() {
initialize();
return target;
}

final 方法不会被拦截,所以在 toString() 中添加 final 修饰符将解决问题。

但请记住,如果您的 toString() 直接访问字段并且代理未初始化,您将看到 null,即使这些字段确实存在。您可以使用 getters in 来避免这种情况。 但是您真的需要触发初始化来打印您的实体以进行记录吗?

如果我错了或者有更好的解决办法请告诉我

关于hibernate - 如何避免在调用 toString() 时初始化 HibernateProxy?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47442454/

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