无法在一对一关系中使用 JPA 执行 LAZY FETCH 操作
Unable to perform LAZY FETCH operation using JPA in one-to-one relationship
我正在尝试使用 JPA 延迟获取 PetDetails
实体。但是,我得到 LazyInitialization Exception
。我阅读了很多针对此异常的解决方案,并使用 JPQL
中的 JOIN FETCH
找到了解决方案。人们还建议使用 Criteria
查询。但是,我正在尝试寻找一种解决方案,如果有一种方法可以按照我想要的方式获取 PetDetails
实体,而无需直接使用查询或依赖于 Criteria API
或不使用 EAGER FETCH
。我可能会遗漏一些东西。如果有任何帮助或建议,我将不胜感激。以下是代码示例:
1. Controller class:
@Controller
public class PetController {
private static Logger LOGGER = Logger.getLogger(PetController.class);
@Autowired
private PetService petService;
@RequestMapping(value = "/", method = RequestMethod.GET)
public void manageAndDisplayPet() {
PetDetails petDetails = new PetDetails();
petDetails.setName("DOG");
Pet pet = new Pet(petDetails);
// save
petService.savePet(pet);
// retrieve
LOGGER.debug("**********************" + petService.getPet());
LOGGER.debug("**********************" + pet.getPetDetails());
}
}
2. PetService class:
@Service
public class PetService {
@Autowired
private PetDAO petDAO;
@Transactional
public void savePet(Pet pet) {
petDAO.savePet(pet);
}
@Transactional
public Pet getPet() {
return petDAO.getPet();
}
}
3. PetDAO class
@Repository
@EnableTransactionManagement
public class PetDAO {
@PersistenceContext(unitName = "petcontext")
private EntityManager entityManagerFactory;
public void savePet(Pet pet) {
entityManagerFactory.persist(pet);
}
public Pet getPet() {
Pet pet = (Pet) entityManagerFactory.find(Pet.class, 1);
return pet;
}
}
4. Pet Entity:
@Entity
@Table(name = "t_pet")
public class Pet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@JoinColumn(name = "pet_details")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private PetDetails petDetails;
public Pet() {
}
public Pet(PetDetails petDetails) {
this.petDetails = petDetails;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public PetDetails getPetDetails() {
return petDetails;
}
public void setPetDetails(PetDetails petDetails) {
this.petDetails = petDetails;
}
@Override
public String toString() {
return "Pet [id=" + id + ", petDetails=" + petDetails + "]";
}
}
5. PetDetails Entity:
@Entity
@Table(name = "pet_details")
public class PetDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "pet_name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "PetDetails [id=" + id + ", name=" + name + "]";
}
}
感谢您的帮助。
您可以轻松地在 PetService#getPet
中调用 pet.getPetDetails()
。这个解决方案不是很清楚,但它也会强制 JPA 获取实体。这是您问题的解决方案,但无论如何都不是好方法。
有什么好的方法吗?
好的方法可能取决于您的特定用例:
- 如果您每次都需要此详细信息 — 您应该使用
EAGER_FETCH
- 如果您不时需要它而不是将 JPQL 与
JOIN FETCH
一起使用的好解决方案
- 但最好的方法是 select 不是实体,而是 DTO,它将包含您的应用程序需要的全部信息,而不是更多。可以使用
SELECT NEW
表达式实现,如 here 所述
我正在尝试使用 JPA 延迟获取 PetDetails
实体。但是,我得到 LazyInitialization Exception
。我阅读了很多针对此异常的解决方案,并使用 JPQL
中的 JOIN FETCH
找到了解决方案。人们还建议使用 Criteria
查询。但是,我正在尝试寻找一种解决方案,如果有一种方法可以按照我想要的方式获取 PetDetails
实体,而无需直接使用查询或依赖于 Criteria API
或不使用 EAGER FETCH
。我可能会遗漏一些东西。如果有任何帮助或建议,我将不胜感激。以下是代码示例:
1. Controller class:
@Controller
public class PetController {
private static Logger LOGGER = Logger.getLogger(PetController.class);
@Autowired
private PetService petService;
@RequestMapping(value = "/", method = RequestMethod.GET)
public void manageAndDisplayPet() {
PetDetails petDetails = new PetDetails();
petDetails.setName("DOG");
Pet pet = new Pet(petDetails);
// save
petService.savePet(pet);
// retrieve
LOGGER.debug("**********************" + petService.getPet());
LOGGER.debug("**********************" + pet.getPetDetails());
}
}
2. PetService class:
@Service
public class PetService {
@Autowired
private PetDAO petDAO;
@Transactional
public void savePet(Pet pet) {
petDAO.savePet(pet);
}
@Transactional
public Pet getPet() {
return petDAO.getPet();
}
}
3. PetDAO class
@Repository
@EnableTransactionManagement
public class PetDAO {
@PersistenceContext(unitName = "petcontext")
private EntityManager entityManagerFactory;
public void savePet(Pet pet) {
entityManagerFactory.persist(pet);
}
public Pet getPet() {
Pet pet = (Pet) entityManagerFactory.find(Pet.class, 1);
return pet;
}
}
4. Pet Entity:
@Entity
@Table(name = "t_pet")
public class Pet {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@JoinColumn(name = "pet_details")
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private PetDetails petDetails;
public Pet() {
}
public Pet(PetDetails petDetails) {
this.petDetails = petDetails;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public PetDetails getPetDetails() {
return petDetails;
}
public void setPetDetails(PetDetails petDetails) {
this.petDetails = petDetails;
}
@Override
public String toString() {
return "Pet [id=" + id + ", petDetails=" + petDetails + "]";
}
}
5. PetDetails Entity:
@Entity
@Table(name = "pet_details")
public class PetDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "pet_name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "PetDetails [id=" + id + ", name=" + name + "]";
}
}
感谢您的帮助。
您可以轻松地在 PetService#getPet
中调用 pet.getPetDetails()
。这个解决方案不是很清楚,但它也会强制 JPA 获取实体。这是您问题的解决方案,但无论如何都不是好方法。
有什么好的方法吗?
好的方法可能取决于您的特定用例:
- 如果您每次都需要此详细信息 — 您应该使用
EAGER_FETCH
- 如果您不时需要它而不是将 JPQL 与
JOIN FETCH
一起使用的好解决方案
- 但最好的方法是 select 不是实体,而是 DTO,它将包含您的应用程序需要的全部信息,而不是更多。可以使用
SELECT NEW
表达式实现,如 here 所述