Hibernate ManyToMany 和 Transactional 注释
Hibernate ManyToMany and Transactional annotation
我尝试使用 jUnit 和集成测试来测试我的@Repository 层。在我的实体 classes 中,我使用 @ManyToMany 双向注解。我的测试 class 我已经用 @Transactional 注释了。当我在关系的父端执行持久化方法时,用户对象和角色被插入到数据库中,但在连接 table 中没有关系。当我将@Transactional 注释移动到@Repository class 时,一切正常。也许有人可以向我解释当@Transactional 注释在测试时它不起作用的原因是什么 class?
用户实体:
@Table(name = "users")
@Entity
public class User extends BaseEntity {
...
@ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
@JoinTable(
name = "users_roles",
joinColumns = { @JoinColumn(name = "user_id") },
inverseJoinColumns = { @JoinColumn(name = "role_id") }
)
private Set<Role> roles;
.. getters and setters
public void addRole(Role role) {
this.getRoles().add(role);
role.getUsers().add(this);
}
public Set<Role> getRoles() {
if (this.roles == null) {
this.roles = new HashSet<>();
}
return this.roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
角色实体
@Table(name = "roles")
@Entity
public class Role extends BaseEntity {
public enum UserRole {
ADMIN, USER
}
@Enumerated(EnumType.STRING)
@Column(name="role")
private UserRole role;
@ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER,cascade = CascadeType.ALL)
private Set<User> users;
... getters and setters
}
测试class:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MysqlPersistanceConfig.class})
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Transactional
public class UserRepositoryIT {
@Autowired
private UserRepository userRepository;
@Test
public void stage10_saveOneUserAndCheckIfWasSavedTest() {
User user = new User();
user.setName("admin");
user.setPassword("root");
Role role1 = new Role(UserRole.USER);
Role role2 = new Role(UserRole.ADMIN);
user.addRole(role1);
user.addRole(role2);
Assert.assertTrue(role1.getUsers().size() == 1);
Assert.assertTrue(role2.getUsers().size() == 1);
Assert.assertTrue(user.getRoles().size() == 2);
userRepository.save(user);
Assert.assertEquals(user, userRepository.find(1));
Assert.assertEquals(user, userRepository.findByName("admin"));
Assert.assertEquals(2, userRepository.findByName("admin").getRoles().size());
}
}
DAO 层:
@Repository
//@Transactional
public class UserRepositoryImpl implements UserRepository {
@PersistenceContext
private EntityManager manager;
@Override
public void save(User user) {
if(user.isNew()) {
manager.persist(user);
} else {
manager.merge(user);
}
}
@Override
public User find(int id) {
return manager.find(User.class, id);
}
@Override
public User findByName(String name) {
String queryString = "SELECT u FROM User u WHERE u.name = :name";
Query query = manager.createQuery(queryString);
query.setParameter("name", name);
return (User) query.getSingleResult();
}
}
Spring 的 JUnit 默认回滚跨越测试方法的事务。如果要检查它,请在测试中使用 EntityManager manager
并调用 manager.flush()
或将 @Rollback(false)
添加到测试方法中。
我尝试使用 jUnit 和集成测试来测试我的@Repository 层。在我的实体 classes 中,我使用 @ManyToMany 双向注解。我的测试 class 我已经用 @Transactional 注释了。当我在关系的父端执行持久化方法时,用户对象和角色被插入到数据库中,但在连接 table 中没有关系。当我将@Transactional 注释移动到@Repository class 时,一切正常。也许有人可以向我解释当@Transactional 注释在测试时它不起作用的原因是什么 class?
用户实体:
@Table(name = "users")
@Entity
public class User extends BaseEntity {
...
@ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
@JoinTable(
name = "users_roles",
joinColumns = { @JoinColumn(name = "user_id") },
inverseJoinColumns = { @JoinColumn(name = "role_id") }
)
private Set<Role> roles;
.. getters and setters
public void addRole(Role role) {
this.getRoles().add(role);
role.getUsers().add(this);
}
public Set<Role> getRoles() {
if (this.roles == null) {
this.roles = new HashSet<>();
}
return this.roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
角色实体
@Table(name = "roles")
@Entity
public class Role extends BaseEntity {
public enum UserRole {
ADMIN, USER
}
@Enumerated(EnumType.STRING)
@Column(name="role")
private UserRole role;
@ManyToMany(mappedBy = "roles", fetch = FetchType.EAGER,cascade = CascadeType.ALL)
private Set<User> users;
... getters and setters
}
测试class:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MysqlPersistanceConfig.class})
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Transactional
public class UserRepositoryIT {
@Autowired
private UserRepository userRepository;
@Test
public void stage10_saveOneUserAndCheckIfWasSavedTest() {
User user = new User();
user.setName("admin");
user.setPassword("root");
Role role1 = new Role(UserRole.USER);
Role role2 = new Role(UserRole.ADMIN);
user.addRole(role1);
user.addRole(role2);
Assert.assertTrue(role1.getUsers().size() == 1);
Assert.assertTrue(role2.getUsers().size() == 1);
Assert.assertTrue(user.getRoles().size() == 2);
userRepository.save(user);
Assert.assertEquals(user, userRepository.find(1));
Assert.assertEquals(user, userRepository.findByName("admin"));
Assert.assertEquals(2, userRepository.findByName("admin").getRoles().size());
}
}
DAO 层:
@Repository
//@Transactional
public class UserRepositoryImpl implements UserRepository {
@PersistenceContext
private EntityManager manager;
@Override
public void save(User user) {
if(user.isNew()) {
manager.persist(user);
} else {
manager.merge(user);
}
}
@Override
public User find(int id) {
return manager.find(User.class, id);
}
@Override
public User findByName(String name) {
String queryString = "SELECT u FROM User u WHERE u.name = :name";
Query query = manager.createQuery(queryString);
query.setParameter("name", name);
return (User) query.getSingleResult();
}
}
Spring 的 JUnit 默认回滚跨越测试方法的事务。如果要检查它,请在测试中使用 EntityManager manager
并调用 manager.flush()
或将 @Rollback(false)
添加到测试方法中。