2011-11-30 1 views
5

Tôi nhận ra đây là một câu hỏi hibernate hơn Grails. Trong môi trường cân bằng tải (2 nút) tôi thấy rằng các id của đối tượng của tôi đang nhảy xung quanh khá một chút. Ngay cả khi không khởi động lại máy chủ ứng dụng tôi thấy rằng các con số bỏ qua 10 đôi khi 20 con số. Tôi nghi ngờ phiên ngủ đông là bộ nhớ đệm một khối các giá trị chuỗi. Có cách nào để kiểm soát hành vi này với grails 1.3.7 không? Về cơ bản tôi ổn với máy chủ kéo nextval từ DB mỗi khi nó cần một.Tạo chuỗi thế hệ Grails cho Oracle 11g

khai chuỗi đối tượng miền của tôi (cùng với 2 đối tượng):

static mapping = { 
     id generator:'sequence', params:[sequence:'MY_SEQ'] 
    } 

Trả lời

3

Tôi có kể từ khi đi đến cơ sở dữ liệu và sửa đổi trình tự với DDL sau :

ALTER SEQUENCE MY_SEQ NOCACHE; 

Tôi nghĩ đây là giải pháp tốt nhất cho vấn đề này. Có ai nhìn thấy các vấn đề tiềm ẩn với cách tiếp cận này không?

Cảm ơn tất cả!

+1

Điều này sẽ làm việc tốt. Tôi nghĩ rằng Hibernate sẽ luôn gọi MY_SEQ.NEXTVAL bất kể chuỗi có được lưu trữ hay không; bộ nhớ đệm xảy ra bên trong Oracle, không phải ở mức Hibernate hoặc JDBC. Lưu ý rằng nếu ứng dụng của bạn phụ thuộc vào không có khoảng trống trong một chuỗi số, thì việc sử dụng chuỗi Oracle có thể không phải là cách tiếp cận đúng. Không có gì đảm bảo rằng bạn sẽ không có bất kỳ khoảng trống nào trong chuỗi - bạn có thể có các chuỗi khác nhau nhận các giá trị chuỗi hoặc bạn có thể có các lần xuất hiện lại. –

3

Vấn đề bộ nhớ đệm là vì Hibernate mặc định là một phương ngữ Oracle mà không có hai điều. Nó tạo ra một chuỗi được chia sẻ trên tất cả các bảng để tạo khóa chính và trình tự lưu trữ 20 số tại một thời điểm, nếu chúng không được sử dụng trong một khung thời gian cụ thể, Oracle sẽ loại bỏ phần còn lại.

Giải pháp Oracle sau đây đến từ một bài đăng của Burt Beckwith, với một tweek để ngăn chặn chuỗi Oracle từ các số bộ nhớ đệm. Do đó, phương ngữ này sẽ thực hiện hai điều cho bạn:

  • Nó sẽ tạo một chuỗi duy nhất cho mỗi bảng, do đó chuỗi không được chia sẻ và số khóa chính không được chia trên bảng.
  • Nó sẽ vô hiệu hóa bộ nhớ đệm của các số trong Oracle, vì vậy bạn sẽ không mất bất kỳ số thứ tự nào trong bộ nhớ cache đã hết hạn. Điều này được thiết lập trong thuộc tính PARAMETERS với lệnh NOCACHE.

Vì bạn đang xác định trình tự bảng của bạn trong ánh xạ, bạn có thể loại bỏ chuỗi trên mỗi bảng và để lại định nghĩa thứ tự NOCACHE để đạt được kết quả mong muốn.

Ngoài ra, bạn sẽ cần phải hủy chuỗi khỏi không gian bảng hiện có của mình, vì Grails sẽ không tạo lại nó, trừ trường hợp createcreate-drop. Khi thực hiện điều này, bạn cũng có thể muốn tăng giá trị bắt đầu của chuỗi mới để tránh xung đột các vấn đề chính chính với các khóa đã được cơ sở dữ liệu sử dụng.

Để sử dụng phương ngữ, hãy thêm dialect = SequencePerTableOracleDialect vào tệp DataSource.groovy của bạn trong phần đóng định nghĩa dữ liệuSource.

import java.util.Properties; 

import org.hibernate.dialect.Dialect; 
import org.hibernate.dialect.Oracle10gDialect; 
import org.hibernate.id.PersistentIdentifierGenerator; 
import org.hibernate.id.SequenceGenerator; 
import org.hibernate.type.Type; 

public class SequencePerTableOracleDialect extends Oracle10gDialect { 
    public static final String PARAMETERS = "MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 NOCACHE NOCYCLE"; 

    /** 
    * Get the native identifier generator class. 
    * 
    * @return TableNameSequenceGenerator. 
    */ 
    @Override 
    public Class<?> getNativeIdentifierGeneratorClass() { 
     return TableNameSequenceGenerator.class; 
    } 

    /** 
    * Creates a sequence per table instead of the default behavior of one 
    * sequence. 
    */ 
    public static class TableNameSequenceGenerator extends SequenceGenerator { 

     /** 
     * {@inheritDoc} If the parameters do not contain a 
     * {@link SequenceGenerator#SEQUENCE} name, we assign one based on the 
     * table name. 
     */ 
     @Override 
     public void configure(final Type type, final Properties params, 
       final Dialect dialect) { 
      if (params.getProperty(SEQUENCE) == null 
        || params.getProperty(SEQUENCE).length() == 0) { 
       /* Sequence per table */ 
       String tableName = params 
         .getProperty(PersistentIdentifierGenerator.TABLE); 
       if (tableName != null) { 
        params.setProperty(SEQUENCE, createSequenceName(tableName)); 
       } 
       /* Non-Caching Sequence */ 
       params.setProperty(PARAMETERS, SequencePerTableOracleDialect.PARAMETERS); 
      } 
      super.configure(type, params, dialect); 
     } 

     /** 
     * Construct a sequence name from a table name. 
     * 
     * @param tableName 
     *   the table name 
     * @return the sequence name 
     */ 
     String createSequenceName(final String tableName) { 
      return "seq_" + tableName; 
     } 
    } 
} 

Liên kết này có một số lịch sử về câu hỏi này, với một liên kết đến mã gốc Burt, và một phản ứng đối với PostgreSQL: Hibernate & postgreSQL with Grails

+0

Cảm ơn vì điều đó! Bạn có nói rằng không có cách nào để xác định NOCACHE hoặc allocSize trong params cho một chuỗi? – dbrin

+0

Không xa như tôi biết, vì đó sẽ là cơ sở dữ liệu SQL cụ thể, mà sẽ buộc xuống ứng dụng của bạn đến một thương hiệu cụ thể của cơ sở dữ liệu. – schmolly159

+0

Xin lỗi schmolly. Đó không phải là giải pháp mà tôi đang tìm kiếm. Tôi sẽ đánh dấu nó vì nó có thể hữu ích cho người khác. Xem giải pháp của tôi để sửa chữa dễ dàng thay thế. ...ít nhất tôi nghĩ như vậy :) – dbrin