简体   繁体   English

JPA/Hibernate5 通过序列名称获取序列 nextval

[英]JPA/Hibernate5 get sequence nextval by sequence name

How can I get sequence nextval in JPA or Hibernate 5 by sequence name ?如何通过sequence nameJPAHibernate 5获取sequence nextval

I have sequence the following TEST_SEQ in Oracle DB and ANOTHER_NAME_SEQ in Postgresql DB.我在Oracle DB 中对以下TEST_SEQPostgresql DB 中的ANOTHER_NAME_SEQ

I need a method with following signature我需要一个具有以下签名的方法

public Long getSequenceByName(String sequenceName){}

And when I call this method it must return nextval from DB which is now used.当我调用这个方法时,它必须从现在使用的 DB 返回nextval

I have a couple of ideas, but they are not suitable.我有几个想法,但都不合适。

1) Store native query for each DB in properties and write method like this: 1)将每个数据库的本机查询存储在属性中,并像这样编写方法:

@Value("${query}")//"SELECT {name}.NEXTVAL FROM DUAL"
private StringQuery;

public Long getSequenceByName(String sequenceName){
    uery q = em.createNativeQuery(StringQuery.replace("{name}", sequenceName));
    return (java.math.BigDecimal) q.getSingleResult();
  }

But I need to store the query string with placeholders and replace placeholder to sequence name, store query for each DB.但是我需要用占位符存储查询字符串并将占位符替换为序列名称,存储每个数据库的查询。

2) Create entity with only one field @Id . 2) 创建只有一个字段@Id实体。 Insert entity and getId(sequence value).插入实体和 getId(序列值)。

But if in different DB is different sequence names - ???但是如果在不同的数据库中是不同的序列名称 - ???

3) Use this . 3)使用这个 But It for hibernate 3 and I don't know if this is a good approach.但它用于 hibernate 3,我不知道这是否是一个好方法。

EDIT:编辑:

I try this solution:我尝试这个解决方案:

@Component
public class SequenseRepository {

    @PersistenceContext
    private EntityManager em;

    @Transactional
    public Long getID(final String sequenceName) {
        final List<Long> ids = new ArrayList<>(1);

        Session session = em.unwrap(Session.class);
        session.doWork(connection -> {
            DialectResolver dialectResolver = new StandardDialectResolver();
            Dialect dialect =  dialectResolver.resolveDialect((DialectResolutionInfo) connection.getMetaData());
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
            try {
                preparedStatement = connection.prepareStatement( dialect.getSequenceNextValString(sequenceName));
                resultSet = preparedStatement.executeQuery();
                resultSet.next();
                ids.add(resultSet.getLong(1));
            }catch (SQLException e) {
                throw e;
            } finally {
                if(preparedStatement != null) {
                    preparedStatement.close();
                }
                if(resultSet != null) {
                    resultSet.close();
                }
            }
        });

        return ids.get(0);
    }
}

And I get exeption:我得到了豁免:

java.lang.ClassCastException: oracle.jdbc.driver.OracleDatabaseMetaData cannot be cast to org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo&#xd;

I found solution thanks to this article enter link description here 我找到了解决方案,感谢这篇文章在这里输入链接描述

    public interface SequenceRepository {
    int getNext(String sequenceName);
   }

and implementation for each DB: 和每个DB的实现:

@Profile("oracle")
@Component("oracleSequenceRepository")
public class OracleSequenceRepository implements SequenceRepository{

    private final DataSource dataSource;

    @Autowired
    public OracleSequenceRepository(@Qualifier("dataSource") DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Transactional(readOnly = true)
    @Override
    public int getNext(String sequenceName) {
        AbstractSequenceMaxValueIncrementer incr = new OracleSequenceMaxValueIncrementer(this.dataSource, sequenceName);
        return incr.nextIntValue();
    }
}

and

@Profile("postgre")
@Component("postgresSequenceRepository")
public class PostgreSequenceRepository implements SequenceRepository{

    private final DataSource dataSource;

    @Autowired
    public PostgreSequenceRepository(@Qualifier("dataSource") DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Transactional(readOnly = true)
    @Override
    public int getNext(String sequenceName) {
        AbstractSequenceMaxValueIncrementer incr = new PostgresSequenceMaxValueIncrementer(this.dataSource, sequenceName);
        return incr.nextIntValue();
    }
}

Try this:尝试这个:

// Get metadata from connection
DatabaseMetaData metaData = connection.getMetaData();

// Create adapter between MetaData and DialectResolutionInfo
DialectResolutionInfo info = new DatabaseMetaDataDialectResolutionInfoAdapter(metaData);

// Resolve dialect
DialectResolver dialectResolver = new StandardDialectResolver();
Dialect dialect = dialectResolver.resolveDialect(info);

// Use it
System.out.println(dialect.getSelectSequenceNextValString(sequenceName));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM