我不明白为什么我的体重记录存储库没有被调用,尽管我的代码。我写了一些日志之前和之后的体重记录存储库调用。在我的控制台,我可以看到日志之前和之后被调用,但不是我的存储库。我有一个代码200 OK,但在我的数据库,我的数据总是在这里。我不明白为什么。我的Tomcat端口被设置为端口7777。我可以创建和读取数据,但不能删除它。
就在我的代码下面:实体、控制器、存储库和服务。
https://gitlab.com/genetquentin/openweighttracker_backend/-/tree/develop
/*ENTITY 'PERSON'*/
@Entity
@Table(name = "person")
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_person")
private Long idPerson;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "id_initial_data")
private InitialData userInitData;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "id_user")
private AppUser appUserPerson;
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
private List<WeightRecord> weightsList = new ArrayList<WeightRecord>();
/* Getters and setters */
/*ENTITY 'WEIGHTRECORD'*/
@Entity
@Table(name = "weight_record")
public class WeightRecord implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id_weight_record")
private Long idWeightRecord;
@Column(name = "weight_record_date", nullable = true)
private LocalDate weightRecordDate;
//JsonIgnore annotation because circular problem with Jackson and entity.
@JsonIgnore
@ManyToOne
private Person person;
@Min(1)
@Max(635)
@Column(name = "weight_kg_record", nullable = true, precision = 1)
private Double weightKgRecord;
@Min(1)
@Max(99)
@Column(name = "percent_fat_mass", nullable = true, precision = 1)
private Double percentFatMass;
@Min(1)
@Max(99)
@Column(name = "percent_muscular_mass", nullable = true, precision = 1)
private Double percentMuscularMass;
@Min(1)
@Max(99)
@Column(name = "percent_body_water", nullable = true, precision = 1)
private Double percentBodyWater;
@Min(1)
@Max(99)
@Column(name = "percent_bone_mass", nullable = true, precision = 1)
private Double percentBoneMass
/* Getters and setters */
/*CONTROLLER*/
@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/weights")
public class WeightRecordController {
@Autowired
WeightRecordServiceImpl weightRecordServiceImpl;
@Autowired
WeightRecordRepository weightRecordRepository;
@Autowired
AppUserRepository appUserRepository;
@Autowired
PersonRepository personRepository;
private final Logger logger = LoggerFactory.getLogger(WeightRecordController.class);
//TODO : Weight is not deleted and repository not called ?
// USE deleteinbatch method repository from jpa ?
@DeleteMapping("/{weightId}")
public ResponseEntity<WeightRecord> deleteWeigthById(@PathVariable("weightId") Long weightId, Principal principal) {
logger.info("DELETE /weights/{}", weightId);
try {
Long appUserConnectedId = this.getAppUserConnectedId(principal);
Person personConnected = personRepository.findById(appUserConnectedId).orElseThrow();
WeightRecord weightRecordToDelete = weightRecordRepository.findById(weightId).orElseThrow();
if(personConnected != null && personConnected.getWeightsList().contains(weightRecordToDelete)) {
logger.info("SERVICE FOR DELETING");
logger.info(weightRecordToDelete.getWeightKgRecord().toString());
return ResponseEntity.ok(weightRecordServiceImpl.deleteWeightById(weightId));
} else {
logger.info("BAD USER FOR BAD WEIGHT");
return ResponseEntity.notFound().build();
}
} catch (NoSuchElementException nse) {
return ResponseEntity.notFound().build();
}
}
}
/*REPOSITORY*/
@Repository
public interface WeightRecordRepository extends JpaRepository<WeightRecord, Long> {
}
/*SERVICE*/
@Service
public class WeightRecordServiceImpl implements WeightRecordService {
@Autowired
WeightRecordRepository weightRecordRepository;
@Autowired
AppUserRepository appUserRepository;
@Autowired
PersonRepository personRepository;
private final Logger logger = LoggerFactory.getLogger(WeightRecordServiceImpl.class);
public WeightRecord deleteWeightById(Long weightRecordToDeleteId) {
logger.info("THIS IS THE WEIGHT ID TO DELETE : {}", weightRecordToDeleteId);
WeightRecord weightRecordToDelete = weightRecordRepository.findById(weightRecordToDeleteId).orElseThrow();
weightRecordRepository.deleteById(weightRecordToDeleteId);
logger.info("Weight with id n°{} is deleted now", weightRecordToDelete.getIdWeightRecord());
return weightRecordToDelete;
}
我在《失眠》中的请求:
控制台中的请求结果:
2条答案
按热度按时间uhry853o1#
"原因"
问题的原因是这部分代码
"为什么会这样“
有一个spring数据属性
spring.jpa.open-in-view
,默认为true
,表示在整个HTTP请求过程中JPA Persistent Context(Hibernate Session)是打开的。What is this spring.jpa.open-in-view=true property in Spring Boot?如果打开了Persistent Context,则下面代码中的
fetch = FetchType.LAZY
属性根本不起作用。当您执行
personConnected.getWeightsList().conatins()
时,Hibernate会在后台加载weightsList
,这就是为什么会记录最后一个SQL日志条目。所以当你删除一个
WeightRecord
时,它仍然保留在Person.weightsList
中,因为它是由personConnected.getWeightsList().conatins()
加载的。当HTTP请求完成后,Persistent Context关闭,Hibernate将刷新所有对数据库的更改。在
Person
端有cascade = CascadeType.ALL
,因此Hibernate应该记住weightsList
中已删除的WeightRecord
。因此它什么也不做,因为您可以删除WeightRecord
,然后出于某些原因再次插入它。你可以通过删除
personConnected.getWeightsList().conatins()
部分代码来验证上面的语句,删除将开始工作。如何解决
1.在
application.property
中设置spring.jpa.open-in-view=false
。这样,您将得到LazyInitializationException
和personConnected.getWeightsList().conatins()
1.删除
personConnected.getWeightsList().conatins()
代码。您可以通过比较WeightRecord.Person.id
和当前的Person.id
来执行相同的操作。现在,您可以将
cascade = CascadeType.ALL
保留在Person
侧的weightsList
上。备注
永远使用
spring.jpa.open-in-view=false
。LazyInitializationException
是您的朋友。在关联的
@ManyToOne
部分始终使用fetch = FetchType.LAZY
。默认情况下为FetchType.EAGER
。永远不要对实体使用Jackson注解(如
@JsonIgnore
)和Hibernate Validator注解(如@Min(1)
)。对实体使用PersonEntity
类别,对JSON使用Person
。在服务层级上进行Map。s6fujrry2#
事实上,我刚刚从我的@OneToMany实体Person中删除了CascadeType.ALL,并且一切正常。我可以从数据库中创建、读取和删除记录。
但我将进一步研究这个问题,以便更好地了解它的起源。