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
иначе ничего не происходит.