问题描述
如何在Room DB中处理多个数据库版本迁移
我无法管理多个版本的数据库。
解决方法
- 每个迁移都有开始和结束版本,Room会运行这些迁移以带来 数据库到最新版本。
Caused by: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.bookstore.domain.security.UserRole.role -> com.bookstore.domain.security.Role
@Entity
public class User implements UserDetails,Serializable {
private static final long serialVersionUID=157954L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "Id",nullable = false,updatable = false)
private Long id;
private String userName;
private String password;
private String firstName;
private String lastName;
private String email;
private String phone;
private boolean enabled;
@OneToMany(mappedBy = "user",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@JsonIgnore
private Set<UserRole> userRoles=new HashSet<UserRole>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities=new HashSet<GrantedAuthority>();
userRoles.forEach(userRole->{
authorities.add(new Authority(userRole.getRole().getRoleName()));
});
return authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
@Override
public String getUsername() {
return userName;
}
}
@Entity
public class Role implements Serializable{
private static final long serialVersionUID=68678L;
@Id
private Long roleId;
private String roleName;
@OneToMany(mappedBy = "role",fetch = FetchType.LAZY)
@JsonIgnore
private Set<UserRole> userRoles=new HashSet<UserRole>();
public Role() {
}
public Long getRoleId() {
return roleId;
}
public void setRoleId(Long roleId) {
this.roleId = roleId;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
}
@Entity
public class UserRole implements Serializable {
private static final long serialVersionUID=456874L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long userRoleId;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "roleId")
private Role role;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "userId")
private User user;
public UserRole(User user,Role role) {
this.role = role;
this.user = user;
}
public UserRole() {
super();
}
public Long getUserRoleId() {
return userRoleId;
}
public void setUserRoleId(Long userRoleId) {
this.userRoleId = userRoleId;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
@Service
public class UserServiceImpl implements UserService {
private static final Logger LOG=LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
@Transactional
@Override
public User CreateUser(User user,Set<UserRole> userRoles) {
User localUser=userRepository.findByUserName(user.getUserName());
if(localUser!=null) {
LOG.warn("Username {} already exists",user.getUserName());
}
else {
for(UserRole userRole:userRoles) {
roleRepository.save(userRole.getRole());
LOG.error("inside for {}",userRole.getRole().getRoleName());
}
user.getUserRoles().addAll(userRoles);
localUser=userRepository.save(user);
}
return localUser;
}
}
@SpringBootApplication
public class BookStoreApplication implements CommandLineRunner {
@Autowired
UserService userService;
public static void main(String[] args) {
SpringApplication.run(BookStoreApplication.class,args);
}
@Override
public void run(String... args) throws Exception {
User user1=new User();
user1.setUserName("test");
user1.setPassword(SecurityUtility.passwordEncoder().encode("test"));
user1.setEmail("[email protected]");
user1.setEnabled(true);
user1.setFirstName("testFirstName");
user1.setLastName("testLastName");
user1.setPhone("123456789");
Role role1=new Role();
role1.setRoleId((long)1);
role1.setRoleName("ROLE_USER");
UserRole userRole1=new
UserRole(user1,role1);
Set<UserRole> userRoles1=new HashSet<UserRole>();
userRoles1.add(userRole1);
userService.CreateUser(user1,userRoles1);
User user2=new User();
user2.setUserName("admin");
user2.setPassword(SecurityUtility.passwordEncoder().encode("admin"));
user2.setEmail("[email protected]");
user2.setEnabled(true);
user2.setFirstName("adminFirstName");
user2.setLastName("adminLastName");
user2.setPhone("223456789");
Role role2=new Role();
role2.setRoleId((long) 2);
role2.setRoleName("ROLE_ADMIN");
UserRole userRole2=new UserRole(user2,role2);
Set<UserRole> userRoles2=new HashSet<UserRole>();
userRoles2.add(userRole2);
userService.CreateUser(user2,userRoles2);
}
}
2. 迁移可以处理多个版本
(例如,如果您有更快的路径来选择何时
将版本3升级到5,而无需将版本4升级)。
如果Room打开版本为的数据库
3,最新版本为> = 5,
房间将使用可从中进行迁移的迁移对象
3到5,而不是3到4和4到5。