Hibernate @Transactional如何在测试方法上工作?
我想知道@Transactional如何在测试方法上与Spring数据JPA/Hibernate一起工作。我在网上搜索了一些解释,但似乎还是不太清楚 下面是我正在使用的代码: Member.javaHibernate @Transactional如何在测试方法上工作?,hibernate,jpa,junit,transactions,jta,Hibernate,Jpa,Junit,Transactions,Jta,我想知道@Transactional如何在测试方法上与Spring数据JPA/Hibernate一起工作。我在网上搜索了一些解释,但似乎还是不太清楚 下面是我正在使用的代码: Member.java 问题是,当我单独使用@Transactional而不使用@Commit时,只会创建用户和角色条目。表MEMBER\u ROLE已创建但为空(无条目):未保存n:n@ManyToMany单向关系 使用@Commit时,一切正常:有两个条目对应于John Doe用户的角色 以下是我的问题: cru
- 问题是,当我单独使用@Transactional而不使用@Commit时,只会创建用户和角色条目。表
已创建但为空(无条目):未保存MEMBER\u ROLE
@ManyToMany单向关系n:n
- 使用
时,一切正常:有两个条目对应于John Doe用户的角色@Commit
@Commit
就不会向数据库提交任何内容(所有内容都是回滚的)。
在测试方法上使用@Transactional
是否是一种良好的做法?
Crudepository.save(…)如何在@Transactional的后台工作,以及为什么单独使用此注释会执行“部分保存”?我们应该预期,如果没有@Commit,就不会向数据库提交任何内容(并且所有内容都是回滚的)
由于它是一个测试,默认情况下,由于TransactionalTestExecutionListener
,事务应该回滚。现在,您会问为什么会提交某些内容,这可能是因为内部事务@Transactional
跨越整个测试方法的事务,因此如果您使用某些dao(如您的案例),该事务也将回滚,但是如果某些方法使用除REQUIRED
之外的事务传播类型,例如REQUIRED\u NEW
,则仍可以执行对db的调用,因为REQUIRED\u NEW
暂停测试中的当前事务并创建一个新事务。新的一个将被承诺。由于hibernate缓存,还存在刷新时间问题——他在事务结束时(通常在方法结束时)调用db,因此在持久化元素后直接获取元素可能会失败。这两件事都很棘手
在测试方法上使用@Transactional是一种好的实践吗
当然,但不是为了测试事务边界。请记住,您还可以使用@DataJpaTest
,它为每个测试方法放置@Transactional
资料来源:
我从来没有在测试方法上使用过Transaction,一直以来,我都是在服务类测试类中使用它,以正常的方式初始化数据,执行测试,并回滚数据更改,以提供测试数据集的原始数据,从而确保在每次测试用例运行后都不会修改任何数据。使下一个测试用例不会受到上一个测试用例的影响,并且每次测试都会以相同的结果运行。
@Entity
@Table(name = "MEMBER")
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
String firstname;
String lastname;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
name = "MEMBER_ROLE",
joinColumns = @JoinColumn(name = "member_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<Role>();
// Getters...
// Setters...
}
@Entity
@Table(name = "ROLE")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private String description;
public Role(String name, String description) {
this.name = name;
this.description = description;
}
@ManyToMany(mappedBy = "roles", cascade = CascadeType.ALL)
private Set<User> users = new HashSet<User>();
public void addUser(User user) {
users.add(user);
user.getRoles().add(this);
}
// Getters...
// Setters...
}
@SpringBootTest
public class MemberRepositoryTest {
@Autowired
private MemberRepository memberRepository;
@Test
@Transactional
//@Commit // When @Commit is uncommented, the relation is saved in the database
public void testSave() {
Member testMember = new Member();
testMember.setFirstname("John");
testMember.setLastname("Doe");
Role role1 = new Role("ROLE_USER", "The role of for basic users");
Role role2 = new Role("ROLE_ADMIN", "The role of for admin users");
testMember.getRoles().add(role1);
testMember.getRoles().add(role2);
this.memberRepository.save(testMember);
// The 2 roles are well in the set
System.out.println("********" + this.memberRepository.findById(1).get().getRoles().toString());
}
}