hibernate从oracle数据库保存后序列自动生成ID为

时间:2015-08-07 09:15:54

标签: java oracle hibernate

具有从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;  

2 个答案:

答案 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