我在将简单数据结构存入数据库时遇到了问题。Hibernate,Spring,PostgreSQL - 列索引超出范围
每条消息可能有多个消息接收者。我需要的一切就是保存在数据库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_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...
}
MessageReceiver.java
@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> {}
插入查询似乎确定,我看不到任何错误了。
我也尝试将MR实体ID更改为具有@IdClass批注和@PrimaryKeyJoinColumn的复合键。那些尝试没有帮助。
您的表格只有4列。你确定你的数据库模式与你的类结构相匹配吗? (什么时候是你最后一次执行创建你的数据库的脚本?) –
@MikeNakis在帖子开头的sql查询是直接从PgAdmin复制的。 类结构是否必须与数据库表结构相同?在类中我没有放置audit_md列。 – mateusz
是的,类结构和数据库模式必须匹配,否则预计hibernate会尝试访问数据库中不存在的列。查看hibernate的'hbm2ddl'属性,它允许你从你的类结构自动创建你的数据库模式。如果你不想(或不能)这样做,你也可以使用'hbm2ddl'来至少让hibernate在程序启动时验证你的类结构是否与你的数据库模式一致,以避免令人讨厌的意外。 –