Spring JPA自动更新诡异现象
最近在操作spring data的时候遇到一个奇怪的问题。
第一,更改了实体entity,数据库会被自动更新
第二,更改了实体的entity,相关实体解析出问题
场景如下,有一个user表,这个表中有role 和project .
@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "User")
public class User extends BaseEntity{
@ManyToOne
private Role role;
@ManyToOne
private Project project;
}
在数据库中,User表这两个字段分别为role_id 和 project_id
role和project实体中并未配置onetomany的映射. 下面奇妙的事情发生了,
第一我更新User实体,仅仅是更新实体,并没有进行save操作,竟然数据库中的内容被自动更新,自动执行了了一遍save的操作,按照Id全员update。
long roleId = userRoleHandler.checkAndUpdateUserRole();
if(roleId > 0) {
Role role = new Role();
role.setId(roleId);
user.setRole(role);
}
这样的情况,即便我新建了一个user , 全量赋值之后执行,依然会被自动更新掉,而且之后对role的操作也会作用到原来的user。
解决方法是写了@query
@Transactional
@Modifying(clearAutomatically = true)
@Query(value = "update AppUser set first_lgn = ?1,last_lgn =?2 , help_flg = ?3, update_dt = ?4 , project_id = ?5, role_id = ?6 where id = ?7 ", nativeQuery = true)
void updateUserByQueryMySql(boolean firstLogin, Date lastLgn, boolean showHelp,Date updateDate,Long projectId,Long roleId, Long id);
这样做之后,不会再影响到原来的user,但实际上是save自动更新还是会被执行,只是被这个query覆盖掉了。
接下来发生第二个诡异事件:
project中有client实体
@Data
@EqualsAndHashCode(callSuper = false)
@Entity
public class Project extends BaseEntity {
@ManyToOne
@JoinColumn(nullable = false, name = "client_id")
protected Client client;
}
client中的属性就相对很多:
@Data
@EqualsAndHashCode(callSuper = false)
@Entity
@Table(name = "Client")
public class Client extends BaseEntity {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 3182405782441627318L;
/** The name. */
@ApiObjectField(description = "Name of the Company/Client")
@Column(nullable = false)
protected String name;
/** The revenue. */
@ApiObjectField(description = "Estimated annual revenue of the company/client")
@ManyToOne
@JoinColumn(nullable = false, name = "revenue")
protected ClientRevenue revenue;
/** The pwc vertical. */
@ApiObjectField(description = "PwC vertical definition")
@ManyToOne
@JoinColumn(nullable = false, name = "vertical")
protected Vertical vertical;
/** The industry. */
@ManyToOne
@JoinColumn(nullable = false, name = "industry")
protected Industry industry;
@ManyToOne
@JoinColumn(nullable = false, name = "territory_id")
protected Territory territory;
/** The sub industry. */
@ManyToOne
@JoinColumn(nullable = false, name = "sub_ind")
protected SubIndustry subIndustry;
/** The employee number. */
@ApiObjectField(description = "Estimated amount of employees of the company/client")
@ManyToOne
@JoinColumn(nullable = false, name = "emp_nmb")
protected EmployeeNumber employeeNumber;
/** The location. */
@ApiObjectField(description = "Where the company/client is located")
protected String location;
/** The domain list. */
@Cascade(value = CascadeType.ALL)
@OneToMany(fetch = FetchType.LAZY)
private List<EmailDomain> domainList;
}
当更改上述表user 中的project_id 时,将user或者project实体返回
return new ResultMessage(1, "Successfully!", project);
则会报无法解析client下相关实体的问题,
Could not write Json: failed to lazily initialize a collection of role:...could not initialize proxy - no session: 接下来就是错误栈信息,将project --> client -->vertical .....
解决方式是
1.显示的再查询project一次,则可以正确解析
2.不返回project,返回null
补充,今天我更改了一个实体,对实体的子列表进行排序,直接造成了数据库更新。解决方法将子列表放到新的对象里面进行处理。
List<ImpactSubCategory> impactSubCategory = new ArrayList<>();
if (CollectionUtils.isNotEmpty(ic.getImpactSubCategory())) {
impactSubCategory.addAll(ic.getImpactSubCategory());
//don't modify entity values directly otherwise it will excute database update
impactSubCategory.sort((ImpactSubCategory o1, ImpactSubCategory o2) -> {
return o1.getValue().compareTo(o2.getValue());
});
}