java.lang.StackOverflowError: null [Spring Boot、Hibernate]
我有两个类 User.java 和 Address.java ,它们之间存在一对一双向映射。
但是当我尝试使用 User 类获取地址时,我收到 "java.lang.StackOverflowError: null" 异常。
当我尝试从 Address 类中获取 User 时,也会发生同样的情况。
User.java
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
private String email;
private String phone;
private String password;
private String imageUrl;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address")
private Address address;
Address.java
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "address")
private User user;
private String country;
private String state;
private String city;
private String street;
private String pincode;
MainController.java
@Controller
public class MainController {
@Autowired
private UserDao userDao;
@Autowired
private AddressDao addressDao;
@RequestMapping("/test")
@ResponseBody
public String test() {
User user = new User();
user.setName("name");
user.setEmail("email");
user.setPhone("phone");
user.setPassword("password");
user.setImageUrl("imageUrl");
Address address = new Address();
address.setCountry("country");
address.setState("state");
address.setCity("city");
address.setStreet("street");
address.setPincode("123456");
user.setAddress(address);
userDao.save(user);
return "working";
}
@RequestMapping("/fetch")
@ResponseBody
public String fetch() {
User user = userDao.getById((long) 1);
System.out.println(user.getAddress());
return "working";
}
}
我正在使用 test() 函数将数据放入数据库并且工作正常。 数据库图像
但是当我调用 fetch() 函数时,我是出现以下错误
java.lang.StackOverflowError: null
at org.hibernate.proxy.pojo.BasicLazyInitializer.invoke(BasicLazyInitializer.java:58) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:43) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at
更新了 MainController.java
package com.demo.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.demo.dao.AddressDao;
import com.demo.dao.UserDao;
import com.demo.entity.Address;
import com.demo.entity.User;
@Controller
public class MainController {
@Autowired
private UserDao userDao;
@Autowired
private AddressDao addressDao;
@RequestMapping("/test")
@ResponseBody
public String test() {
User user = new User();
user.setName("name");
user.setEmail("email");
user.setPhone("phone");
user.setPassword("password");
user.setImageUrl("imageUrl");
userDao.save(user);
Address address = new Address();
address.setCountry("country");
address.setState("state");
address.setCity("city");
address.setStreet("street");
address.setPincode("123456");
addressDao.save(address);
user.setAddress(address);
userDao.save(user);
return "working";
}
@RequestMapping("/fetch")
@ResponseBody
public String fetch() {
Optional<User> op = userDao.findById((long) 1);
User user = op.get();
// working
System.out.println(user.getName() + " " + user.getEmail() + " " + user.getPhone());
// java.lang.StackOverflowError:null
System.out.println(user.getAddress());
return "working";
}
}
I have two classes User.java and Address.java and there is a one-to-one bi-directional mapping between them.
But when I try to get the address using the User class I get an "java.lang.StackOverflowError: null" exception.
The same thing happens when I try to get the User from the Address class.
User.java
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
private String email;
private String phone;
private String password;
private String imageUrl;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address")
private Address address;
Address.java
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "address")
private User user;
private String country;
private String state;
private String city;
private String street;
private String pincode;
MainController.java
@Controller
public class MainController {
@Autowired
private UserDao userDao;
@Autowired
private AddressDao addressDao;
@RequestMapping("/test")
@ResponseBody
public String test() {
User user = new User();
user.setName("name");
user.setEmail("email");
user.setPhone("phone");
user.setPassword("password");
user.setImageUrl("imageUrl");
Address address = new Address();
address.setCountry("country");
address.setState("state");
address.setCity("city");
address.setStreet("street");
address.setPincode("123456");
user.setAddress(address);
userDao.save(user);
return "working";
}
@RequestMapping("/fetch")
@ResponseBody
public String fetch() {
User user = userDao.getById((long) 1);
System.out.println(user.getAddress());
return "working";
}
}
I am using the test() function to put data in the database and it is working fine.
database image
But when I call the fetch() function I am getting the following error
java.lang.StackOverflowError: null
at org.hibernate.proxy.pojo.BasicLazyInitializer.invoke(BasicLazyInitializer.java:58) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:43) ~[hibernate-core-5.6.5.Final.jar:5.6.5.Final]
at
Updated MainController.java
package com.demo.controller;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.demo.dao.AddressDao;
import com.demo.dao.UserDao;
import com.demo.entity.Address;
import com.demo.entity.User;
@Controller
public class MainController {
@Autowired
private UserDao userDao;
@Autowired
private AddressDao addressDao;
@RequestMapping("/test")
@ResponseBody
public String test() {
User user = new User();
user.setName("name");
user.setEmail("email");
user.setPhone("phone");
user.setPassword("password");
user.setImageUrl("imageUrl");
userDao.save(user);
Address address = new Address();
address.setCountry("country");
address.setState("state");
address.setCity("city");
address.setStreet("street");
address.setPincode("123456");
addressDao.save(address);
user.setAddress(address);
userDao.save(user);
return "working";
}
@RequestMapping("/fetch")
@ResponseBody
public String fetch() {
Optional<User> op = userDao.findById((long) 1);
User user = op.get();
// working
System.out.println(user.getName() + " " + user.getEmail() + " " + user.getPhone());
// java.lang.StackOverflowError:null
System.out.println(user.getAddress());
return "working";
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
TLDR:您实际上并没有在任何地方保存任何内容,但是很容易修复。这是我的代码和解释:
MainController.java:
User.java:
Address.java:
AddressRepository.java:
UserRepository.java:
UserDAO.java:
A DAO 没有与数据库的连接,它的意图就是缩写所代表的意思,简单地说传输数据,仅此而已。创建存储库时,您可以通过将对象保存在存储库中来将其粘贴在那里。请注意,通过使用正确的泛型扩展
CrudRepository
,您甚至不需要自己实现这些方法。save
方法实际上保存了 POJO,并返回保存的版本,这就是我执行user = userRepository.save(user)
的原因,这乍一看似乎违反直觉,但是它只是帮助确保一切都如您所愿。如果您随后想要发送UserDAO
对象作为响应,您可以使用从数据库返回的user
对象来创建它,可能类似于:请注意
MainController
中的test
方法内部发生了什么。首先,我们创建 POJO User 对象并设置其字段。然后我们必须将其保存到存储库中,只有在调用存储库的save
方法后它才会被持久化。请注意,user
对象在使用address
更新后会再次保存。这是一种非常粗略的做事方式,最好创建一个服务层并使用 @Transactional 注释来执行此操作,这意味着如果内部出现问题,所有内容都会回滚。方法注释为@Transactional。
另外,使用
CascadeType.ALL
可能不是您想要的,请参阅此答案。在
fetch
方法中,我确保user
确实存在,但无法保证。为了避免 500 错误,重要的是在某些事情不起作用时有一个后备机制。作为最后的旁注,您不应该像这样存储原始密码,您至少应该使用盐和胡椒进行哈希处理,或者使用许多可用的库之一来实现此类功能(尽管这样做可能会非常有趣)代码本身很脏)。您还应该考虑当出现问题时您要透露多少信息,因为您不想泄露太多可用于对特定用户进行匿名化的信息,甚至不想了解有关您的代码和系统架构的更多信息。
TLDR: you aren't actually saving anything anywhere, but it's easy to fix. Here's my code and my explanation:
MainController.java:
User.java:
Address.java:
AddressRepository.java:
UserRepository.java:
UserDAO.java:
A DAO has no connection to the database, it's intent is what the acronym stands for, simply to transfer data, and that's it. When you make a repository, you can stick your objects there by saving them in the repository. Notice that by extending the
CrudRepository
with correct generics, you don't even need to implement the methods yourself. Thesave
method actually saves the POJO, and returns the saved version, which is why I diduser = userRepository.save(user)
, which may seem counterintuitive at first, but it simply helps ensure that everything is as you expect. If you then want to send theUserDAO
object as a response, you can create it using theuser
object that is returned from the database, maybe something like:Please take notice of what is happening inside the
test
method inMainController
. First, we create the POJOUser
object and set its fields. Then we have to save it to the repository, it is only persisted after you callsave
method of the repository. Please note that theuser
object is saved again once it is updated with theaddress
.This is a very crude way to do things, it is best to create a service layer and do this there with the
@Transactional
annotation, which would mean that everything is rolled back in case something goes wrong inside a method annotated as@Transactional
.Also, using
CascadeType.ALL
may be not what you want, please refer to this answer.Inside
fetch
method, I ensure that theuser
indeed exists, which is not guaranteed. To avoid 500 errors, it's important to have a fallback mechanism for when something doesn't work.As a final side note, you shouldn't be storing raw passwords like that, you should at least use hashing with salt and pepper, or use one of the many available libraries for implementing such functionality (although it can be quite fun getting down and dirty with the code itself). You should also consider how much information you are revealing when something does go wrong, as you don't want to give away too much information which could be used to deanonimise a specific user, or even learn more about your code and the system architecture.