Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

[Dúvida] Problemas envolvendo tabela particionada

Estou trabalhando com tabelas particionadas usando Postgres e Spring Boot, consegui fazer a partição e nos testes que eu fiz o método GET e POST está funcionando do jeito que eu queria, porém gostaria de ajuda para resolver o seguinte erro, que é retornado quando eu inicio a aplicação:

GenerationTarget encountered exception accepting command : Error executing DDL "create table teste (data date not null, id int4 not null, nome varchar(255), primary key (data, id))" via JDBC Statement org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table teste (data date not null, id int4 not null, nome varchar(255), primary key (data, id))" via JDBC Statement at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]

O passo a passo do que eu fiz antes do erro aparecer:

Criei o Model principal, que fará referência a tabela particionada:

@Entity
@Table(name = "teste")
@IdClass(TesteId.class)
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Teste {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "teste_id_seq")
    @SequenceGenerator(name = "teste_id_seq", sequenceName = "teste_id_seq", initialValue = 1, allocationSize = 1)
    private int id;

    @Id
    private LocalDate data;

    private String nome;

}

Criei a classe do id composto:

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
public class TesteId implements Serializable {

    private int id;

    private LocalDate data;

}

E então iniciei a aplicação, tudo rodou normalmente.

Após isso pausei a aplicação e particionei a tabela 'teste' seguindo a documentação do Postgres: https://www.postgresql.org/docs/current/ddl-partitioning.html Tópico: 5.11.2.1. Example

E minha tabela ficou da seguinte forma:

CREATE TABLE IF NOT EXISTS public.teste
(
    data date NOT NULL,
    id integer NOT NULL,
    nome character varying(255) COLLATE pg_catalog."default",
    CONSTRAINT teste_pkey PRIMARY KEY (data, id)
) PARTITION BY RANGE (data);

Então eu iniciei a aplicação novamente e o seguinte erro foi impresso no log:

WARN 16668 --- [ main] o.h.t.s.i.ExceptionHandlerLoggedImpl : GenerationTarget encountered exception accepting command : Error executing DDL "create table teste (data date not null, id int4 not null, nome varchar(255), primary key (data, id))" via JDBC Statement org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "create table teste (data date not null, id int4 not null, nome varchar(255), primary key (data, id))" via JDBC Statement at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final] at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlString(AbstractSchemaMigrator.java:562) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final] at org.hibernate.tool.schema.internal.AbstractSchemaMigrator.applySqlStrings(AbstractSchemaMigrator.java:507) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]

Meu application.properties está assim:

spring.datasource.url=jdbc:postgresql://localhost:5432/teste
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.defer-datasource-initialization=true
spring.datasource.driver-class-name=org.postgresql.Driver
3 respostas

O erro que você está enfrentando está relacionado à criação da tabela particionada no banco de dados. Parece que o Hibernate está tentando criar a tabela "teste" novamente, mesmo que ela já exista no banco de dados após ter sido particionada.

Uma possível solução para esse problema é desabilitar a geração automática de DDL (Data Definition Language) pelo Hibernate, definindo a propriedade spring.jpa.hibernate.ddl-auto como none no seu arquivo application.properties. Isso evitará que o Hibernate tente criar a tabela novamente.

No entanto, observe que essa solução implica que você precisará gerenciar manualmente as alterações no esquema do banco de dados, incluindo a criação das tabelas particionadas. Certifique-se de que todas as alterações necessárias tenham sido aplicadas ao esquema do banco de dados antes de iniciar a aplicação.

Além disso, é importante verificar se a estrutura da tabela particionada está correta de acordo com a documentação do PostgreSQL. Certifique-se de que as partições estejam definidas corretamente e que a chave primária seja consistente em todas as partições.

Outra opção é criar a tabela particionada manualmente no banco de dados e remover a anotação @Table da entidade Teste. Dessa forma, o Hibernate não tentará criar a tabela novamente e usará a tabela existente no banco de dados.

Essas são algumas sugestões para resolver o problema que você está enfrentando ao trabalhar com tabelas particionadas usando o PostgreSQL e o Spring Boot com JPA e Hibernate. Espero que uma dessas soluções seja útil para você.

  • Desabilitar a geração automática de DDL resolve o problema, porém não é a solução que eu desejo, já que não quero gerenciar manualmente todas as alterações no banco de dados.

  • Acredito que forma de particionar está de acordo com a documentação, fiz da seguinte forma:

Tabela original:

CREATE TABLE IF NOT EXISTS public.teste
(
    data date NOT NULL,
    id integer NOT NULL,
    nome character varying(255) COLLATE pg_catalog."default",
    CONSTRAINT teste_pkey PRIMARY KEY (data, id)
)

Processo de particionamento:

CREATE TABLE teste_particionado (
    data date NOT NULL,
    id integer NOT NULL,
    nome character varying(255),
    PRIMARY KEY (data, id)
) PARTITION BY RANGE (data);


CREATE TABLE teste_particionado_2023_01
    PARTITION OF teste_particionado
    FOR VALUES FROM ('2023-01-01') TO ('2023-02-01');

CREATE TABLE teste_particionado_2023_02
    PARTITION OF teste_particionado
    FOR VALUES FROM ('2023-02-01') TO ('2023-03-01');

CREATE TABLE teste_particionado_2023_03
    PARTITION OF teste_particionado
    FOR VALUES FROM ('2023-03-01') TO ('2023-04-01');

CREATE TABLE teste_particionado_2023_04
    PARTITION OF teste_particionado
    FOR VALUES FROM ('2023-04-01') TO ('2023-05-01');

CREATE TABLE teste_particionado_2023_05
    PARTITION OF teste_particionado
    FOR VALUES FROM ('2023-05-01') TO ('2023-06-01');

INSERT INTO teste_particionado SELECT * FROM teste;

ALTER TABLE teste RENAME TO teste_old;
ALTER TABLE teste_particionado RENAME TO teste;

CREATE INDEX ON teste (data);
  • Criar a tabela particionada manualmente no banco seria o ideal para mim, porém remover a anotação @Table não impede que o Hibernate tente criar a tabela, acredito que por conta da anotação @Entity.
@Entity
@IdClass(TesteId.class)
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Teste {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "teste_id_seq")
    @SequenceGenerator(name = "teste_id_seq", sequenceName = "teste_id_seq", initialValue = 1, allocationSize = 1)
    private int id;

    @Id
    private LocalDate data;

    private String nome;

}

Então nenhuma dessas soluções resolveram, mas agradeço pela ajuda.

Existe alguma referência de artigo ou documentação para trabalhar com tabelas particionadas + Spring Boot? Não consegui encontrar nada específico na internet...

solução!
Consegui resolver atualizando o Spring Boot para a última versão e adicionando a seguinte dependência no pom.xml:
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.2.3.Final</version>
        </dependency>