我有一个带有 thymeleaf 前端、Spring 后端和 mariadb 数据库的全栈应用程序。当我尝试通过 thymeleaf 表单更新对象时,出现了奇怪的问题。 对象的类如下所示(简化):
@Entity
@Table(name = "[tenants]")
@ApiModel( value = "Tenant", description = "Tenants resource representation" )
public class Tenant implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "[tenant_id]")
@ApiModelProperty( value = "tenantId", required = false )
private long tenantId;
@OneToMany(mappedBy = "tenant", fetch = FetchType.EAGER)
@JsonIgnoreProperties("tenant")
private List<Car> cars = new ArrayList<>();
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Column(name = "[rent_start]")
@ApiModelProperty( value = "rentStart", required = true )
@NotNull(message = "Rent start is required")
private Date rentStart;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Column(name = "[rent_end]")
@ApiModelProperty( value = "rentEnd", required = true )
@NotNull(message = "Valid to is required")
private Date rentEnd;
}
Car 类如下所示:
@Entity
@Table(name = "[car]")
@ApiModel( value = "Car", description = "Cars resource representation" )
public class Car implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "[car_id]")
@ApiModelProperty( value = "carId", required = false )
private long carId;
@ManyToOne
@JoinColumn(name = "tenant_id", nullable = true)
@JsonIgnoreProperties("cars")
private Tenant tenant;
}
在后端有一个 TenantView 类的常见结构,它调用 TenantService,TenantService 调用扩展 CrudRepository 的 TenantRepository。我的问题发生在更新租户时。以下是更新租户时调用的方法:
租户视图:
@RequestMapping(path="/update-tenant", method = RequestMethod.POST)
public ModelAndView updateTenant(@Valid @ModelAttribute("tenant") Tenant tenant, BindingResult result, HttpServletRequest request, RedirectAttributes redirectAttributes) {
ModelAndView modelAndView = new ModelAndView();
ResponseMessage message = null;
try {
tenantService.save(tenant);
// Neues ModelAndView mit Redirect verwenden, um das POST-Redirect-Get-Pattern umzusetzen
modelAndView = new ModelAndView("redirect:/view/tenants/all");
message = new ResponseMessage("message.success.title", "tenant.message.success.update.text", "message.success.color");
redirectAttributes.addFlashAttribute("message", message);
LOGGER.debug("Update tenant was successfully");
return modelAndView;
} catch (SQLException sex) {
LOGGER.error(sex.getMessage());
modelAndView = new ModelAndView("redirect:/view/tenants/update-tenant/");
message = new ResponseMessage("message.error.title", "tenant.message.error.update.sql.text", "message.error.color");
redirectAttributes.addFlashAttribute("message", message);
return modelAndView;
} catch (Exception ex) {
LOGGER.error(ex.getMessage());
modelAndView = new ModelAndView("redirect:/view/tenants/update-tenant/");
message = new ResponseMessage("message.error.title", "tenant.message.error.update.unkown.text", "message.error.color");
redirectAttributes.addFlashAttribute("message", message);
return modelAndView;
}
}
租户服务实现:
public Tenant save(Tenant tenant) throws SQLException {
return tenantRepository.save(tenant);
}
TenentRepository:CrudRepository
这是我的问题:我有一个租户租了两辆车(我想这里并不重要),他的rentStart是01-01-2024,rentEnd是12-31-2024。他是这样保存在我的数据库里的。我想将rentStart更新为06-06-2024,rentEnd更新为06-30-2024。我在TenantView的第一行设置了一个断点(ModelAndView modelAndView = new ModelAndView();)。当我现在查看数据库时,新日期(2024 年 6 月 6 日和 2024 年 6 月 30 日)已保存在数据库中。之后代码按预期执行并再次保存。我不知道如何开始在这里搜索问题。我尝试在每种情况下设置断点“tenantRepository.save(tenant);”被调用但没有运气。
关于我和提供的代码的一些信息:我是一名初级开发人员,拥有大约一年的经验。所以我不知道您是否需要更多或不同的信息。我处理的代码是生产代码,因此我无法在这里一对一地发布它,因此我对其进行了修剪并更改了类名称。从我的示例数据来看,这应该不是问题,因为无论哪种方式,结果都是相同的,无论它是否在实际保存到存储库之前保存到数据库中。但在实际代码中,汽车也会根据某些逻辑在服务中进行更新,当租户过早保存时,这些逻辑就会中断。我测试了这个逻辑是否与问题有关并将其注释掉,以便真正的存储库保存方法看起来与提供的方法完全相同。问题依然存在。
我不期望快速解决(也不会抱怨),因为我认为问题存在于更深层次的地方。我想知道是否有人经历过类似的事情,并且知道从哪里以及如何开始寻找问题的原因。
提前非常感谢您!
昨天睡觉前(还有什么时候?)我想到了一个想法。
我将 TenantService 中的方法命名为“save”。如果这个名字有问题怎么办?该名称在 TenentRepository 扩展 CrudRepository 中有其固定用途。今天我尝试将该方法重命名为其他名称,它实际上解决了我的问题。 所以我自己得出结论:如果您使用 CrudRepository 中的 save 方法,请不要命名服务方法,其中会发生一些除了调用存储库之外的附加逻辑,只是“保存”,但还有其他东西。
需要注意的是,我使用 Ubuntu 22.04.4 LTS。我的同事使用 MacO。他没有遇到这个问题。
我仍然不知道为什么会发生这种情况。也许比我更熟练的人可以进一步解释。