如何在Room DB中处理多个数据库版本

问题描述

如何在Room DB中处理多个数据库版本迁移
我无法管理多个版本的数据库

解决方法

  1. 每个迁移都有开始和结束版本,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。