具有从oracle触发器序列自动生成的id的实体。
@Entity
@Table(name = "REPORT", schema = "WEBPORTAL")
public class Report {
private Integer id;
....
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="report_sequence")
@SequenceGenerator(name="report_sequence", sequenceName = "report_id_seq")
@Column(name="REPORT_ID", unique = true, nullable = false)
public Integer getId() {
return id;
}
....
}
服务
@Service("reportService")
public class ReportServiceImpl implements ReportService {
....
@Transactional(readOnly=false)
public void saveOrUpdate(Report report) {
reportDAO.saveOrUpdate(report);
}
}
DAO
@Repository
public class ReportDAOImpl implements ReportDAO {
....
@Override
public Report save(Report report) {
try {
Session session = sessionFactory.getCurrentSession();
session.save(report);
} catch (Exception e) {
logger.error("error", e);
}
return report;
}
}
当我调用service的saveOrUpdate然后尝试访问实体的id时,我得到的值不同于数据库中的持久值。具有自动生成功能的数据库上的值都可以。有什么建议吗?
reportService.saveOrUpdate(report);
System.out.println(report.getId());
打印:4150 但在数据库中保存的ID是:84
注意:我获得ID的目的来自于我想用级联来保存孩子。但是孩子的外键在数据库中是不同的(我用getId()得到的id的值)。
在数据库中生成的Id增加2. EX:80,82,84。
更新
用于序列生成的Oracle触发器
CREATE OR REPLACE TRIGGER REPORT_ID_TRIG
BEFORE INSERT ON WEBPORTAL.REPORT
FOR EACH ROW
BEGIN
SELECT report_id_seq.NEXTVAL
INTO :new.report_id
FROM dual;
END;
答案 0 :(得分:1)
答案:触发器应检查id是否为空
CREATE OR REPLACE TRIGGER REPORT_ID_TRIG
BEFORE INSERT ON WEBPORTAL.REPORT
FOR EACH ROW
WHEN (new.report_id is null)
BEGIN
SELECT report_id_seq.NEXTVAL
INTO :new.report_id
FROM dual;
END;
说明强>
@GeneratedValue不仅仅是一个序列生成器。它有点像HiLo算法。当它首次从数据库请求id时,它将它与50相乘(它可以不同),接下来将给出50个新实体,并且下一个请求将被提供给数据库。这是为了减少对数据库的请求
我从java获得的数字是应该保存在报告上的正确数字。
没有id null值检查Hibernate首先请求来自数据库的id和被调用的sequence.nextval。当hibernate持久化(完成事务)时,数据库第二次调用sequence.next并将该值设置为database。所以在ReportDetails上有报告的真实id值,在报告ID上它是从数据库设置的id。
答案 1 :(得分:0)
问题在于有两个独立的机制来生成密钥:
Hibernate 级别的一个,即调用序列并使用该值填充 Id 列并将其作为插入键发送到数据库
还有另一种 Hibernate 不知道的数据库机制:列通过触发器递增。
Hibernate 认为插入是使用序列的值进行的,但在数据库中发生了其他事情。最简单的解决方案可能是移除触发机制,让 Hibernate 仅根据序列填充键。
另一种解决方案:
检查应该采用这种格式的触发器定义
(WHEN (new.report_id is null)
) 很重要。
CREATE OR REPLACE TRIGGER TRIGGER_NAME
BEFORE INSERT ON TABLE_NAME
FOR EACH ROW
WHEN (new.id is null)
BEGIN
SELECT SEQUENCE_NAME.NEXTVAL
INTO :new.id
FROM dual;
END