通过我的代码,我在实体之间的多对一关系中强制执行 n + 1 问题。 为了检查是否存在 n + 1 问题,我设置了一个测试。
运行测试时,我还可以看到执行了 3 个查询,但休眠统计信息仍然返回 1 个已执行的查询。这显然是错误的。
在我的测试中刷新并清除实体管理器也应该可以防止缓存问题。
这是测试的日志:
Hibernate: insert into shelter (name,id) values (?,default)
Hibernate: insert into shelter (name,id) values (?,default)
Hibernate: insert into messages (name,shelter_id,id) values (?,?,default)
Hibernate: insert into messages (name,shelter_id,id) values (?,?,default)
Hibernate: insert into messages (name,shelter_id,id) values (?,?,default)
Hibernate: select a1_0.id,a1_0.name,a1_0.shelter_id from messages a1_0
Hibernate: select s1_0.id,s1_0.name from shelter s1_0 where s1_0.id=?
Hibernate: select s1_0.id,s1_0.name from shelter s1_0 where s1_0.id=?
Hibernate: drop table if exists messages cascade
这是我的代码:
实体一:
@Entity
@Table(name = "messages")
data class Animal(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
@Column(nullable = false)
val name: String,
@ManyToOne
@JoinColumn(name = "shelter_id")
val shelter: Shelter
)
实体二:
@Entity
@Table(name = "shelter")
data class Shelter(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
@Column(nullable = false)
val name: String,
)
存储库:
@Repository
interface AnimalRepository: JpaRepository<Animal, Long> {}
存储库测试:
@DataJpaTest
class AnimalRepositoryTest @Autowired constructor(
private val animalRepository: AnimalRepository,
private val entityManager: EntityManager
) {
private lateinit var hibernateStatistics: Statistics
@BeforeEach
fun setUp() {
// // Initialize the Hibernate statistics
val sessionFactory = entityManager.unwrap(Session::class.java).sessionFactory
hibernateStatistics = sessionFactory.statistics
hibernateStatistics.isStatisticsEnabled = true
hibernateStatistics.clear() // Reset statistics before each test
// Insert initial test data
val shelter = Shelter(name = "Happy Shelter")
val shelter2 = Shelter(name = "Happy Shelter2")
entityManager.persist(shelter)
entityManager.persist(shelter2)
val animal1 = Animal(name = "Lion", shelter = shelter)
val animal2 = Animal(name = "Tiger", shelter = shelter)
val animal3 = Animal(name = "Panda", shelter = shelter2)
entityManager.persist(animal1)
entityManager.persist(animal2)
entityManager.persist(animal3)
entityManager.flush()
entityManager.clear() // Clear persistence context to ensure fresh retrieval
}
@Test
@Transactional
@Rollback
fun `should execute one SQL query when finding all animals with shelter`() {
// Perform the operation (fetch all animals with shelter)
val animals = animalRepository.findAll()
// Assert the result
assertThat(animals).hasSize(3)
animals.forEach { animal -> animal.shelter.name}
// Check Hibernate statistics for SQL query count
val executedQueryCount = hibernateStatistics.queryExecutionCount
assertThat(executedQueryCount).isEqualTo(1)
}
}
如果您需要更多信息,请告诉我;)
Hibernate 统计信息不将获取单个实体视为查询,而是将其视为加载的实体。您可以将
.findAll()
替换为 .findById(1)
,并且 hibernateStatistics.queryExecutionCount
将为 0。要查看已加载实体的数量,请检查 hibernateStatistics.entityLoadCount
。