В чем разница между идентификатором последовательности с использованием JPA @TableGenerator, @GeneratedValue и базы данных Auto_Increment
Q1.: В чем разница между применением идентификатора последовательности в базе данных с помощью
а.
CREATE TABLE Person
(
id long NOT NULL AUTO_INCREMENT
...
PRIMARY KEY (id)
)
против
В.
@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
, который подвержен проблемам concurrency.
Q2. Эта ссылка здесь (http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Advanced_Sequencing) предполагает, что B может пострадать от concurrency но я не понимаю предлагаемого решения. Я был бы очень признателен, если бы кто-нибудь мог объяснить мне, как избежать проблем concurrency с 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. Если B страдает от проблем concurrency, имеет ли A то же самое?
Ответы
Ответ 1
Используя TableGenerator, следующее значение id будет проверяться и поддерживаться в таблице и в основном поддерживается JPA, а не вашей базой данных. Это может привести к ошибке concurrency, когда у вас есть несколько потоков, обращающихся к вашей базе данных и пытающихся выяснить, что может быть следующим значением для поля id.
Тип auto_increment заставит вашу базу данных заботиться о следующем id вашей таблицы, т.е. он будет автоматически определяться сервером базы данных при запуске вставки, что, безусловно, является concurrency безопасным.
Update:
Есть ли что-то, что мешает вам использовать GenerationType.AUTO?
GenerationType.AUTO действительно выбирает подходящий способ для получения идентификатора для вашего объекта. Поэтому в лучшем случае используется встроенная функциональность. Однако вам нужно проверить сгенерированные SQL-запросы и посмотреть, что именно там происходит - поскольку MSSQL не предлагает последовательности, я предполагаю, что он будет использовать GenerationType.IDENTITY.
Как сказано, столбец auto_increment заботится о назначении следующего значения id, т.е. там нет проблемы concurrency - даже с несколькими потоками, параллельно использующими базу данных. Задача состоит в передаче этой функции, которая будет использоваться JPA.
Ответ 2
A: используется генерация идентификатора IDENTITY, @GeneratedValue (IDENTITY)
B: использует генерацию TABLE id
JPA поддерживает три типа: IDENTITY, SEQUENCE и TABLE.
Есть компромиссы с обоими.
ИДЕНТИФИКАЦИЯ не разрешает предварительное выделение, поэтому требуется дополнительный SELECT после каждого INSERT, предотвращает пакетную запись и требует сброса для доступа к id, что может привести к плохим concurrency.
TABLE допускает предварительное распределение, но может иметь concurrency проблемы с блокировками в таблице последовательностей.
Технически генерация идентификаторов SEQUENCE является лучшей, но не все базы данных поддерживают ее.
С помощью последовательности TABLE, если вы используете размер preallocaiton 100, тогда только каждые 100 вложений будут блокировать строку в таблице последовательности, так что, пока вы обычно не используете 100 вставок одновременно, вы не будете страдать любая потеря в concurrency. Если в приложении много вставок, возможно, используйте значение 1000 или больше.
EclipseLink будет использовать отдельную транзакцию для последовательности TABLE, поэтому любая проблема concurrency с блокировками в таблице последовательности будет уменьшена. Если вы используете JTA, вам нужно указать источник non-jta-datasource для этого и настроить пул соединений-соединений в свойствах persistence.xml.