所以我们的项目使用PostgreSQL数据库,我们使用JPA来操作数据库。 我们使用Netbeans 7.1.2中的自动创建程序从数据库创建了实体。
经过小幅更改后,我们的主键值被描述为:
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Basic(optional = false)
@NotNull
@Column(name = "idwebuser", nullable = false)
private Integer idwebuser;
问题是现在应用程序不灵活,因为当我们直接修改数据库(使用SQL或其他工具)而不是通过Java应用程序时 - 生成的值低于实际的数据库ID值 - 所以我们在创建新实体期间收到错误。
JPA是否有可能让数据库自动生成ID,然后在创建过程后获取它? 或者什么是更好的解决方案? 感谢。
修改 进一步来说: 我们有一个用户表,我的问题是使用任何类型的策略生成类型,JPA正在插入一个由它的生成器id指定的新实体。这对我来说是错误的,因为如果我自己对表进行更改,通过添加新条目,应用程序的GeneratedValue低于当前ID - 这导致我们出现重复ID异常。 我们能解决它吗?)?
答案的简短说明 我身边有一点谎言,因为我们使用了PG管理员 - >从那里查看前100行和编辑行而不是使用选择。但是,事实证明,这个编辑器以某种方式跳过了更新ID的过程,因此即使在DB中,当我们编写一个正确的INSERT时,它也会被执行不正确的ID!所以它基本上是我们使用的编辑器的问题而不是数据库和应用程序......
现在它甚至可以使用@GeneratedValue(strategy=GenerationType.IDENTITY)
答案 0 :(得分:70)
鉴于表格定义:
CREATE TABLE webuser(
idwebuser SERIAL PRIMARY KEY,
...
)
使用映射:
@Entity
@Table(name="webuser")
class Webuser {
@Id
@SequenceGenerator(name="webuser_idwebuser_seq",
sequenceName="webuser_idwebuser_seq",
allocationSize=1)
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="webuser_idwebuser_seq")
@Column(name = "idwebuser", updatable=false)
private Integer id;
// ....
}
命名tablename_columname_seq
是SERIAL
的PostgreSQL默认序列命名,我建议您坚持使用它。
如果你需要Hibernate与其他客户端合作到数据库,allocationSize=1
很重要。
请注意,如果事务回滚,此序列将包含“空白”。由于各种原因,事务可以回滚。您的应用程序应该设计为能够应对此问题。
n
都有一个身份n-1
或n+1
n
之前或ID大于n
之后添加或提交了ID n
。如果你对如何使用序列非常小心,你可以做到这一点,但你永远不应该尝试;记录表格中的时间戳。请参阅PostgreSQL documentation for sequences和the serial data types。
他们解释说上面的表定义基本上是:
的快捷方式CREATE SEQUENCE idwebuser_id_seq;
CREATE TABLE webuser(
idwebuser integer primary key default nextval('idwebuser_id_seq'),
...
)
ALTER SEQUENCE idwebuser_id_seq OWNED BY webuser.idwebuser;
...这应该有助于解释为什么我们添加了@SequenceGenerator
注释来描述序列。
如果您确实必须有无间隙序列(例如,检查或发票编号),请参阅gapless sequences但请认真考虑,请避免使用此设计,并且从不将其用作主键
注意:如果您的表格定义如此:
CREATE TABLE webuser(
idwebuser integer primary key,
...
)
并使用(不安全,不要使用)插入其中:
INSERT INTO webuser(idwebuser, ...) VALUES (
(SELECT max(idwebuser) FROM webuser)+1, ...
);
或(不安全,从不这样做):
INSERT INTO webuser(idwebuser, ...) VALUES (
(SELECT count(idwebuser) FROM webuser), ...
);
然后你做错了并且应该使用锁定的计数器表切换到序列(如上所示)或正确的无间隙序列实现(同样,见上文并参见Google中的“无间隙序列postgresql”。如果在数据库上有多个连接工作,则上述操作都是错误的。
答案 1 :(得分:2)
似乎你必须使用序列生成器,如:
@GeneratedValue(generator="YOUR_SEQ",strategy=GenerationType.SEQUENCE)
答案 2 :(得分:1)
请尝试使用GenerationType.TABLE
代替GenerationType.IDENTITY
。数据库将创建单独的表,用于生成唯一的主键,它还将存储上次使用的ID号。
答案 3 :(得分:0)
您还可以通过编写脚本来执行通用$(document).ready(function() {
$('nav li a i:first').on('click', function() {
$('.forperson1').slideToggle();
$('nav').toggleClass('open closed');
});
});
到所选答案提议的解决方案的批量转换,从而节省一些工作。下面的脚本对Java源文件的格式有一些轻微的依赖关系,并且无需备份即可进行修改。注意事项!
运行脚本后:
GenerationType.IDENTITY
import javax.persistence.Table;
。将以下脚本保存为import javax.persistence.Table; import javax.persistence.SequenceGenerator;
或类似名称:
update-sequences.sh
使用NetBeans生成CRUD应用程序时,ID属性将不包含可编辑的输入字段。
答案 4 :(得分:0)
对我有用
CREATE TABLE webuser(
idwebuser SERIAL PRIMARY KEY,
...
)
@Entity
@Table(name="webuser")
class Webuser {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
// ....
}