无法在一对一关系中使用 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 获取实体。这是您问题的解决方案,但无论如何都不是好方法。


有什么好的方法吗?

好的方法可能取决于您的特定用例:

  1. 如果您每次都需要此详细信息 — 您应该使用 EAGER_FETCH
  2. 如果您不时需要它而不是将 JPQL 与 JOIN FETCH
  3. 一起使用的好解决方案
  4. 但最好的方法是 select 不是实体,而是 DTO,它将包含您的应用程序需要的全部信息,而不是更多。可以使用 SELECT NEW 表达式实现,如 here
  5. 所述