JPA实体类有Id保存也会新增一条新的数据问题

原创
2019/07/02 16:35
阅读数 2.9K

前言:沉浸在代码中,没有跳出来看问题就容易钻牛角尖。还是遇见的问题太少。遇见的问题越多,知道的就会越多。

 

两个不同的实体类深拷贝,然后把id赋值回去更新,会出现一条新数据。

A updateA = DTOMapper.MAPPER.po2po(bAudit);
updateA.setId(1)
sheetRepository.save(updateA);

 

1.save方法源码

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.CrudRepository#save(java.lang.Object)
	 */
	@Transactional
	public <S extends T> S save(S entity) {

		if (entityInformation.isNew(entity)) {
			em.persist(entity);
			return entity;
		} else {
			return em.merge(entity);
		}
	}

在这里说一下,save上spring就已经加了 @Transactional 开启事务的注解。用spring来管理事务就必须开启事务,不然保存不了,因为SET AUTOCOMMIT=0了。

save方法的第一句代码就是判断entity是否是新增还是更新。

 

2.看isNew实现
 

第一个是AbstractPersistable提供的,也是我们熟知的 ,根据id是否为空来判断是否是更新

/**
	 * Must be {@link Transient} in order to ensure that no JPA provider complains because of a missing setter.
	 *
	 * @see org.springframework.data.domain.Persistable#isNew()
	 */
	@Transient // DATAJPA-622
	public boolean isNew() {
		return null == getId();
	}

第二个是 JpaMetamodelEntityInformation提供的

	/*
	 * (non-Javadoc)
	 * @see org.springframework.data.repository.core.support.AbstractEntityInformation#isNew(java.lang.Object)
	 */
	@Override
	public boolean isNew(T entity) {

		if (!versionAttribute.isPresent()
				|| versionAttribute.map(Attribute::getJavaType).map(Class::isPrimitive).orElse(false)) {
			return super.isNew(entity);
		}

		BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity);

		return versionAttribute.map(it -> wrapper.getPropertyValue(it.getName()) == null).orElse(true);
	}

这个是是根据version版本号来判断是否是更新,问题就出在这里,我们如果更新,必须更新实体的jpaVersion和数据库里的Version一致,不然就是新增操作。

 

总结:我一直在各种打印 id有木有赋值进去,刚开始是从对象里get出来的,后来又赋值给一个变量,然后怀疑jpa是不是直接拿自己的属性,而不是拿public方法(id是父类继承下来的),反正折腾了好久。

其实回想一下很简单,但是jpa没有给我报错,我觉得是jpa的不对,哈哈。

 

博客地址:https://my.oschina.net/wangnian

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部