背景:我有一个表有三个主键,实体类用@EmbeddedId来设置复合主键,现在就是有一个功能解析文件后插入数据库。有两个文件,两个文件内容完全一样。 然后循环之中,用一个事务platformTransactionManager去控制一个文件,即文件扫描完成后需要删除该主键下的数据,然后再插入数据,如果有一个地方出错就用事务手动回滚,这样就不影响下一个文件扫描。现在就是有一个情况,两个文件内容完全一样,扫描解析文件之后,会先删除相同主键下的数据,然后再插入文件内容数据。而上面说的执行完后,数据库为空,如果我debug第一个文件的comitt之后,是可以看到插入的数据的,而后执行完全一样的文件之后,就消失了。
实体类代码
@Data
@Entity
@Table(name = "report_ar")
public class ReportArRec {
@EmbeddedId
private ReportArId id;
@Column(name = "ric")
private String ric;
@Data
@Embeddable
public class ReportArId implements Serializable {
@Column(name = "serial_number")
private Integer serialNumber;
@Column(name = "stock_code")
private String stockCode;
@Column(name = "report_year")
private Integer reportYear;
@Column(name = "report_quarter")
private String reportQuarter;
下面是我的一个简化业务逻辑代码
for (MultipartFile file : files) {
if (!file.isEmpty()) {
TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
try{
deleteArResult = reportArRepository.deleteByCodeAndYearAndQuarter(reportBaseForm.getStockCode(), reportBaseForm.getReportYear(), reportBaseForm.getReportQuarter());
updateArResult = reportArRepository.saveAll(reportArRecs);
platformTransactionManager.commit(transactionStatus);
} catch (Exception e) {
platformTransactionManager.rollback(transactionStatus);
}
} else {
}
}
下面是我的dao方法库:
@Repository
public interface ReportArRepository extends JpaRepository<ReportArRec, ReportArId>, JpaSpecificationExecutor<ReportArRec> {
@Transactional
@Modifying
@Query("DELETE FROM ReportArRec r WHERE r.id.stockCode = :stockCode AND r.id.reportYear = :reportYear AND r.id.reportQuarter = :reportQuarter")
int deleteByCodeAndYearAndQuarter(@Param("stockCode") String stockCode, @Param("reportYear") Integer reportYear, @Param("reportQuarter") String reportQuarter);
@Transactional
int deleteByIdStockCodeAndIdReportYearAndIdReportQuarter(String stockCode, Integer reportYear, String reportQuarter);
}
总结:当我把删除的方法写成deleteByCodeAndYearAndQuarter这种@Query sql的方式删除时,会出现数据消失的问题,比如,第一个文件commit之后我能在数据库看到数据,继续执行下去,delete之前可以看到数据库有数据,delete之后数据库没有数据了,说明delete是生效的了,但是!saveall之后再打印findall还是空数据,有可能是saveall以为数据库还有数据就不操作了,但是有相同的话应该是更新才对。反正就是deleteByCodeAndYearAndQuarter这种删除有点像假删除,迷惑了saveall这边的操作。而当我尝试性使用jpa方法名查询的方式时,比如deleteByIdStockCodeAndIdReportYearAndIdReportQuarter,前面的问题都解决。虽然都解决了,但我很想知道该怎么排查深层的问题,有点不明所以,所以想问问有没有大佬知道上面这两个删除的区别。这个问题是真滴奇怪,还好有人用了方法名查询这种方法,不然我都不会怀疑到这个删除身上