Java Hibernate、Spring、PostgreSQL-列索引超出范围
我无法将简单的数据结构持久化到数据库中 每条消息可以有多个消息接收器。我所需要的一切就是保存在数据库Message和MessageReceivers(MR)中。MR具有名为fk_message_id的列,该列应自动填充message_id(M) 在数据库(PostgreSQL)中,使用SQL代码创建表:Java Hibernate、Spring、PostgreSQL-列索引超出范围,java,postgresql,hibernate,spring-data-jpa,Java,Postgresql,Hibernate,Spring Data Jpa,我无法将简单的数据结构持久化到数据库中 每条消息可以有多个消息接收器。我所需要的一切就是保存在数据库Message和MessageReceivers(MR)中。MR具有名为fk_message_id的列,该列应自动填充message_id(M) 在数据库(PostgreSQL)中,使用SQL代码创建表: CREATE TABLE public.message ( message_id integer NOT NULL DEFAULT nextval('message_message_id_se
CREATE TABLE public.message
(
message_id integer NOT NULL DEFAULT nextval('message_message_id_seq'::regclass),
fk_author_id integer NOT NULL,
topic text NOT NULL,
text text NOT NULL,
audit_cd timestamp without time zone NOT NULL DEFAULT now(),
audit_md timestamp without time zone,
CONSTRAINT message_pkey PRIMARY KEY (message_id)
)
CREATE TABLE public.message_receiver
(
fk_message_id integer NOT NULL,
fk_user_id integer NOT NULL,
is_read boolean NOT NULL,
read_date timestamp without time zone,
audit_cd timestamp without time zone NOT NULL DEFAULT now(),
autid_md timestamp without time zone,
CONSTRAINT message_receiver_pkey PRIMARY KEY (fk_message_id, fk_user_id),
CONSTRAINT message_receiver_fk_message_id_fkey FOREIGN KEY (fk_message_id)
REFERENCES public.message (message_id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
)
Message.java
@Entity
@Table(name="message")
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="message_message_id_seq")
@SequenceGenerator(name="message_message_id_seq", sequenceName="message_message_id_seq", allocationSize=1)
@Column(name="message_id")
private Long id;
@NotNull
@Column(name="fk_author_id")
private Long author;
@OneToMany
@Cascade(CascadeType.PERSIST)
@JoinColumn(name="fk_message_id", nullable = false)
private List<MessageReceiver> receivers;
@NotNull
@Column(name="topic")
private String topic;
@NotNull
@Column(name="text")
private String text;
@NotNull
@Column(name="audit_cd")
@Convert(converter=PersistentLocalDateTime.class)
private LocalDateTime sendDate;
...getters, setters, constructors...
}
@Entity
@Table(name="message_receiver")
public class MessageReceiver implements Serializable {
private static final long serialVersionUID = 2L;
@Id
@Column(name="fk_message_id")
private Long messageId;
@Id
@Column(name="fk_user_id")
private Long receiverId;
@NotNull
@Column(name="is_read")
private Boolean isRead;
@Column(name="read_date")
@Convert(converter = PersistentLocalDateTime.class)
private LocalDateTime readDate;
...getters, setters, constructors...
}
当我尝试使用接收者保存邮件时,我得到:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not insert: [com.example.foldermessage.model.MessageReceiver]; SQL [insert into message_receiver (is_read, read_date, fk_message_id, fk_user_id) values (?, ?, ?, ?)]; nested exception is org.hibernate.exception.DataException: could not insert: [com.example.foldermessage.model.MessageReceiver]] with root cause
org.postgresql.util.PSQLException: The column index is out of range: 5, number of columns: 4.
at org.postgresql.core.v3.SimpleParameterList.bind(SimpleParameterList.java:68) ~[postgresql-9.4.1211.jar:9.4.1211]
at org.postgresql.core.v3.SimpleParameterList.setNull(SimpleParameterList.java:157) ~[postgresql-9.4.1211.jar:9.4.1211]
at org.postgresql.jdbc.PgPreparedStatement.setNull(PgPreparedStatement.java:287) ~[postgresql-9.4.1211.jar:9.4.1211]
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:61) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:257) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:252) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:343) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrateId(AbstractEntityPersister.java:2636) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2604) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2883) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3386) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:89) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:560) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:434) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
我使用JpaRepository执行保存操作:
@Repository
public interface MessageRepository extends JpaRepository<Message, Long> {}
@存储库
公共接口MessageRepository扩展了JpaRepository{}
插入查询似乎还可以,但我看不出有任何错误
我还尝试将MR实体ID更改为带有@IdClass注释和@PrimaryKeyJoinColumn的复合键。那些尝试都没有帮助。我找到了临时解决办法
spring.jpa.hibernate.DDL auto=create(或update)
来自动生成模式fk\u消息\u id,fk\u用户\u id
。此复合密钥的主要目的是防止向一个用户发送同一消息两次或多次@Entity
@Table(name="message_receiver")
public class MessageReceiver implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="message_receiver_id")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="message_receiver_id_seq")
@SequenceGenerator(name="message_receiver_id_seq", sequenceName="message_receiver_id_seq", allocationSize=1)
private Long messageReceiverId;
@NotNull
@Column(name="fk_message_id")
private Long messageId;
@NotNull
@Column(name="fk_user_id")
private Long receiverId;
@NotNull
@Column(name="is_read")
private Boolean isRead;
@Column(name="read_date")
@Convert(converter = PersistentLocalDateTime.class)
private LocalDateTime readDate;
..getters, setters..
Message.java
@Entity
@Table(name="message")
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="message_message_id_seq")
@SequenceGenerator(name="message_message_id_seq", sequenceName="message_message_id_seq", allocationSize=1)
@Column(name="message_id")
private Long id;
@NotNull
@Column(name="fk_author_id")
private Long author;
@OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
@JoinColumn(name="fk_message_id")
private List<MessageReceiver> receivers = new ArrayList<>();
@NotNull
@Column(name="topic")
private String topic;
@NotNull
@Column(name="text")
private String text;
@NotNull
@Column(name="audit_cd")
@Convert(converter=PersistentLocalDateTime.class)
private LocalDateTime sendDate;
..getters, setters..
@实体
@表(name=“message”)
公共类消息实现可序列化{
私有静态最终长serialVersionUID=1L;
@身份证
@GeneratedValue(策略=GenerationType.SEQUENCE,generator=“message\u message\u id\u seq”)
@SequenceGenerator(name=“message\u message\u id\u seq”,sequenceName=“message\u message\u id\u seq”,allocationSize=1)
@列(name=“message\u id”)
私人长id;
@NotNull
@列(name=“fk\u author\u id”)
私人长作者;
@OneToMany(fetch=FetchType.LAZY,cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REMOVE})
@JoinColumn(name=“fk\u message\u id”)
私有列表接收者=新的ArrayList();
@NotNull
@列(name=“topic”)
私有字符串主题;
@NotNull
@列(name=“text”)
私有字符串文本;
@NotNull
@列(name=“audit\u cd”)
@Convert(converter=PersistentLocalDateTime.class)
私有LocalDateTime sendDate;
…能手,二传手。。
现在,我很好奇为什么第一个解决方案不起作用以及如何使它起作用。我尝试了@PrimaryKeyJoinColumn、@IdClass、@OneToMany(mappedBy)、@JoinColumn(可空、可插入、可更新)的混合
当我启用DDL(创建)时,Hibernate将生成与我在开始时放置的相同的表。这意味着表结构不正确不会有问题
如果更改生成主键的策略有帮助,那么保存复合键可能会导致错误。在日志中,我经常看到Hibernate添加到实体*\u IdBackref
。可能它尝试将此id保存/映射到数据库中,但其列尚未准备好
如果找到最终解决方案,我将发布。您的表中没有一个只有4列。您确定您的数据库架构与您的类结构匹配吗?(上次执行创建数据库的脚本是什么时候?)@我在文章开头提出的MikeNakis sql查询是直接从PgAdmin复制的。类结构必须与数据库表结构相同吗?在类中,我没有提出audit_md列。是的,类结构和数据库架构必须匹配,否则hibernate将尝试访问这些列数据库中不存在。请查找hibernate的
hbm2ddl
属性,该属性允许您从类结构自动创建数据库架构。如果您不想(或不能)要做到这一点,您还可以使用hbm2ddl
至少让hibernate在程序启动期间验证您的类结构是否与数据库架构一致,以避免令人不快的意外情况。@MikeNakis我在java类中添加了缺少的列。现在我得到了相同的错误,但数字不同。查询:插入到消息接收器中(审核cd、is读取、autid md、读取日期、fk消息id、fk用户id)值(?,,,,,?,?)
错误:org.postgresql.util.psqleexception:列索引超出范围:7,列数:6。
好的,那么很明显,实际的postgres表不包含列audit\u cd,is\u read,autid\u md,read\u date,fk\u message\u id,fk\u user\u id
。让它包含这些列。