Tengo una aplicación Spring que usa Hibernate en una base de datos PostgreSQL. Intento almacenar archivos en una tabla de la base de datos. Parece que almacena la fila con el archivo (sólo tiene que utilizar el método persistir en EntityManager), pero cuando el objeto se carga desde la base de datos me sale el siguiente excepción:Los objetos grandes no se pueden utilizar en el modo de confirmación automática
org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode.
Para cargar los datos que estoy usando una MultipartFile atributo transitorio y en su setter estoy configurando la información que quiero persistir (byte [], fileName, tamaño). La entidad estoy persistiendo miradas como éste (he omitido el resto de getters/setters):
@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 se persistió tengo los datos en la fila, pero cuando llamo 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 compromete los datos cuando la transacción finaliza y realiza una reversión si algo falla, por lo que no entiendo por qué sucede esto.
¿Alguna idea?
Gracias.
ACTUALIZACIÓN
Mirando el enlace dado por Shekhar se sugiere incluir la llamada en un transation, por lo que ha fijado la llamada de servicio dentro de una transacción una que funciona (He añadido @Transactional anotación).
@Transactional
public List<myClass> find(String text) {
return myClassDAO.findByDescription(text);
}
el problema es que no quiero que persistan los datos, así que no entiendo por qué se debe incluir dentro de una transacción. ¿Tiene algún sentido hacer una confirmación cuando solo he cargado algunos datos de la base de datos?
Gracias.
si no desea conservar los datos ¿por qué tiene 'archivos' mapeados? ¿No debería ser '@ Transient'? –
@matt b Deseo conservar los archivos pero solo en la operación de guardar, no en la de lectura. Por eso no entendí que la lectura debería estar en una transacción. – Javi
No solo usa @Transactional cuando quiere guardar objetos. Por lo general, se requiere una transacción para acceder a la base de datos, ya sea leyendo o escribiendo. – Volksman