在我的spring-boot项目中,我使用spring-data, Hibernate和Oracle作为数据库。
我有实体Message
,User
和SeenMessage
。
Messaage
看起来像:
@Entity
@Table(name = "MESSAGES")
public class Messages {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "MARKET_MESSAGE_GENERATOR")
@SequenceGenerator(name = "MARKET_MESSAGE_GENERATOR", sequenceName = "MARKET_MESSAGE_SEQ", allocationSize = 1)
private Long id;
@Basic
@Column(name = "PUBLISH_DATE")
private Timestamp dateTime;
@Basic
@Column(name = "TITLE")
private String title;
@Lob
@Nationalized
@Column(name = "MESSAGE", columnDefinition="NCLOB NOT NULL")
private String message;
}
User
看起来像:
@Entity
@Table(name = "Users")
public class User {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_GENERATOR")
@SequenceGenerator(name = "USER_GENERATOR", sequenceName = "USERS_SEQ", allocationSize = 1)
private Long id;
@Basic
@Column(name = "USER_NAME")
private String userName;
}
和SeenMessage
看起来像:
@Entity
@Table(name = "SEEN_MESSAGE")
public class SeenMessage {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEEN_MESSAGE_GENERATOR")
@SequenceGenerator(name = "SEEN_MESSAGE_GENERATOR", sequenceName = "SEEN_MESSAGE_SEQ", allocationSize = 1)
private Long id;
@Basic
@Column(name = "SEEN_DATE")
private Timestamp seenDate;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "MESSAGE_ID")
private Messages message;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "USER_ID")
private User user;
}
同样在这个表(SEEN_MESSAGE
)上,我对(Message_Id
,User_Id
)对有唯一的约束条件
现在的问题是:
我有一个简单的REST API,用于获取具有其ID的消息,当任何人调用此服务时,我将返回所请求的消息,并且我还将在seenMessage
表中插入messageId
和userId
的记录,当然还有它的时间。
我通过调用存储库中的方法在我的服务层中执行第二个操作(插入SeenMessage):
@Repository
public interface SeenMessageRepository extends JpaRepository<SeenMessage, Long> {
@Query(value = "begin " +
"insert into SEEN_MESSAGE(ID, MESSAGE_ID, USER_ID, SEEN_DATE) " +
"values(seen_message_seq.nextval, :MId , :UId , CURRENT_TIMESTAMP ); " +
"exception " +
"when dup_val_on_index THEN " +
"RETURN; " +
"end;", nativeQuery = true)
void insertAndForget(Long MId, Long UId);
}
正如你所看到的,我已经写了一个本地查询,当我在DBMS上执行它时,它将成功执行,但是当我使用Postman调用我的API时,查询将执行并执行,但它也会抛出一个异常,这是:
2021-10-26 11:12:50.385 ERROR 4848 --- [nio-1201-exec-2] c.a.b.o.exceptions.ExceptionTranslator : -1
java.lang.NegativeArraySizeException: -1
at org.hibernate.loader.custom.ResultRowProcessor.prepareForAutoDiscovery(ResultRowProcessor.java:36)
at org.hibernate.loader.custom.CustomLoader.autoDiscoverTypes(CustomLoader.java:489)
at org.hibernate.loader.Loader.preprocessResultSet(Loader.java:2343)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2299)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2050)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:2012)
at org.hibernate.loader.Loader.doQuery(Loader.java:948)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349)
at org.hibernate.loader.Loader.doList(Loader.java:2843)
at org.hibernate.loader.Loader.doList(Loader.java:2825)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2657)
at org.hibernate.loader.Loader.list(Loader.java:2652)
at org.hibernate.loader.custom.CustomLoader.list(CustomLoader.java:338)
at org.hibernate.internal.SessionImpl.listCustomQuery(SessionImpl.java:2141)
at org.hibernate.internal.AbstractSharedSessionContract.list(AbstractSharedSessionContract.java:1169)
at org.hibernate.query.internal.NativeQueryImpl.doList(NativeQueryImpl.java:176)
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1604)
at org.hibernate.query.internal.AbstractProducedQuery.getSingleResult(AbstractProducedQuery.java:1652)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:196)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:88)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:155)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:143)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137)
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:159)
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:138)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:80)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:145)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
at com.sun.proxy.$Proxy125.insertAndForget(Unknown Source)
也许可以说我写了这个查询并且没有使用简单的插入查询,因为在这种情况下,我需要自己检查Duplicate(如果我没有检查副本,我可能会面对UniqueconstraintViolationException
),另一个数据库调用在我看来是额外的,所以我写了这个。
谁能告诉我这个错误的原因?为什么它在DBMS上执行没有错误,但在我的应用程序中它会导致错误??
任何帮助将不胜感激!!
我需要将@Modifying
注释放在我的存储库方法上,如下所示:
@Modifying
@Query(value = "BEGIN " +
"INSERT INTO SEEN_MESSAGE(ID, MESSAGE_ID, USER_ID, SEEN_DATE) " +
"VALUES(seen_message_seq.nextval, :MId , :UId , CURRENT_TIMESTAMP ); " +
"EXCEPTION " +
"WHEN dup_val_on_index THEN " +
"RETURN;" +
"END;", nativeQuery = true)
void insertAndForget(Long MId, Long UId);
我还需要在我的服务层中打开一个TRANSACTION
,为此,我将@Transactional(rollbackFor = Exception.class)
放在调用我的存储库方法的服务层方法上。