我有兩個類User.java和Address.java并且它們之間存在一對一的雙向映射。
但是當我嘗試使用User類獲取地址時,我得到一個“java.lang.StackOverflowError:null”例外。
當我嘗試從Address類中獲取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;
地址.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;
主控制器.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";
}
}
uj5u.com熱心網友回復:
TLDR:你實際上并沒有在任何地方保存任何東西,但它很容易修復。這是我的代碼和我的解釋:
主控制器.java:
@RestController
public class MainController {
private final UserRepository userRepository;
private final AddressRepository addressRepository;
public MainController(UserRepository userRepository, AddressRepository addressRepository){
this.userRepository = userRepository;
this.addressRepository = addressRepository;
}
@GetMapping("/test")
public String test() {
User user = new User();
user.setName("name");
user.setEmail("email");
user.setPhone("phone");
user.setPassword("password");
user.setImageUrl("imageUrl");
user = userRepository.save(user);
System.out.println("saved user");
Address address = new Address();
address.setCountry("country");
address.setState("state");
address.setCity("city");
address.setStreet("street");
address.setPincode("123456");
address = addressRepository.save(address);
System.out.println("saved address");
user.setAddress(address);
userRepository.save(user);
System.out.println("set user's address");
return "working";
}
@GetMapping("/fetch")
public String fetch() {
Optional<User> optionalUser = userRepository.findById((long) 1);
if(optionalUser.isPresent()){
User user = optionalUser.get();
System.out.println(user.getAddress());
boolean addressExists = addressRepository.existsById((long) 1);
System.out.println(addressExists);
System.out.println(user.getAddress().getCountry());
return "working";
}
System.out.println("Error: user with id 1 not found!");
return "failing";
}
}
用戶.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_id", referencedColumnName = "id")
private Address address;
//getters and setters omitted for brevity
}
地址.java:
@Entity
@Table(name = "address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@OneToOne(mappedBy = "address")
private User user;
private String country;
private String state;
private String city;
private String street;
private String pincode;
//getters and setters omitted for brevity
}
地址存盤庫.java:
public interface AddressRepository extends CrudRepository<Address, Long> {
}
用戶存盤庫.java:
public interface UserRepository extends CrudRepository<User, Long> {
}
用戶DAO.java:
public class UserDAO {
private final String name;
private final String email;
private final String phone;
private final String imageUrl;
public UserDAO(User user) {
name = user.getName();
email = user.getEmail();
phone = user.getPhone();
imageUrl = user.getImageUrl();
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getPhone() {
return phone;
}
public String getImageUrl() {
return imageUrl;
}
}
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. The save method actually saves the POJO, and returns the saved version, which is why I did user = 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 the UserDAO object as a response, you can create it using the user object that is returned from the database, maybe something like:
UserDAO dao = new UserDAO(userRepository.save(user));
Please take notice of what is happening inside the test method in MainController. First, we create the POJO User object and set its fields. Then we have to save it to the repository, it is only persisted after you call save method of the repository. Please note that the user object is saved again once it is updated with the address.
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 the user 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.
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/433456.html
