Поле идентификатора объекта JPA с последовательностью SQL Server 2022

Я пытаюсь подключить службу Spring Boot к базе данных SQL Server 2022, но у меня возникают проблемы с последовательностью:

public class SomeEntity {
    @Id
    @SequenceGenerator(name = "some_seq", schema = "sch_some", sequenceName = "some_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "some_seq")
    @Column(name = "id", columnDefinition = "decimal")
    private Long id;
    ...
}

Это ошибка, которую я получаю, когда пытаюсь сохранить что-то в таблице:

{"date":"2024-07-07T20:50:08,250Z","env":"test","app":"some-service","version":"1.32.0","host": "_","level":"ERROR","logger":"org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]","msg":"Servlet .service() для сервлета [dispatcherServlet] в контексте с путем [] выдал исключение [Ошибка обработки запроса; вложенное исключение — org.springframework.dao.InvalidDataAccessResourceUsageException: ошибка при выполнении изолированной работы; SQL [н/д]; hibernate.Exception.SQLGrammarException: ошибка при выполнении изолированной работы] с основной причиной","thread":"http-nio-8080-exec-1","context":[],"eventId":"com.microsoft.sqlserver. jdbc.SQLServerException","stack":"com.microsoft.sqlserver.jdbc.SQLServerException: неверное имя объекта 'some_db.sch_some.some_seq'.\n\tat com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java) :262)\n\tat com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1624)\n\tat com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:594)\n\ tat com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:524)\n\tat com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7194)\n\tat com.microsoft .sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:2979)\n\tat com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:248)\n\tat com.microsoft.sqlserver.jdbc.SQLServerStatement .executeStatement(SQLServerStatement.java:223)\n\tat com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeQuery(SQLServerPreparedStatement.java:446)\n\tat com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java :52)\n\tat com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)\n\tat

Вот как я создал последовательность

create sequence SCH_SOME.SOME_SEQ start with 1 increment by 1;

Поскольку у меня есть еще одна таблица в этой схеме, в которой нет проблем со вставкой, я думаю, что это может быть проблема с доступом. Я также пытался запустить оператор выбора гранта, как в Oracle, но в итоге получил вот это

Ошибка SQL [4606] [S0001]: Предоставленная или отозванная привилегия SELECT несовместима с объектом.

Итак, есть ли в SQL Server другой набор разрешений, для которого мне нужно предоставить грант? Я также пробовал UPDATE и ALTER, но это не имело значения. Если бы кто-нибудь мог пролить свет на эти вопросы, мы были бы очень признательны. Спасибо.

Обновление. Я провел некоторую отладку и обнаружил, что именно это генерирует Hibernate:

Hibernate: 
    select
        next_val as id_val 
    from
        some_db.sch_some.some_seq with (updlock,
        rowlock)

Я не думаю, что это правильный синтаксис для SQL Server.

Этот вопрос задавался много раз, например. stackoverflow.com/questions/49037803/… и вам нужно проверить одну вещь: у вас установлены последние версии драйверов и вы используете правильный диалект SqlServer.

Dale K 08.07.2024 04:13

Какие версии Spring, Hibernate и JPA вы используете? Используемый им синтаксис совершенно неверен для SQL Server, он должен быть ближе к select next value for SCH_SOME.SOME_SEQ as [id_val];. Ссылка: db<>рабочий пример

AlwaysLearning 08.07.2024 05:32

Да, это правильно, в итоге я изменил диалект спящего режима с org.hibernate.dialect.SQLServerDialect на org.hibernate.dialect.SQLServer2012Dialect, и это устранило проблему.

kayelbb 08.07.2024 19:42
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
3
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Сообщение об ошибке, которое вы видите, связано с тем, что Hibernate пытается использовать последовательность способом, который не поддерживается SQL Server. В SQL Server доступ к последовательностям осуществляется не как к таблицам, а через вызов функции. Правильный синтаксис для получения следующего значения из последовательности в SQL Server — NEXT VALUE FOR sequence_name. Однако Hibernate генерирует оператор SQL, как если бы последовательность была таблицей, что неверно для SQL Server. Чтобы решить эту проблему, вы можете использовать аннотацию @TableGenerator вместо @SequenceGenerator. Аннотация @TableGenerator — это портативный способ генерации идентификаторов, который хорошо работает с базами данных, которые не поддерживают последовательности, например SQL Server. Вот пример того, как вы можете изменить свой код:

@Id
@TableGenerator(name = "some_gen", table = "id_gen", pkColumnName = "gen_name", valueColumnName = "gen_val", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.TABLE, generator = "some_gen")
@Column(name = "id", columnDefinition = "decimal")
private Long id;

В приведенном выше коде id_gen — это таблица, которую Hibernate будет использовать для генерации идентификаторов. В этой таблице должно быть два столбца: gen_name и gen_val. В столбце gen_name хранится имя генератора, а в столбце gen_val — текущее значение идентификатора. Обратите внимание, что вам нужно будет создать таблицу id_gen вручную в вашей базе данных. Вот пример того, как вы можете это сделать:

CREATE TABLE id_gen (
    gen_name VARCHAR(255) NOT NULL,
    gen_val BIGINT NOT NULL,
    PRIMARY KEY (gen_name)
);

После создания таблицы вам необходимо вставить строку для вашего генератора:

INSERT INTO id_gen (gen_name, gen_val) VALUES ('some_gen', 0);

Это должно решить проблему, с которой вы столкнулись.

Спасибо за ответ. В итоге я изменил диалект спящего режима с org.hibernate.dialect.SQLServerDialect на org.hibernate.dialect.SQLServer2012Dialect, и это устранило проблему.

kayelbb 08.07.2024 19:42

Другие вопросы по теме