resolucion - swing java
Los objetos grandes no se pueden usar en el modo de confirmación automática (4)
Tengo una aplicación Spring que utiliza Hibernate en una base de datos PostgreSQL. Estoy tratando de almacenar archivos en una tabla de la base de datos. Parece que almacena la fila con el archivo (solo uso el método de persistencia en EntityManager), pero cuando el objeto se carga desde la base de datos obtengo la siguiente excepción:
org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode.
Para cargar los datos, estoy usando un atributo transitorio MultipartFile y en su configurador, estoy configurando la información que deseo conservar (byte [], fileName, tamaño). La entidad en la que estoy persistiendo se parece a esta (omití el resto de captadores / definidores):
@Entity
@Table(name="myobjects")
public class MyClass {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence")
@SequenceGenerator(name="sequence", sequenceName="myobjects_pk_seq", allocationSize=1)
@Column(name="id")
private Integer id;
@Lob
private String description;
@Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
@Transient
private MultipartFile multipartFile;
@Lob
@Basic(fetch=FetchType.LAZY, optional=true)
byte[] file;
String fileName;
String fileContentType;
Integer fileSize;
public void setMultipartFile(MultipartFile multipartFile) {
this.multipartFile = multipartFile;
try {
this.file = this.multipartFile.getBytes();
this.fileName = this.multipartFile.getOriginalFilename();
this.fileContentType = this.multipartFile.getContentType();
this.fileSize = ((Long) this.multipartFile.getSize()).intValue();
} catch (IOException e) {
logger.error(e.getStackTrace());
}
}
}
Puedo ver que cuando persiste tengo los datos en la fila pero cuando llamo a este método falla:
public List<MyClass> findByDescription(String text) {
Query query = getEntityManager().createQuery("from MyClass WHERE UPPER(description) like :query ORDER BY creationDate DESC");
query.setParameter("query", "%" + text.toUpperCase() + "%");
return query.getResultList();
}
Este método solo falla cuando el resultado tiene objetos con archivos. He intentado establecer en mi persistence.xml
<property name="hibernate.connection.autocommit" value="false" />
Pero no resuelve el problema.
En general, la aplicación funciona bien, solo confirma los datos cuando finaliza la transacción y realiza una reversión si algo falla, por lo que no entiendo por qué sucede esto.
¿Alguna idea?
Gracias.
ACTUALIZAR
Mirando el enlace dado por Shekhar, se sugiere incluir la llamada en una transacción, así que establezco la llamada de servicio dentro de una transacción y funciona (he agregado la anotación @Transactional).
@Transactional
public List<myClass> find(String text) {
return myClassDAO.findByDescription(text);
}
el problema es que no quiero conservar ningún dato, por lo que no entiendo por qué debería incluirse dentro de una transacción. ¿Tiene algún sentido hacer un compromiso cuando solo he cargado algunos datos de la base de datos?
Gracias.
A menos que necesite almacenar archivos de más de 1 GB, le sugiero que use bytea como tipo de datos en lugar de objetos grandes.
bytea es básicamente lo que BLOB es en otras bases de datos (por ejemplo, Oracle) y su manejo es mucho más compatible con JDBC.
En lugar de usar @Transactional
, todo lo que hice para este problema fue actualizar esta columna en PostgreSQL DB del tipo oid
tipo bytea
y agregar @Type
para el campo @Lob
.
es decir
ALTER TABLE person DROP COLUMN image;
ALTER TABLE person ADD COLUMN image bytea;
Y cambiado
@Lob
private byte[] image;
A
@Lob
@Type(type = "org.hibernate.type.ImageType")
private byte[] image;
Si puede, cree una Entidad intermedia entre MyClass y propiedad de archivo, por ejemplo. Algo como:
@Entity
@Table(name="myobjects")
public class MyClass {
@OneToOne(cascade = ALL, fetch = LAZY)
private File file;
}
@Entity
@Table(name="file")
public class File {
@Lob
byte[] file;
}
No puedes usar @Lob y buscar el tipo Lazy. No funciona. Debes tener una clase intermedia.
Un objeto grande se puede almacenar en varios registros, por eso debe usar una transacción. Todos los registros son correctos o nada en absoluto.
https://www.postgresql.org/docs/current/static/largeobjects.html