【问题标题】:Spring data JPA lazy loadingSpring数据JPA延迟加载
【发布时间】:2020-09-14 12:12:11
【问题描述】:

我对 Java Spring 非常陌生,我尝试了几天来让我的关系正常工作,但它没有。我正在使用 Java Spring 和 Mysql。

管理员应将员工添加到数据库。员工只会看到特定数据。我的问题是,我不明白如何从EmployeesController 发出正确的POST 请求并从用户模型中获取user_id。我尝试了一些不同的实现,但仍然无法正常工作。

我有一个用户、角色和员工实体。员工始终是用户,但用户可能不是员工。所以我的数据库结构如下:

用户:

+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| id       | int          | NO   | PRI | NULL    | auto_increment |
| username | varchar(30)  | NO   |     | NULL    |                |
| email    | varchar(100) | NO   |     | NULL    |                |
| password | varchar(100) | NO   |     | NULL    |              
+----------+--------------+------+-----+---------+----------------+

员工:

+-------------------+--------------+------+-----+---------+----------------+
| Field             | Type         | Null | Key | Default | Extra          |
+-------------------+--------------+------+-----+---------+----------------+
| id                | int          | NO   | PRI | NULL    | auto_increment |
| academic_title    | varchar(100) | NO   |     | NULL    |                |
| department        | varchar(100) | NO   |     | NULL    |                |
| user_id           | int          | NO   |     | NULL    |                |
+-------------------+--------------+------+-----+---------+----------------+

只有管理员可以将员工添加到系统中,员工只能登录并查看一些数据。因此,就像我在 Java 中所理解的那样,员工表中的 user_id 之类的 Spring 参数并没有额外写入模型中。所以这就是我现在所拥有的:

Employee.java

@Entity
@Table(name = "employees")
public class Employee{
  
    @OneToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Size(min=3, max = 100)
    private String academic_title;

    @Size(min=3, max = 100)
    private String department;

    public Employee() {}
 
    public Employee(String academic_title, String department) {
        super();
        this.academic_title = academic_title;
        this.department = department;
    }
    
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }

    public String getDepartment() {
        return department;
    }
 
    public void setDepartment(String department) {
        this.department = department;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

用户.java

@Entity
@Table(name = "users")
public class User{
  @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
  
    @NotBlank
    @Size(min=3, max = 50)
    private String username;
 
    @NaturalId
    @NotBlank
    @Size(max = 50)
    @Email
    private String email;
 
    @NotBlank
    @Size(min=6, max = 100)
    private String password;
 
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(name = "user_roles", 
      joinColumns = @JoinColumn(name = "user_id"), 
      inverseJoinColumns = @JoinColumn(name = "role_id"))
    private Set<Role> roles = new HashSet<>();

    @OneToOne(fetch = FetchType.LAZY,
            cascade =  CascadeType.ALL,
            mappedBy = "user")
    private Employee employee;
 
    public User() {}
 
    public User(String username, String email, String password) {
        super();
        this.username = username;
        this.email = email;
        this.password = password;
    }
 
    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 getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public Set<Role> getRoles() {
        return roles;
    }
 
    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
}

EmployeeController.java(创建Employee函数)

    public Employee createEmployee(@PathVariable (value = "user_id") Long user_id,
                                 @Valid @RequestBody Employee employee) {
                                     
        userRepository.findById(user_id);
        employeeRepository.save(employee);
        return employee;

    }

userRepository.java

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
    Optional<User> findById(Long id);
    Boolean existsByUsername(String username);
    Boolean existsByEmail(String email);
}

我的 Postman POST 请求添加员工:

{
    "academic_title": "xy",
    "department": "xx",
    "user_id": 5
}

当我尝试将 user_id 保存为普通的 Long 参数时,我可以将其保存到数据库中。但是当我获取现有员工时,join 函数不起作用,所以我看不到 user_id 5 是谁。 当我以另一种方式尝试时,就像上面的代码一样,我收到了如下错误:not-null property references a null or transient value 或类似的东西 Employee 列:user_id(应使用 insert="false" update="false" 映射)。所以我不知道该怎么办,我在这个问题上卡了 5 天。

提前感谢您的帮助!

【问题讨论】:

    标签: java mysql spring hibernate one-to-one


    【解决方案1】:

    如果您决定使用 Hibernate 和注释 @OneToOne 定义您的关系,您应该记住现在 Employee 有一个类属性(属性)User。而对于将员工表中的外键存储在用户表上,您需要将用户实例设置为员工。

    你应该在你的情况下尝试这样的事情:

    public Employee createEmployee(@PathVariable (value = "user_id") Long user_id,
                                 @Valid @RequestBody Employee employee) {
                                     
        // find user by id or else throw exception
        User userById = userRepository.findById(user_id).orElseThrow(() -> new 
        RuntimeException("Not found."));
        
        // set user into employee. it's like binding two entities
        employee.setUser(userById);
    
        // after that you can save your employee entity.
        return employeeRepository.save(employee);
        
    }
    

    【讨论】:

    • 谢谢。但是如果没有 Hibernate,我怎么能建立关系呢?我看到的所有示例都使用了 Hibernate。我试过你的代码,但我仍然收到这个错误:not-null property references a null or transient value
    • 您也可以使用 Spring Jdbc 或 Hibernate 或 Jooq 将数据库的表映射到 Java 的对象,这就是我的意思。
    • 那你的错误呢。从邮递员那里查看您的 json。它包含“user_id”,但您在上面代码的 createEmployee() 中将“user_id”声明为“@PathVariable”。您应该将该 ID 放在 url 中。现在你在正文中发送这个 id。
    • 我添加了@PostMapping("/addemployee")。那么你的意思是我需要制作 /addemployee/user_id 然后在 Postman 中使用 JSON user_id: 5 吗?我试过这样,它返回一个 404 not found 错误。我也试过 /addemployee/5 但它也返回同样的错误。
    • @Rosina 你不需要 set user_id: 5 in your json in postman) 只需这样注释控制器的方法:@PostMapping(“addemployee/{id}”) 和它。并且不要忘记在 url 路径中添加您的用户 ID。你最终会得到类似的东西:localhost:8080/addemployee/5 其中 5 是 user_id
    【解决方案2】:

    连接功能不起作用

    User 和 Employee 之间的获取类型是 Lazy。这意味着它在加载员工时实际上并没有加载用户。相反,它会在请求时加载它们。

    所以正如@Zooger 提到的,你应该先从数据库中加载用户。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-14
      • 2022-01-09
      • 2014-03-06
      • 2018-03-01
      • 2013-11-02
      • 2022-09-29
      • 2011-12-20
      • 2014-02-13
      相关资源
      最近更新 更多