每当我尝试更新我的实体时,我都会在日志中经常收到此错误。 有趣的是,当我检查我的数据库时,我看到实体已使用与日志相同的时间戳成功更新。当我尝试在本地点击相同的更新请求时,我无法重现该问题。
该实体如下:
MySqlAbstractEntity的晚餐类
@MappedSuperclass
public abstract class MysqlAbstractEntity<ID extends Serializable> implements AbstractEntity<ID> {
private static final long serialVersionUID = 8920812256547697337L;
@Id
@GeneratedValue(
generator = "myGenerator",
strategy = GenerationType.SEQUENCE
)
@GenericGenerator(
name = "myGenerator",
strategy = "com.****.MysqlLongIDGenerator"
)
@Column(
name = "id",
updatable = false,
insertable = false
)
protected Long id;
@Temporal(TemporalType.TIMESTAMP)
@Column(
name = "created_on",
nullable = false,
updatable = false
)
protected Date createdOn;
@Temporal(TemporalType.TIMESTAMP)
@Column(
name = "last_modified_on",
nullable = false
)
protected Date lastModifiedOn;
@Version
@Column(
name = "version"
)
protected Long version = Long.valueOf(0L);
public MysqlAbstractEntity() {
}
@PrePersist
protected void onCreate() {
this.lastModifiedOn = this.createdOn = this.createdOn == null?new Date():this.createdOn;
}
@PreUpdate
protected void onUpdate() {
this.lastModifiedOn = new Date();
}
我的自定义ID生成器如下所示:
public class MysqlLongIDGenerator extends IdentityGenerator {
public MysqlLongIDGenerator() {
}
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) {
try {
LongIDAbstractEntity entity = (LongIDAbstractEntity)object;
if(entity.getId() != null && entity.getId().longValue() > 0L) {
return entity.getId();
}
} catch (Exception var4) {
;
}
return super.generate(session, object);
}
}
我的实际实体是
public class MyEntity extends MysqlAbstractEntity {
@OneToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(name = "other_entity_id", nullable = false)
private SomeOtherEntity user;
@Column(name = "active")
private Boolean active;
@Column(name = "device_type")
@Enumerated(EnumType.STRING)
private DeviceType deviceType;
@Column(name = "app_version")
private String appVersion;
@Column(name = "device_id")
private String deviceId;
@Column(name = "device_version")
private String deviceVersion;
@Column(name = "client_id")
private String clientId;
}
我的存储库是
@Transactional(rollbackFor = Exception.class)
public class MyEntityRepository extends CrudRepository<MyEntity, Long> {
}
我的更新代码是这样的:
public MyEntity update(@NotNull MyEntity updatedMyEntity) {
MyEntity entity = myEntityRepository.findByDeviceId(updatedMyEntity.getDeviceId());
if (entity != null) {
return myEntityRepository.save(updateEntity(entity, updatedMyEntity));
} else {
return null;
}
}
updateEntity方法实际上是更新字段值
这是我在日志中的例外
ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1, stackTrace org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:320)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy118.save(Unknown Source)