복붙노트

[SQL] 데이터베이스를 사용하여 최대 절전 모드에서 다음 시퀀스 값을 가져

SQL

데이터베이스를 사용하여 최대 절전 모드에서 다음 시퀀스 값을 가져

I는 시퀀스에서 설정해야하는 NON-ID 필드가 엔티티를 갖는다. 현재, 나는 시퀀스의 첫 번째 값을 가져 클라이언트 측에 저장하고 그 값에서 계산한다.

그러나, 나는이 일의 "더 나은"방법을 찾고 있어요. 나는 다음 순서 값을 가져올 수있는 방법을 시행하고있다 :

public Long getNextKey()
{
    Query query = session.createSQLQuery( "select nextval('mySequence')" );
    Long key = ((BigInteger) query.uniqueResult()).longValue();
    return key;
}

그러나,이 방법은 크게 성능 (- 5740ms에서 13648ms에 ~ 5000 개체의 생성 3의 요인에 의해 둔화됩니다)을 줄일 수 있습니다.

나는 "가짜"엔티티를 추가하는 것을 시도했다 :

@Entity
@SequenceGenerator(name = "sequence", sequenceName = "mySequence")
public class SequenceFetcher
{
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
    private long                      id;

    public long getId() {
        return id;
    }
}

그러나이 방법은 (IDS는 반환이 모두 0이었다) 작업 중 하나를하지 않았다.

누군가의 조언을 내게 얼마나 효율적으로 최대 절전 모드를 사용하여 다음 순서 값을 가져올 수 있습니까?

편집 : 조사를, 나는 호출하면 검색어 쿼리 = 그것은 Session.createSQLQuery ( "의 nextval ( 'mySequence'를) 선택") 것을 발견했다; 훨씬 더 비효율적 때문에 하이버 네이트의 @ GeneratedValue-를 사용하여보다이다 든 @GeneratedValue 의해 개시된 시퀀스에 액세스 할 때의 인출 수를 감소 관리한다.

나는 70,000 엔티티 (70,000 기본 키가 같은 순서에서 가져온 따라서으로) 만들 때 예를 들어, 나는 모든 것을 내가 필요를 얻을.

하지만 Hibernate는 1404 선택의 nextval ( 'local_key_sequence') 명령을 실행합니다. 참고 : 데이터베이스 측면에서, 캐싱이 1로 설정됩니다.

내가 수동으로 모든 데이터를 가져하려고하면, 그것은 나에게 70,000 선택, 성능에 따라서 큰 차이를 취할 것입니다. 사람이 최대 절전 모드의 내부 기능을 알고 있나요, 어떻게 수동으로 재현?

해결법

  1. ==============================

    1.여기에 나를 위해 일한 것입니다 (오라클 특정,하지만 스칼라를 사용하는 열쇠가 될 것 같다)

    여기에 나를 위해 일한 것입니다 (오라클 특정,하지만 스칼라를 사용하는 열쇠가 될 것 같다)

    Long getNext() {
        Query query = 
            session.createSQLQuery("select MYSEQ.nextval as num from dual")
                .addScalar("num", StandardBasicTypes.BIG_INTEGER);
    
        return ((BigInteger) query.uniqueResult()).longValue();
    }
    

    여기에 포스터 덕분에 : 스프링 소스 포럼

  2. ==============================

    2.당신은 다음과 같은 데이터베이스의 독립을 위해 최대 절전 모드 방언의 API를 사용할 수 있습니다

    당신은 다음과 같은 데이터베이스의 독립을 위해 최대 절전 모드 방언의 API를 사용할 수 있습니다

    class SequenceValueGetter {
        private SessionFactory sessionFactory;
    
        // For Hibernate 3
        public Long getId(final String sequenceName) {
            final List<Long> ids = new ArrayList<Long>(1);
    
            sessionFactory.getCurrentSession().doWork(new Work() {
                public void execute(Connection connection) throws SQLException {
                    DialectResolver dialectResolver = new StandardDialectResolver();
                    Dialect dialect =  dialectResolver.resolveDialect(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);
        }
    
        // For Hibernate 4
        public Long getID(final String sequenceName) {
            ReturningWork<Long> maxReturningWork = new ReturningWork<Long>() {
                @Override
                public Long execute(Connection connection) throws SQLException {
                    DialectResolver dialectResolver = new StandardDialectResolver();
                    Dialect dialect =  dialectResolver.resolveDialect(connection.getMetaData());
                    PreparedStatement preparedStatement = null;
                    ResultSet resultSet = null;
                    try {
                        preparedStatement = connection.prepareStatement( dialect.getSequenceNextValString(sequenceName));
                        resultSet = preparedStatement.executeQuery();
                        resultSet.next();
                        return resultSet.getLong(1);
                    }catch (SQLException e) {
                        throw e;
                    } finally {
                        if(preparedStatement != null) {
                            preparedStatement.close();
                        }
                        if(resultSet != null) {
                            resultSet.close();
                        }
                    }
    
                }
            };
            Long maxRecord = sessionFactory.getCurrentSession().doReturningWork(maxReturningWork);
            return maxRecord;
        }
    
    }
    
  3. ==============================

    3.나는 해결책을 발견 :

    나는 해결책을 발견 :

    public class DefaultPostgresKeyServer
    {
        private Session session;
        private Iterator<BigInteger> iter;
        private long batchSize;
    
        public DefaultPostgresKeyServer (Session sess, long batchFetchSize)
        {
            this.session=sess;
            batchSize = batchFetchSize;
            iter = Collections.<BigInteger>emptyList().iterator();
        }
    
            @SuppressWarnings("unchecked")
            public Long getNextKey()
            {
                if ( ! iter.hasNext() )
                {
                    Query query = session.createSQLQuery( "SELECT nextval( 'mySchema.mySequence' ) FROM generate_series( 1, " + batchSize + " )" );
    
                    iter = (Iterator<BigInteger>) query.list().iterator();
                }
                return iter.next().longValue() ;
            }
    
    }
    
  4. ==============================

    4.Oracle을 사용하는 경우, 순서에 대한 캐시 크기를 지정하는 것이 좋습니다. 당신이 정기적으로 5K의 일괄 적으로 객체를 생성하는 경우, 당신은 단지 1000 - 5000 우리는 대리모 기본 키에 사용되는 시퀀스를했고, 자바 하락에 ETL 프로세스의 실행 시간은 손으로 쓴 것을 놀랐다으로 설정할 수 있습니다 반으로.

    Oracle을 사용하는 경우, 순서에 대한 캐시 크기를 지정하는 것이 좋습니다. 당신이 정기적으로 5K의 일괄 적으로 객체를 생성하는 경우, 당신은 단지 1000 - 5000 우리는 대리모 기본 키에 사용되는 시퀀스를했고, 자바 하락에 ETL 프로세스의 실행 시간은 손으로 쓴 것을 놀랐다으로 설정할 수 있습니다 반으로.

    나는 코멘트에 서식 코드를 붙여 넣 없습니다. 여기 시퀀스 DDL이다 :

    create sequence seq_mytable_sid 
    minvalue 1 
    maxvalue 999999999999999999999999999 
    increment by 1 
    start with 1 
    cache 1000 
    order  
    nocycle;
    
  5. ==============================

    5.새로운 ID를 얻으려면, 당신이해야 할 엔티티 관리자를 플러시입니다. GETNEXT () 메소드를 아래 참조 :

    새로운 ID를 얻으려면, 당신이해야 할 엔티티 관리자를 플러시입니다. GETNEXT () 메소드를 아래 참조 :

    @Entity
    @SequenceGenerator(name = "sequence", sequenceName = "mySequence")
    public class SequenceFetcher
    {
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
        private long id;
    
        public long getId() {
            return id;
        }
    
        public static long getNext(EntityManager em) {
            SequenceFetcher sf = new SequenceFetcher();
            em.persist(sf);
            em.flush();
            return sf.getId();
        }
    }
    
  6. ==============================

    6.POSTGRESQL

    POSTGRESQL

    String psqlAutoincrementQuery = "SELECT NEXTVAL(CONCAT(:psqlTableName, '_id_seq')) as id";
    
    Long psqlAutoincrement = (Long) YOUR_SESSION_OBJ.createSQLQuery(psqlAutoincrementQuery)
                                                          .addScalar("id", Hibernate.LONG)
                                                          .setParameter("psqlTableName", psqlTableName)
                                                          .uniqueResult();
    

    MYSQL

    String mysqlAutoincrementQuery = "SELECT AUTO_INCREMENT as id FROM information_schema.tables WHERE table_name = :mysqlTableName AND table_schema = DATABASE()";
    
    Long mysqlAutoincrement = (Long) YOUR_SESSION_OBJ.createSQLQuery(mysqlAutoincrementQuery)
                                                              .addScalar("id", Hibernate.LONG)
                                                              .setParameter("mysqlTableName", mysqlTableName)                                                              
                                                              .uniqueResult();
    
  7. ==============================

    7.재미있는 당신을 위해 작동합니다. 나는 당신의 솔루션을 시도 할 때 오류가 그 말을, 와서 "유형 불일치 :은 SQLQuery에서 쿼리로 변환 할 수 없습니다." -> 그러므로 내 솔루션의 외모와 같은 :

    재미있는 당신을 위해 작동합니다. 나는 당신의 솔루션을 시도 할 때 오류가 그 말을, 와서 "유형 불일치 :은 SQLQuery에서 쿼리로 변환 할 수 없습니다." -> 그러므로 내 솔루션의 외모와 같은 :

    SQLQuery query = session.createSQLQuery("select nextval('SEQUENCE_NAME')");
    Long nextValue = ((BigInteger)query.uniqueResult()).longValue();
    

    이 솔루션을 통해 나는 성능 문제로 실행되지 않았다.

    그리고 당신은 단지 정보 제공의 목적으로 알고 싶다면, 당신의 값을 다시 설정하는 것을 잊지 마세요.

        --nextValue;
        query = session.createSQLQuery("select setval('SEQUENCE_NAME'," + nextValue + ")");
    
  8. ==============================

    8.봄 5는 일부 내장 도우미 클래스가 있습니다 : 조직 / 스프링 프레임 워크 / JDBC / 지원 / 증가 기

    봄 5는 일부 내장 도우미 클래스가 있습니다 : 조직 / 스프링 프레임 워크 / JDBC / 지원 / 증가 기

  9. ==============================

    9.여기에 내가 그것을 할 방법입니다 :

    여기에 내가 그것을 할 방법입니다 :

    @Entity
    public class ServerInstanceSeq
    {
        @Id //mysql bigint(20)
        @SequenceGenerator(name="ServerInstanceIdSeqName", sequenceName="ServerInstanceIdSeq", allocationSize=20)
        @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ServerInstanceIdSeqName")
        public Long id;
    
    }
    
    ServerInstanceSeq sis = new ServerInstanceSeq();
    session.beginTransaction();
    session.save(sis);
    session.getTransaction().commit();
    System.out.println("sis.id after save: "+sis.id);
    
  10. ==============================

    10.SequenceGenerator 가짜 엔티티와 당신의 아이디어는 좋다.

    SequenceGenerator 가짜 엔티티와 당신의 아이디어는 좋다.

    @Id
    @GenericGenerator(name = "my_seq", strategy = "sequence", parameters = {
            @org.hibernate.annotations.Parameter(name = "sequence_name", value = "MY_CUSTOM_NAMED_SQN"),
    })
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "my_seq")
    

    키 이름 "sequence_name"로 매개 변수를 사용하는 것이 중요합니다. 라인에서 최대 절전 모드 클래스 SequenceStyleGenerator에 디버깅 세션을 실행, 구성 (...) 메소드 최종 qualifiedName가 sequenceName = determineSequenceName (PARAMS, 방언, jdbcEnvironment); 시퀀스 이름이 Hibernate에 의해 계산하는 방법에 대한 자세한 내용을 볼 수 있습니다. 당신은 또한 사용할 수 있습니다 몇 가지 기본 설정이 있습니다.

    가짜 엔티티 후, 나는 CrudRepository을 만들어 :

    public interface SequenceRepository extends CrudRepository<SequenceGenerator, Long> {}
    

    Junit와에서, 나는 SequenceRepository의 저장 방법을 문의하십시오.

    SequenceGenerator sequenceObject 새로운 SequenceGenerator을 () =;         SequenceGenerator 결과 = sequenceRepository.save (sequenceObject);

    이 작업을 수행 할 수있는 더 좋은 방법이 있다면 (아마도 대신 아이디의 필드의 모든 유형에 발전기 지원),이 "속임수"대신 사용하는 것이 더 이상 행복 할 것입니다.

  11. from https://stackoverflow.com/questions/6386888/get-next-sequence-value-from-database-using-hibernate by cc-by-sa and MIT license