[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.여기에 나를 위해 일한 것입니다 (오라클 특정,하지만 스칼라를 사용하는 열쇠가 될 것 같다)
여기에 나를 위해 일한 것입니다 (오라클 특정,하지만 스칼라를 사용하는 열쇠가 될 것 같다)
Long getNext() { Query query = session.createSQLQuery("select MYSEQ.nextval as num from dual") .addScalar("num", StandardBasicTypes.BIG_INTEGER); return ((BigInteger) query.uniqueResult()).longValue(); }
여기에 포스터 덕분에 : 스프링 소스 포럼
-
==============================
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.나는 해결책을 발견 :
나는 해결책을 발견 :
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.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.새로운 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.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.재미있는 당신을 위해 작동합니다. 나는 당신의 솔루션을 시도 할 때 오류가 그 말을, 와서 "유형 불일치 :은 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.봄 5는 일부 내장 도우미 클래스가 있습니다 : 조직 / 스프링 프레임 워크 / JDBC / 지원 / 증가 기
봄 5는 일부 내장 도우미 클래스가 있습니다 : 조직 / 스프링 프레임 워크 / JDBC / 지원 / 증가 기
-
==============================
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.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);
이 작업을 수행 할 수있는 더 좋은 방법이 있다면 (아마도 대신 아이디의 필드의 모든 유형에 발전기 지원),이 "속임수"대신 사용하는 것이 더 이상 행복 할 것입니다.
from https://stackoverflow.com/questions/6386888/get-next-sequence-value-from-database-using-hibernate by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] 자체 참조 테이블에 SQL 재귀 쿼리 (오라클) (0) | 2020.04.19 |
---|---|
[SQL] 'dateAdded'에 대한 잘못된 기본값 (0) | 2020.04.19 |
[SQL] SQL Server 2005의 시간 차이를 찾기 위해 두 날짜를 비교하는 방법, 날짜 조작 (0) | 2020.04.19 |
[SQL] 2008 SQL에 외래 키 관계에서 삭제 정책을 생성? (0) | 2020.04.19 |
[SQL] 형식화 된 목록에서 IDataReader에 가져 오기 (0) | 2020.04.19 |