【问题标题】:JpaRepository findAll returns empty ListJpaRepository findAll 返回空列表
【发布时间】:2019-05-30 02:59:39
【问题描述】:

JpaRepository 中的findAll() 方法返回空值,但空值的数量正确

我正在使用 h2 数据库,并且在某个未知时刻之前一切正常。 http://localhost:8080/users 的简单 GET 返回 {} x 先前添加到数据库的用户数。我尝试实现一种基于用户名返回 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() 也不起作用,但那是其他时间。

编辑:你要求的一些 ov 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的?您也可以为该类添加代码吗?
  • @AmitNaik Spring Data 自动提供实现。
  • Filip,这是一个附带问题,但您有一些样式问题需要纠正。避免使用optional.get();您的整个方法可以替换为return repository.findById(id).getOrElse(null);。同样,如果您无论如何都要抛出异常,执行显式空检查通常被认为是嘈杂且无益的;如果你真的想,请使用Objects.requireNonNull(user.getUsername())
  • @chrylis 我知道希望没有为findAll 添加实现。只是为了清除它,这里没有任何假设
  • 你能提供你完整的Controller和Repository代码sn-p吗?

标签: java maven spring-boot httprequest


【解决方案1】:

问题是您的属性不是可变的。您已经公开了 getter 和 setter,但您没有指定访问级别,并且默认情况下它们不是 public,因此 hibernate 看不到它们,因此无法使用从数据库返回的记录填充您的实体.将它们公开应该可以解决问题。

【讨论】:

  • Hibernate 和 HttpMessageConverters 看不到返回 { } 的属性,否则 { "id" : null , "username" : null} 会返回。所以在实体类中设置Getters和Setterspublic应该可以解决这个问题
  • 当然,你提到了Hibernate,我也只是添加了空json对象的原因
  • 谢谢! IDE(IntelliJ Idea)建议 getter 和 setter 可以是包私有的,所以我将它们设为包私有。
  • IntelliJ 通常会尝试变得比实际更聪明:)
  • 谢谢。在实体类中,我将private int id; 更改为public int id;,现在我得到了想要的响应。
【解决方案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) 解决了这个问题。

【讨论】:

    猜你喜欢
    • 2017-08-25
    • 2021-05-20
    • 2020-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多