Hibernate 4.1 с HSQLDB дает "исключение данных: строковые данные, правильное усечение"
У меня очень странная проблема, я получил ее, когда я обновил som, чтобы перейти к проекту.
Теперь я использую следующие версии:
- Spring: 3.1.0.RELEASE
- Спящий режим: 4.1.7. Финал
- Hsqldb: 2.2.8 (org.hsqldb)
Я ДУМАЮ, что проблема должна что-то сделать с полем файла. (Dbfile.content)
StackTrace:
javax.persistence.PersistenceException: org.hibernate.exception.DataException: could not insert: [org.project.model.Cv]
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1387)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1315)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1321)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:843)
at sun.reflect.GeneratedMethodAccessor11.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy36.persist(Unknown Source)
at org.project.dao.jpa.GenericDaoJpa.save(GenericDaoJpa.java:49)
at sun.reflect.GeneratedMethodAccessor10.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy40.save(Unknown Source)
at org.project.dao.CvDaoTest.updateTest(CvDaoTest.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.exception.DataException: could not insert: [org.project.model.Cv]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:102)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:64)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2345)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2852)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:71)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:320)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:837)
... 45 more
Caused by: java.sql.SQLDataException: data exception: string data, right truncation
at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
at org.hsqldb.jdbc.JDBCPreparedStatement.fetchResult(Unknown Source)
at org.hsqldb.jdbc.JDBCPreparedStatement.executeUpdate(Unknown Source)
at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeUpdate(NewProxyPreparedStatement.java:105)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:94)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:57)
... 60 more
Caused by: org.hsqldb.HsqlException: data exception: string data, right truncation
at org.hsqldb.error.Error.error(Unknown Source)
at org.hsqldb.error.Error.error(Unknown Source)
at org.hsqldb.types.BinaryType.castOrConvertToType(Unknown Source)
at org.hsqldb.types.BinaryType.convertToType(Unknown Source)
at org.hsqldb.StatementDML.getInsertData(Unknown Source)
at org.hsqldb.StatementInsert.getInsertValuesNavigator(Unknown Source)
at org.hsqldb.StatementInsert.getResult(Unknown Source)
at org.hsqldb.StatementDMQL.execute(Unknown Source)
at org.hsqldb.Session.executeCompiledStatement(Unknown Source)
at org.hsqldb.Session.execute(Unknown Source)
... 65 more
Консоль:
INFO : org.hibernate.engine.jdbc.JdbcSupportLoader - Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
Hibernate: insert into Nationality (id, countryCode) values (default, ?)
Hibernate: insert into Language (id, countryCode, languageCode) values (default, ?, ?)
Hibernate: insert into Person (id, birthdate, created, email, enabled, firstName, image, lastName, lastUpdate, nationality_id, password, role, salt) values (default, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Nationality (id, countryCode) values (default, ?)
Hibernate: insert into Person (id, birthdate, created, email, enabled, firstName, image, lastName, lastUpdate, nationality_id, password, role, salt) values (default, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Company (id, name) values (default, ?)
Hibernate: insert into Language (id, countryCode, languageCode) values (default, ?, ?)
Hibernate: insert into Company (id, name) values (default, ?)
Hibernate: insert into Skill (id, company_id, created, isCategory, lastUpdate, skill_fk) values (default, ?, ?, ?, ?, ?)
Hibernate: insert into Company (id, name) values (default, ?)
Hibernate: insert into Skill (id, company_id, created, isCategory, lastUpdate, skill_fk) values (default, ?, ?, ?, ?, ?)
Hibernate: insert into Nationality (id, countryCode) values (default, ?)
Hibernate: insert into Person (id, birthdate, created, email, enabled, firstName, image, lastName, lastUpdate, nationality_id, password, role, salt) values (default, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into CourseExperience (created, lastUpdate, lastUpdatePerson_id, person_fk, endDate, startDate, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Nationality (id, countryCode) values (default, ?)
Hibernate: insert into Person (id, birthdate, created, email, enabled, firstName, image, lastName, lastUpdate, nationality_id, password, role, salt) values (default, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into CourseExperience (created, lastUpdate, lastUpdatePerson_id, person_fk, endDate, startDate, id) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into Cv (id, company, created, language, lastUpdate, lastUpdatePerson_id, name, person_fk, summary_id) values (default, ?, ?, ?, ?, ?, ?, ?, ?)
WARN : org.hibernate.util.JDBCExceptionReporter - SQL Error: -3401, SQLState: 22001
ERROR: org.hibernate.util.JDBCExceptionReporter - data exception: string data, right truncation
Cv.java:
package org.project.model;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.OrderColumn;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.project.model.interfaces.DomainObject;
@Entity
public class Cv implements DomainObject {
private static final long serialVersionUID = -9111485038728016755L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@ManyToOne
@JoinColumn(name = "person_fk")
private Person person;
@ManyToMany
private List<Skill> skills = new ArrayList<Skill>();
@ManyToOne
private Summary summary;
@ManyToMany(targetEntity = Experience.class)
@OrderColumn(name = "index")
private List<Experience> experiences = new ArrayList<Experience>();
@Temporal(TemporalType.TIMESTAMP)
@Column(updatable = false, insertable = true)
private Date created;
@Temporal(TemporalType.TIMESTAMP)
private Date lastUpdate;
@ManyToOne(optional = false)
private Person lastUpdatePerson;
@Column(nullable = false)
private Language language;
@Column(nullable = false)
private Company company;
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL, targetEntity = DbFile.class)
@OrderBy("created DESC")
private List<DbFile> files = new ArrayList<DbFile>();
@PrePersist
@PreUpdate
protected void updateDates() {
Date now = new Date();
if (this.created == null) {
this.created = new Date(now.getTime());
}
this.lastUpdate = now;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public List<Skill> getSkills() {
return skills;
}
public void setSkills(List<Skill> skills) {
this.skills = skills;
}
public List<Experience> getExperiences() {
return experiences;
}
public void setExperiences(List<Experience> experiences) {
this.experiences = experiences;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(Date lastUpdate) {
this.lastUpdate = lastUpdate;
}
public Person getLastUpdatePerson() {
return lastUpdatePerson;
}
public void setLastUpdatePerson(Person lastUpdatePerson) {
this.lastUpdatePerson = lastUpdatePerson;
}
public void addSkill(Skill skill) {
this.skills.add(skill);
}
public void addExperience(Experience experience) {
this.experiences.add(experience);
}
public Summary getSummary() {
return summary;
}
public void setSummary(Summary summary) {
this.summary = summary;
}
public List<DbFile> getFiles() {
return files;
}
public void setFiles(List<DbFile> files) {
this.files = files;
}
public void addFile(DbFile file) {
this.files.add(file);
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public Language getLanguage() {
return language;
}
public void setLanguage(Language language) {
this.language = language;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Cv other = (Cv) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
DbFile.java:
package org.project.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.PrePersist;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.Type;
import org.project.model.interfaces.DomainObject;
@Entity
public class DbFile implements DomainObject {
private static final long serialVersionUID = 1974800702358176016L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String filename;
@Column(nullable = false)
@Lob
@Type(type = "org.hibernate.type.MaterializedClobType")
private byte[] content;
private String contentType;
@Temporal(TemporalType.TIMESTAMP)
@Column(updatable = false)
private Date created;
@PrePersist
protected void updateDates() {
if (this.created == null) {
this.created = new Date();
}
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public byte[] getContent() {
return content;
}
public void setContent(byte[] content) {
this.content = content;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public Date getCreated() {
return created;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DbFile other = (DbFile) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
Тест:
@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
...
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class CvDaoTest extends AbstractTest {
@Autowired
private CvDao cvDao;
@Test
public void updateTest() {
Cv cv = new Cv();
cv.setName("test");
...
cv.setLastUpdatePerson(lastUpdatePerson);
...
cv.setPerson(person);
cv.setCreated(new Date());
cv.setLastUpdate(new Date());
cv.setCompany(getCompany());
cv.setLanguage(getLanguage());
...
cv.addSkill(skill1);
cv.addSkill(skill2);
...
cv.addExperience(experience1);
cv.addExperience(experience2);
cvDao.save(cv).getId();
}
}
GenericDaoJpa.java
public class GenericDaoJpa<T extends DomainObject> implements GenericDao<T> {
private Class<T> type;
// @PersistenceContext
protected EntityManager entityManager;
@PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public GenericDaoJpa(Class<T> type) {
super();
this.type = type;
}
@Transactional(readOnly = true)
public T get(Long id) {
if (id == null) {
return null;
} else {
return entityManager.find(type, id);
}
}
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
public List<T> getAll() {
return entityManager.createQuery("select o from " + type.getName() + " o").getResultList();
}
@Transactional(readOnly = false)
public T save(T object) {
if (object.getId() != null) {
return entityManager.merge(object);
} else {
entityManager.persist(object);
}
entityManager.flush();
return object;
}
public T delete(T object) {
entityManager.remove(object);
return object;
}
}
Он не работает: 'cvDao.save(cv).getId();'
Источник данных с использованием класса 'com.mchange.v2.c3p0.ComboPooledDataSource' с драйвером 'org.hsqldb.jdbcDriver' в url 'jdbc: hsqldb: mem: data'
Что я сделал неправильно?
Ответы
Ответ 1
Попробуйте HSQLDB 2.2.9 или последний санфот, поскольку трассировка стека выглядит как проблема, которая была исправлена после 2.2.8.
Репозиторий Maven для моментальных снимков и выпусков находится здесь:
http://www.hsqldb.org/repos/org/hsqldb/hsqldb/
Также см. ответ ниже. Кажется, использование "org.hibernate.type.MaterializedClobType" является общим для PostgreSQL. Но ваше поле является байтом [] и может быть лучше показано как BLOB с HSQLDB.
Получить изображение из blob через Hibernate (не JDBC)
Ответ 2
Проблема заключается в реализации HSQLDialect, которая регистрирует sql-типы в своем конструкторе:
public HSQLDialect() {
super();
...
registerColumnType( Types.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "clob($l)" );
...
}
Где $l берется из атрибута длины столбца. Но если атрибут длины столбца не задан явно, он имеет значение по умолчанию 255
.
В этом случае HSQLDialect
создает столбец как CLOB (255), который смешно для клобов...
1)
Одним из решений является установка длины столбца явно с достаточным значением.
Например:
@Lob
@Column(length = 10000)
private String text;
Но если вы хотите избежать таких искусственных конструкций, вы можете изменить диалект.
2)
Второе решение - изменить HSQLDialect:
package com.extensions.dialect;
import java.sql.Types;
import org.hibernate.dialect.HSQLDialect;
public class MyHsqlDialect extends HSQLDialect {
public MppHsqlDialect() {
super();
registerColumnType(Types.CLOB, "clob");
}
}
и в диалоговом режиме настройки спящего режима новый диалект:
hibernate.dialect=com.extensions.dialect.MyHsqlDialect
Я использую это решение в своих тестах интеграции.
Дополнительную информацию можно найти здесь:
https://hibernate.atlassian.net/browse/HHH-7541
Ответ 3
Правильный ответ: добавить длину к аннотации @Column, например:
@Lob
@Column(length = 10000, name = "style")
private String style;
Ответ 4
У меня была схожая проблема. Было много ошибок: "исключение данных: строковые данные, правильное усечение". Решением было указать размер больших полей. Без этого поля будут ограничены размером по умолчанию. Но это еще не все. HSQL автоматически не обновляет схему базы данных. Таким образом, изменения не будут применяться, если вы воссоздаете базу данных.
@Column(length = 5 * 1024 * 1024) // five megabytes
private byte[] bytesPreview;
Ответ 5
Я получил то же сообщение об ошибке, когда в одном из моих свойств отношения отсутствовала аннотация @ManyToOne. Обновление HSQLDB до 2.2.9 не решило проблему.
JPA 2 имеет это требование:
"Отношение минимально требует аннотации отношения, либо @OneToMany или @ManyToMany"
Вы добавили новое свойство без добавления такой аннотации?