В чем разница между: идентификатором последовательности с использованием JPA @TableGenerator, @GeneratedValue и базы данных Auto_Increment
Q1.: В чем разница между применением идентификатора последовательности в базе данных с помощью
A.
CREATE TABLE Person
(
id long NOT NULL AUTO_INCREMENT
...
PRIMARY KEY (id)
)
против
B.
@Entity
public class Person {
@Id
@TableGenerator(name="TABLE_GEN", table="SEQUENCE_TABLE", pkColumnName="SEQ_NAME",
valueColumnName="SEQ_COUNT", pkColumnValue="PERSON_SEQ")
@GeneratedValue(strategy=GenerationType.TABLE, generator="TABLE_GEN")
private long id;
...
}
Моя система очень параллельна. Поскольку моя БД является сервером Microsoft SQL, я не думаю, что он поддерживает @SequenceGenerator
так что я должен остаться с @TableGenerator
который склонен к проблемам параллелизма.
Q2. Эта ссылка здесь ( http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing) предполагает, что B может страдать от проблем параллелизма, но я не понимаю предложенное решение. Я был бы очень признателен, если бы кто-нибудь мог объяснить мне, как избежать проблем с параллелизмом в B. Вот фрагмент их решения:
If a large sequence pre-allocation size is used this becomes less of an issue, because the sequence table is rarely accessed.
Q2.1: о каком размере выделения мы говорим здесь? Я должен делать allocationSize=10
или же allocationSize=100
?
Some JPA providers use a separate (non-JTA) connection to allocate the sequence ids in, avoiding or limiting this issue. In this case, if you use a JTA data-source connection, it is important to also include a non-JTA data-source connection in your persistence.xml.
Q2.2: я использую EclipseLink в качестве моего провайдера; я должен делать то, что он предлагает выше?
Q3. Если В страдает от проблем параллелизма, страдает ли А то же самое?
2 ответа
A: использует генерацию идентификатора IDENTITY, @GeneratedValue(IDENTITY)
B: использует генерацию идентификатора TABLE
JPA поддерживает три типа, IDENTITY, SEQUENCE and TABLE.
Есть компромиссы с обоими.
IDENTITY не разрешает предварительное распределение, поэтому требует дополнительного SELECT после каждой INSERT, предотвращает пакетную запись и требует сброса для доступа к id, что может привести к плохому параллелизму.
TABLE допускает предварительное распределение, но может иметь проблемы с параллелизмом при блокировках таблицы последовательности.
Технически генерация идентификатора SEQUENCE является лучшей, но не все базы данных поддерживают ее.
При использовании последовательности TABLE, если вы используете размер предаллокации 100, тогда только каждые 100 вставок будут блокировать строку в таблице последовательностей, поэтому, если у вас обычно нет 100 вставок одновременно, вы не понесете никаких потерь в параллелизм. Если ваше приложение делает много вставок, возможно, используйте значение 1000 или больше.
EclipseLink будет использовать отдельную транзакцию для секвенирования TABLE, поэтому любая проблема параллелизма с блокировками таблицы последовательности будет уменьшена. Если вы используете JTA, вам нужно указать не-jta-datasource для этого и настроить пул соединений-последовательностей в ваших свойствах persistence.xml.
Используя TableGenerator, следующее значение идентификатора будет просматриваться и поддерживаться в таблице и в основном поддерживаться JPA, а не вашей базой данных. Это может привести к проблеме параллелизма, когда у вас есть несколько потоков, обращающихся к вашей базе данных и пытающихся выяснить, какое может быть следующее значение для поля id.
Тип auto_increment заставит вашу базу данных позаботиться о следующем идентификаторе вашей таблицы, т.е. он будет автоматически определяться сервером базы данных при запуске вставки, что, безусловно, безопасно для параллелизма.
Обновить:
Есть ли что-то, что удерживает вас от использования GenerationType.AUTO?
GenerationType.AUTO выбирает подходящий способ получения идентификатора для вашей сущности. Поэтому в лучшем случае использует встроенную функциональность. Однако вам нужно проверить сгенерированные SQL и посмотреть, что именно там происходит - поскольку MSSQL не предлагает последовательности, я предполагаю, что он будет использовать GenerationType.IDENTITY.
Как уже говорилось, столбец auto_increment позаботится о назначении следующего значения id, т.е. здесь нет проблемы параллелизма - даже если несколько потоков параллельно работают с базой данных. Задача состоит в том, чтобы передать эту функцию для использования JPA.