gpt4 book ai didi

java - 在 ControllerTest 中使用 @WebAppConfiguration 而不是 @SpringBootTest 时,Spring Data JPA 中会忽略延迟初始化

转载 作者:行者123 更新时间:2023-11-30 02:09:45 25 4
gpt4 key购买 nike

我使用以下模型:

@Entity
public class User {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String username;

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "USER_ROLE", joinColumns = {@JoinColumn(name = "USER_ID", referencedColumnName = "ID")}, inverseJoinColumns = {@JoinColumn(name = "ROLE_ID", referencedColumnName = "ID")})
private List<Role> roles;

(...)
}

@Entity
public class Role {

private String name;

@ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
private List<User> users;

(...)
}

导致以下存储库:

public interface UserRepository extends CrudRepository<User, Long> {

User findByUsername(String username);
}

然后是一个 Controller ,例如:

@RestController
@RequestMapping("/test")
public class Controller {

@Autowired
private UserRepository userRepository;

@GetMapping
public void test(@RequestParam final String u) {
if(!this.userRepository.findByUsername(u).getRoles().get(0).getUsers().get(0).getRoles().get(0).getName().equals("Role1")) throw new RuntimeException();
}

}

Application 是普通的,不使用任何与 Transaction 相关的注释(但 main 用 @SpringBootApplication 注释)。

@SpringBootApplication
public class Application {
public static void main(final String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}

我只在 application.properties 中使用单个属性:spring.jpa.open-in-view=false

测试过程如下:

@RunWith(SpringRunner.class)
@WebAppConfiguration @ContextConfiguration(classes = Application.class)
@AutoConfigureMockMvc
public class ControllerTest {

@Autowired
private MockMvc mockMvc;

@Test
public void test() throws Exception {
this.mockMvc.perform(get("/test").param("u", "user1")).andExpect(status().isOk());
}
}

然后我的问题是,当调试时,看起来所有实体图都已完全急切地获取,并且测试返回成功,因为 Controller 没有失败。

我知道 JPA 存储库方法使用事务,但据我所知,只要我们不将它们包装在更高级别的事务上,它就应该在方法结束后完成。那么我在尝试访问角色或用户 -> 角色 -> 用户时怎么可能没有得到 LazyInitializatioExceptions ?这是预期的行为吗?

这是 Eclipse 调试器在显示用户角色中的用户时所显示的内容,值得一看:

enter image description here

Hibernate 日志记录显示了它在查找用户时如何急切地获取关系:

12:47:24.890 [main] DEBUG org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer - Loading collection:  ..domain.User.roles
12:47:24.937 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl - Found row of collection: [User.roles#1002]
12:47:24.953 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Resolving associations for [...domain.Role#5]
12:47:24.953 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [...domain.Role#5]
12:47:24.953 [main] DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext - 1 collections were found in result set for role: ...domain.User.roles
12:47:24.968 [main] DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext - Collection fully initialized: [...domain.User.roles#1002]
12:47:24.968 [main] DEBUG org.hibernate.engine.loading.internal.CollectionLoadContext - 1 collections initialized for role: ....domain.User.roles
12:47:24.968 [main] DEBUG org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered
12:47:24.968 [main] DEBUG org.hibernate.loader.collection.plan.AbstractLoadPlanBasedCollectionInitializer - Done loading collection

.

编辑:我发现如果我用现代的@SpringBootTest更改ControllerTest上的@WebAppConfiguration行>,我收到了LazyInitializationException。为什么@WebAppConfiguration旧方法会忽略延迟获取?

最佳答案

Spring Boot 默认情况下注册 OpenEntityManagerInViewInterceptor 以应用 Open EntityManager in View 模式,以允许在 Web View 中延迟加载。如果您不希望出现此行为,则应在 application.properties 中将 spring.jpa.open-in-view 设置为 false。

编辑:(编辑问题后)

确实,您应该有一个LazyInitializationException。我的猜测是,在您的测试中,Session 仍然处于打开状态?

如果您使用@SpringBootTest进行测试,您将得到一个LazyInitializationException

@RunWith(SpringRunner.class)
@SpringBootTest
public class LazyLoadingExceptionTest {

@Autowired UserRepository userRepository;

@Test(expected=LazyInitializationException.class)
public void showRolesTest() {
User whimusical = userRepository.findByUsername("Whimusical");
System.err.println(whimusical.getRoles());
}

}

但是如果您使用@DataJpaTest进行测试,您将不会得到异常

 @RunWith(SpringRunner.class)
@DataJpaTest
public class NoLazyLoadingExceptionTest {

@Autowired UserRepository userRepository;

@Test
public void showRolesTest() {
User whimusical = userRepository.findByUsername("Whimusical");;
System.err.println(whimusical.getRoles());
}
}

触发LazyInitializationException的另一种方式

覆盖UsertoString()

@Override
public String toString() {
return username + " with roles: " + roles;
}

并使用此组件启动应用程序

@Component
public class DataSetup implements CommandLineRunner{

@Override
public void run(String... args) throws Exception {
List<Role> roles = new ArrayList<>();

Role role = new Role();
role.setName("user");
roles.add(roleRepository.save(role));

User whimusical = new User();
whimusical.setUsername("Whimusical");
whimusical = userRepository.save(whimusical);

whimusical.setRoles(roles);
whimusical = userRepository.save(whimusical);

userRepository.findAll().forEach(System.err::println);
}
}

关于java - 在 ControllerTest 中使用 @WebAppConfiguration 而不是 @SpringBootTest 时,Spring Data JPA 中会忽略延迟初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50429722/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com