【问题标题】:Spring Data JPA strange behaviorSpring Data JPA 奇怪的行为
【发布时间】:2018-01-26 12:43:26
【问题描述】:

我是 JPA 和 Hibernate 的新手,遇到了奇怪的行为。考虑下面的代码。

License实体:

@Entity
@Data
public class License {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Enumerated(EnumType.STRING)
    private LicenseType type;
    @Column(unique = true)
    private String activationKey;
    @OneToMany(mappedBy = "id", cascade = CascadeType.REMOVE)
    private List<Payment> payments = new ArrayList<>();
    private long productId;
    private String productName;
    private long term;
    private long creationTimestamp;
    private boolean active;
}

LicenceType 枚举:

public enum LicenseType {
    NAMED
}

Payment实体:

@Entity
@Data
public class Payment {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH})
    private License license;
    private BigDecimal sum;
}

LicenceRepository:

@Repository
public interface LicenseRepository extends CrudRepository<License, Long> {

}

PaymentRepository:

@Repository
public interface PaymentRepository extends CrudRepository<Payment, Long> {

}

引导类:

@SpringBootApplication
public class LsPocApplication {

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

    @Bean
    public CommandLineRunner demo(LicenseRepository licenseRepository, PaymentRepository paymentRepository) {
        return (args) -> {

            License license = new License();
            license.setActivationKey(UUID.randomUUID().toString());

            Payment payment = new Payment();
            payment.setSum(BigDecimal.valueOf(new Random().nextDouble()));
            payment.setLicense(license);

            paymentRepository.save(payment);

            // licenseRepository.delete(license); // This does nothing
            // licenseRepository.delete(license.getId()); // This deletes both licence and associated payment(s)
        };
    }
}

所以问题是为什么licenseRepository.delete(license.getId()) 按预期工作,但licenseRepository.delete(license) 什么都不做?我假设,它们在逻辑上是等价的。还是我错了?

请指教。

提前致谢!

【问题讨论】:

  • 如果您将 License id 从原始 long 更改为 Long 类,也会发生同样的情况吗?
  • @arocketman 是的
  • @alxg2112 尝试从关系映射中删除级联并检查它。
  • @chŝdk 没有级联,一切正常。为什么这对他们不起作用,这就是问题......
  • @alxg2112 当您删除 Cascade 时它会起作用,但为什么呢?老实说我不知道​​,我已经在网上挖了一段时间了,我还没有找到答案,请查看this thread 以供参考。

标签: java spring hibernate spring-data-jpa


【解决方案1】:

您的许可证是否实现了可序列化?如果是这样,我认为这两个调用都将调用相同的方法,即用于 id 参数的方法。但是由于没有许可证有另一个许可证作为 id,因此没有任何内容被删除。

原因是在类型擦除之后,好的泛型剩下的所有内容都是 Serializable 用于 id 和 Object 用于实体类型。如果实体类型也恰好实现了Serializable,则使用该方法,因为它更具体。 (我不得不承认我的脑子里有一些挥手的动作,但这个想法应该是正确的)。

这就是为什么从 Spring Data 2.0(又名 Kay)开始改变方法名称的原因,所以这种混乱不再发生。

【讨论】:

  • 这是一个非常有价值的评论,但License 没有实现Serializable,所以我认为不应该有任何歧义。
  • 我已经调试了我的代码,结果证明你是绝对正确的!尽管License 出于某种原因没有实现Serializable,但licenseRepository.delete(license)licenseRepository.delete(license.getId()) 调用都会在JdkDynamicAopProxy.java 类中调用相同的方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
【解决方案2】:

看起来像 Payment 实体使用合并保存到数据库。所以 License 没有添加到会话中,因此 licenseRepository.delete(license) 不起作用。

尝试在 Payment 类中更改此行:

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.REFRESH})
private License license;

@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private License license;

【讨论】:

  • 不正确。不会改变任何东西
猜你喜欢
  • 2019-10-04
  • 2016-04-14
  • 1970-01-01
  • 2015-04-11
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 2014-08-21
  • 1970-01-01
相关资源
最近更新 更多