【问题标题】:spring data JPA - mysql - findById() empty unless findAll() called beforespring data JPA - mysql - findById() 为空,除非 findAll() 之前调用过
【发布时间】:2020-01-07 17:45:32
【问题描述】:

我正在努力解决这个奇怪的错误:CrudRepositoryfindById() 方法返回 Optional.empty,除非在使用 mysql 时之前调用了 findAll()

例如

用户

@Entity
public class User {

    @Id
    @GeneratedValue
    private UUID id;

    public UUID getId() {
        return id;
    }

}

用户存储库

public interface UserRepository extends CrudRepository<User, UUID> { }

用户服务

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public UUID create() {
        final User user = new User();
        userRepository.save(user);
        return user.getId();
    }

    @Transactional
    public User find(@PathVariable UUID userId) {
        // userRepository.findAll(); TODO without this functin call, Optinoal.empty is returned by the repo
        return userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException(String.format("missing user:%s", userId)));
    }
}

用户应用

@SpringBootApplication
public class UserApp {

    private static final Logger LOG = LoggerFactory.getLogger(UserApp.class);

    @Autowired
    private UserService userService;

    @EventListener
    public void onApplicationEvent(ContextRefreshedEvent event) {
        final UUID userId = userService.create();
        final User user = userService.find(userId);
        LOG.info("found user: {}", user.getId());
    }

    public static void main(String[] args) {
        SpringApplication.run(UserApp.class, args);
    }

}

application.properties

spring.datasource.url=jdbc:mysql://localhost:3306/db_test
spring.datasource.username=springuser
spring.datasource.password=ThePassword

spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.database=mysql

为什么findAll()方法调用会改变findById()的结果?

编辑:带有findAll 的休眠日志:

Hibernate: drop table if exists user
Hibernate: create table user (id binary(255) not null, primary key (id)) engine=MyISAM
Hibernate: insert into user (id) values (?)
Hibernate: select user0_.id as id1_0_ from user user0_

没有:

Hibernate: drop table if exists user
Hibernate: create table user (id binary(255) not null, primary key (id)) engine=MyISAM
Hibernate: insert into user (id) values (?)
Hibernate: select user0_.id as id1_0_0_ from user user0_ where user0_.id=?

【问题讨论】:

  • 我无法给出明确的答案,但这可能与 Hibernates 缓存和 findAll 触发刷新有关。您能否发布针对这两种变体执行的 SQL 语句?
  • 我的问题所附的日志。
  • 嗨,我也面临同样的问题。你找到解决问题的方法了吗?谢谢。
  • 嘿,你找到答案了吗?我也面临同样的问题
  • @MHogge 你找到解决方案了吗?

标签: mysql spring spring-data-jpa spring-data


【解决方案1】:

我也面临同样的问题。根本原因是不可为空的@ManyToOne 关系与表中保留的数据不匹配。 我有这个:

@ManyToOne(optional = false)
  @JoinColumn(name="batch_id")
  private Batch batch;

这意味着 batch_id 在任何行中都不能为空。但是,我的行对 batch_id 外键有空值。删除 optional = false(这是预期的业务规则)后,findById 开始按预期工作。

从这个帖子得到指示:I tired to do something with JpaRepository But Can not find row with findById ,

【讨论】:

  • 对我来说这是同一个根本原因!我有一个@JoinColumn(name = "voucher_id", nullable = false),但在voucher_id 列中使用null 值保留了实体。删除非空约束后,一切都按预期工作了!
【解决方案2】:

正如之前(但更笼统地)在一些测试之后已经写过的那样,我的结论是,当@ManyToOne 关系中的必填字段和数据库数据存在差异时,就会出现问题。例如,假设有一个没有强制字段约束的表,但同时您的 Hibernate 模型类具有 @ManyToOne(optional = false) 约束。并想象填充表(例如使用 SQL 脚本),将指示字段保留为 null。当您尝试执行 findById()deleteById 或任何暗示按 ID 获取的操作时,您会遇到这种情况(可怕)副作用。

【讨论】:

    【解决方案3】:

    尝试使用下面的代码;

    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Type(type="uuid-char")
    private UUID id;
    

    【讨论】:

      猜你喜欢
      • 2023-03-12
      • 2022-07-21
      • 1970-01-01
      • 1970-01-01
      • 2018-01-02
      • 1970-01-01
      • 2018-06-15
      • 1970-01-01
      • 2019-05-19
      相关资源
      最近更新 更多