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 create
và create-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
Đ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. –