JPA: "Данные слишком длинные для столбца" не изменяется

Одна из моих сущностей Machinery получил String свойство называется notes, JPA 2-Hibernate генерирует схему для меня, в моем случае СУБД - это MySQL.

notes создается как VARCHAR(255) столбец, который прав.

Пользователи начинают создавать записи и все работает отлично, но затем некоторые пользователи получают печально известную Data too long for column "notes" ошибка.

В этом поле недостаточно места для заметок пользователя машины! Без проблем. Давайте изменим схему!

Итак, я открываю свой класс сущности и меняю свойство на:

@Column(length=1000000)
@Lob
private String notes;

Кстати, мой persistence.xml заявляет:

<property name="hibernate.hbm2ddl.auto" value="update" />

После перезапуска приложения я рад, что Hibernate меняет мой notes столбец к LONGTEXT (мне этого достаточно).

Поэтому я сначала пытаюсь использовать свое приложение для создания новой "давно отмеченной" записи, и у меня все еще остается ошибка "Слишком длинные данные", хотя это LONGTEXT сейчас.

Затем я пытаюсь сделать сырье INSERT из командной строки MySQL, и это работает! Я могу вставить длинные заметки в это поле!

Наконец-то я DROP моя локальная / промежуточная схема БД и изменение hibernate.hbm2ddl.auto в persistence.xml в create и это работает.

JPA все еще думает, что это VARCHAR? Есть ли у него какой-то кэш или какое-то место, в котором хранится информация схемы?

Я не могу бросить свою производственную базу данных, очевидно. Итак, что я могу сделать, чтобы сбросить или изменить тип столбца?

Я использую JBossAS7 JPA 2-Hibernate.

9 ответов

Решение

НИЧЕГО ТАКОГО! Я закончил с: - резервное копирование БД - hbm2ddl => CREATE-DROP - hbm2ddl => ОБНОВЛЕНИЕ - восстановление БД

Псих!:(

В окончательной книге Hibernate"Сохранение Java с Hibernate" упоминается об обновлении значения hibernate.hbm2ddl.auto (жирным шрифтом - мое)

Дополнительная опция для этого свойства конфигурации, update, может быть полезна при разработке: она включает встроенный инструмент SchemaUpdate, который может упростить эволюцию схемы. Если включено, Hibernate считывает метаданные базы данных JDBC при запуске и создает новые таблицы и ограничения, сравнивая старую схему с текущими метаданными отображения. Обратите внимание, что эта функциональность зависит от качества метаданных, предоставляемых драйвером JDBC, области, в которой отсутствуют многие драйверы. Поэтому на практике эта функция менее захватывающая и полезная, чем кажется.

Также Hibernate документы предлагают то же самое здесь

Инструмент SchemaUpdate обновит существующую схему с "инкрементными" изменениями. SchemaUpdate зависит от API метаданных JDBC и поэтому не будет работать со всеми драйверами JDBC.

Я попытался повторить ваш вариант использования и обнаружил удивление, что у меня тоже была эта проблема.

У меня есть пользовательский объект, как это

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table( name = "usr" )

public class User {
  @Id
  @GeneratedValue
  private Long id;

  @Column( length = 40, unique = true )
  private String name;

  @Lob
  @Column( length = 100000 )
  private String text;

  public long getId() {
    return id;
  }

  public void setName( String name ) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public String getText() {
    return text;
  }

  public void setText( String text ) {
    this.text = text;
  }

}

и моя настойчивость XML так

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
   <persistence-unit name="jpatest" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.connection.password" value="root"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/jpadatabase"/>
            <property name="hibernate.show-sql" value="true"/>
        </properties>
    </persistence-unit>
</persistence>

Если я изменю значение hibernate.hbm2ddl.auto, чтобы создать и изменить текстовое свойство объекта на

.....

  @Column( length = 255 )
  private String text;
......

Генератор схемы генерирует следующий sql при запуске

DEBUG SchemaExport:415 - drop table if exists usr
DEBUG SchemaExport:415 - create table usr (id bigint not null auto_increment, name varchar(40) unique, text varchar(255), primary key (id)) ENGINE=InnoDB
INFO SchemaExport:281 - schema export complete

Теперь снова меняем свойство в сущности

.....
@Lob
@Column( length = 100000 )
private String text;
.......

Теперь следующий правильный sql генерируется

DEBUG SchemaExport:415 - drop table if exists usr
DEBUG SchemaExport:415 - create table usr (id bigint not null auto_increment, name varchar(40) unique, text longtext, primary key (id)) ENGINE=InnoDB
INFO SchemaExport:281 - schema export complete

Все идет нормально.

Теперь, если я изменяю значение hibernate.hbm2ddl.auto для обновления и повторяю вышеупомянутое изменение в сущности в том же порядке, столбец обновления sql не создается, несмотря на то, что я обновил текстовый столбец с varchar(255) до LONGTEXT

 INFO TableMetadata:65 - table found: jpadatabase.usr
 INFO TableMetadata:66 - columns: [id, text, name]
 INFO TableMetadata:68 - foreign keys: []
 INFO TableMetadata:69 - indexes: [name, primary]
 DEBUG DefaultIdentifierGeneratorFactory:90 - Setting dialect  [org.hibernate.dialect.MySQL5InnoDBDialect]
 INFO SchemaUpdate:217 - schema update complete

Однако, если я использую обновление и вместо изменения свойства я добавляю другое местоположение свойства, тогда корректный sql генерируется снова

DEBUG SchemaUpdate:203 - alter table usr add column location varchar(255)
INFO SchemaUpdate:217 - schema update complete

Таким образом, по сути, создание (которое сначала удаляет таблицу, а затем воссоздает) работает правильно, а обновление - нет, если в метаданных свойства есть изменение.

Мне кажется, что проблема поддержки драйверов для инкрементных обновлений находится здесь. Также интуитивно. Если я подумаю об этом, то не имеет смысла оказывать поддержку в обновлении типа данных столбцов. Что произойдет с существующими данными, если измененный тип данных столбца является уменьшенной версией более раннего типа данных.

У меня просто была эта проблема, после прочтения которой я нашел ответ, очень логичный, если подумать, связан с проверенными таблицами envers.

Как воспроизвести

  • Вы используете Hibernate Envers
  • Вы меняете тип столбца в коде, добавляя аннотацию @Lob.

причина

Hibernate обновляет только исходную таблицу, а не проверенную, вот что делает Hibernate:

ALTER TABLE piece_aud MODIFY notes LONGTEXT;

симптомы

Возникает исключение MysqlDataTruncation из-за печально известного "Данные слишком длинные для столбца" x "".

Решение

Обновите вручную тип проверяемой таблицы. Пример:

ALTER TABLE piece_aud MODIFY notes LONGTEXT;

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

У меня тоже был такой же сценарий, и ниже одного у меня работает плавно

@Column(name="your_column_name",columnDefinition="LONGTEXT")
private String notes;

Я знаю, что об этом давно спрашивали, но все же это может кому-то помочь.:)

Я думаю, что это решает проблему@Column(columnDefinition="LONGVARCHAR")

У меня была та же проблема, что оператор INSTER работал совершенно напрямую с базой данных, но выполнение этого через Hibernate не сработало и привело к усечению данных: данные слишком длинные для столбца. Все работало, когда hbm2ddl был изменен на create-drop.

Но моя настоящая проблема была из-за того, что я использовал таблицы аудита, используя встроенную функцию аудита Hibernate. Основная таблица была обновлена ​​правильно до увеличенного размера, но не для таблицы аудита, поэтому все изменения, которые были записаны в таблицу аудита, вызвали эту ошибку усечения данных. Просто вручную обновил столбец в таблице Audit до нужного размера и все работало нормально.

@Column( length = 100000 )
private String text;

Это работает, но вы должны УДАЛИТЬ в таблицу! Потому что в этом случае спящий режим не обновляет таблицу. Итак, вам нужно заставить спящий режим воссоздать таблицу, и она работает!

Что касается меня, я исключаю следующие свойства и проблема уходит

<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>

Впрочем, довольно неприятная проблема. Вместо резервного копирования всей базы данных и изменения hibernate.hbm2ddl.autoориентированный на диалект ALTER TABLE SQL могут быть использованы. Например; для MySQL просто обновите тип столбца с помощью

alter table your_table modify column your_column text

и вуаля!

PS: не забыть обновить таблицы аудита!

Весной /JPA/Hibernate/Postgres,

@Type(type="org.hibernate.type.StringClobType")
String message;

Работает как шарм для меня!

Важное примечание: для меня тип столбца в базе данных не обновляется автоматически, поэтому мне нужно либо разрешить Hibernate пересоздать таблицу, либо вручную изменить тип с varchar(255) в text иначе ничего не происходит.

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