在事务内部生成Hibernate自定义id

时间:2017-10-09 08:07:46

标签: java spring hibernate

我正在尝试向表中插入行(问题)列表。(比如说'Question_Table')。 整个过程在单个事务中执行。 (即,我必须插入所有问题或不插入)。我正在使用Spring的声明式事务。

我已经为Question_Table定制了ID生成。(参考:Custom id generation

它适用于第一个问题。但它不适用于第二个问题,因为第一行是未提交的,并且表将为空。我无法将DAO类注入Id生成器,因为它不是Spring托管bean(因此我可以在DAO类中使用读取未提交记录的方法)。

在这种情况下使用的最佳方法是什么。

生成器类

public class IdGenerator implements IdentifierGenerator, Configurable {


    private String prefix = "";
    private String queryKey = "";

    @Override
    public Serializable generate(SessionImplementor sessionImpl, Object arg1) throws HibernateException {

        long count = (long)sessionImpl.getNamedQuery(queryKey).list().get(0);
        System.out.println("COUNT >>> "+count);

        long id = count + 1;
        if(id == 4) throw new NullPointerException();
        String generatedId = prefix + id;

        return generatedId;
    }

    @Override
    public void configure(Type arg0, Properties arg1, ServiceRegistry arg2) throws MappingException {
        prefix=arg1.getProperty("PREFIX");
        queryKey=arg1.getProperty("QUERY_KEY");
    }

}
  

查询:从Question_Table中选择count(*)

3 个答案:

答案 0 :(得分:1)

正如我在评论中所述,如果使用字符串和序列的组合没有问题,你可以use this approach。但缺点是,即使删除该表中的所有记录,该值也将始终增加。

如果您坚持使用count,那么解决方案就是手动保存定义您的实体ID。 .save(question, "QSTN_"+(row_count + i));但您需要能够通过我认为不是问题的row_count,因为它必须是一次请求。

答案 1 :(得分:0)

我对您的具体问题没有答案,但我想分享一些注意事项。

如果您的id生成依赖于数据库状态,那么必须在数据库级别完成(实现取决于您,自动增量,自定义函数或序列等)...

否则,如果您在应用程序级别执行此操作,则必须遇到并发访问问题,并且必须使用某些锁定或专用事务来缓解它,这会对应用程序性能产生重大影响并可能变为稍后不一致(例如,在添加水平可伸缩性或分片时)。

但是,如果您想在应用层(which can be a very good idea)中生成ID,那么您必须拥有专门用于此任务的独特分布式系统,而该系统不属于您当前的工作单元。

答案 2 :(得分:0)

@Transactional(isolation = Isolation.READ_COMMITTED)
public AccountDto saveAccount(AccountDto accountDto) {
    Long accountTypeId = accountDto.getAccountTypeId();
    AccountTypes accountTypes = accountTypesDao.getById( accountTypeId ).orElseThrow( NotFoundAppException::new );
    account.setAccountName( newAccountName );
    account.setAccountType( accountTypes );
    ...
    accountDao.save( account );
    accountDao.flush();

    // new inserted account id is in the transaction now
    return createAccountDtoFrom( account );
}