JpaRepository的findAll方法返回空列表

7

JpaRepositoryfindAll() 方法返回了空值,但是正确数量的空值。

我正在使用 h2 数据库,一切都正常工作,直到某个未知的时刻。在 http://localhost:8080/users 上进行简单的 GET 请求会返回 {}(空对象)和先前添加到数据库中的用户数。我尝试实现一个根据用户名返回 id 的方法,并且这个方法也完全正常工作。

下面是我的 User.java

@Entity
@Table(name = "Users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "username")
    @NotBlank(message = "Username is mandatory")
    @Size(min = 1, max = 20, message = "Username must be less than 20 characters long")
    private String username;
    @Column(name = "balance")
    private Double balance = 0.0;

    Long getId() {
        return id;
    }

    void setId(Long id) {
        this.id = id;
    }

    String getUsername() {
        return username;
    }

    void setUsername(String username) {
        this.username = username;
    }

    Double getBalance() {
        return balance;
    }

    void setBalance(Double balance) {
        this.balance = balance;
    }
}

这里是UserService,它实现了IUserService的方法:

@Service
public class UserService implements IUserService {

    @Autowired
    private UserRepository repository;

    @Override
    public void createNewUser(User user) {
        repository.save(user);
    }

    @Override
    public List<User> findAll() {
        return repository.findAll();
    }

    @Override
    public Long findByUsername(String username) {
        return repository.findByUsername(username);
    }

    @Override
    public User findById(Long id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public boolean checkIfUsernameIsTaken(User user) {
        return repository.findByUsername(user.getUsername()) != null;
    }

    @Override
    public void deleteUser(Long id) {
        repository.deleteById(id);
    }

    @Override
    public void updateBalance(Long id, Double balance) {
        repository.updateBalance(id, balance);
    }
}

我尝试使用和不使用@Column注释,但似乎没有产生任何作用。
如果我仅通过createNewUser()添加一个用户,则Postman返回的输出是[{}],如果我添加了两个用户,则返回[{},{​​}]​​,以此类推。我不理解是什么导致了findAll()方法出现问题。
另外,updateBalance()也无法正常工作,但这是另一个时间再处理。
编辑:一些人要求查看UserController代码。
@RestController
public class UserController {

    @Autowired
    IUserService userService;

    @GetMapping("/users")
    public List<User> findUsers() {
        return userService.findAll();
    }

    @GetMapping("/users/{id}")
    public User findUserById(@PathVariable Long id) {
        return userService.findById(id);
    }

    @PostMapping("/users")
    public ResponseEntity<Object> createUser(@RequestBody User user) {

        if (userService.checkIfUsernameIsTaken(user)) {

            Map<String, Object> response = new HashMap<>();
            response.put("status", HttpStatus.NOT_ACCEPTABLE);
            response.put("errors", "Username is already taken");
            response.put("timestamp", new Date());

            return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
        } else {
            userService.createNewUser(user);
            User currentUser = userService.findById(userService.findByUsername(user.getUsername()));
            Map<String, Object> response = new HashMap<>();
            response.put("id", currentUser.getId());
            response.put("username", currentUser.getUsername());
            response.put("balance", currentUser.getBalance());
            return new ResponseEntity<>(response, HttpStatus.OK);
        }
    }

    @DeleteMapping("/users/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }

    @PutMapping("/users/{id}/{balance}")
    public void updateBalance(@PathVariable Long id, @PathVariable Double balance) {
        userService.updateBalance(id, balance);
    }
}

以及 UserRepository

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT id FROM User WHERE username = ?1")
    Long findByUsername(String username);

    @Transactional
    @Modifying
    @Query("UPDATE User SET balance = ?2 WHERE id = ?1")
    void updateBalance(Long id, Double balance);
}

据我所知,我的问题最初出现在我实现更新查询之后,但我尝试运行另一台计算机上已知可行的版本,但仍然无法正常工作。


你是如何实现你的 UserRepository 的?你能同时添加这个类的代码吗? - Amit Naik
Spring Data 提供自动实现。 - chrylis -cautiouslyoptimistic-
Filip,这是一个次要问题,但你有一些应该纠正的风格问题。避免使用optional.get();整个方法可以被替换为return repository.findById(id).getOrElse(null);。同样地,如果你打算抛出异常,那么执行显式的空检查通常被认为是嘈杂和无用的;如果你真的想这样做,使用Objects.requireNonNull(user.getUsername()) - chrylis -cautiouslyoptimistic-
@chrylis 我知道希望没有添加findAll的实现。只是为了澄清一下,不要有任何假设。 - Amit Naik
请提供您完整的Controller和Repository代码片段。 - DEBENDRA DHINDA
你是否像这样使用你的仓库代码:UserRepository extends JpaRepository<User, Long> - corroborator
2个回答

9
问题是你的属性不可变。你已经公开了getter和setter,但是你没有指定访问级别,它们默认不是公共的,因此Hibernate无法看到它们,也无法使用来自数据库返回的记录填充实体。将它们设为公共的应该可以解决这个问题。

Hibernate和HttpMessageConverters无法看到属性,因此返回{ }。否则,将返回{"id": null, "username": null}。因此,在实体类中使Getter和Setter变为public可以解决此问题。 - Jebil
当然,你提到了Hibernate,我只是补充了空JSON对象的原因。 - Jebil
谢谢!IDE(IntelliJ Idea)建议将getter和setter设置为包私有,因此我将它们设置为包私有。 - Filip Pranklin
往往,IntelliJ试图比它实际上更聪明 :) - NiVeR
谢谢。在实体类中,我将 private int id; 改为 public int id;,现在我得到了期望的响应。 - Jay Teli

2
尽管上述答案解决了问题,但我遇到了类似的情况,其中repository.findById(id)会返回结果,而repository.findAll()会返回空值。
事实证明,我已经用@Transactional(readOnly = true)包装了调用者方法,在该方法中将写入并读取所有记录。
@Override
    @Transactional(readOnly = true)
    public List<Object> writeThenReadAll(...){
       repository.save(...);
       ...
       Object byId = repository.findById(1L).get(); //not null
       List<Object> all = repository.findAll(); //returns empty
       return all;
    }

@Transactional(readOnly = true)更改为@Transactional(readOnly = false)解决了此问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接