2010-07-02 2 views
14

У меня есть приложение Spring, которое использует Hibernate в базе данных PostgreSQL. Я пытаюсь хранить файлы в таблице базы данных. Кажется, он хранит строку с файлом (я просто использовать метод сохраняются на EntityManager), но когда объект загружается из базы данных, я получаю следующее исключение:Большие объекты не могут использоваться в режиме автоматической фиксации

org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode. 

Для загрузки данных я использую MultipartFile transient атрибут и его сеттер Я устанавливаю информацию, которую хочу сохранить (байт [], имя_файла, размер). Субъект я сохраняющийся выглядит как эта (я пропущен остальные добытчики/сеттера):

@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()); 
     } 
    } 
} 

я могу видеть, что, когда она сохраняется у меня есть данные в строке, но когда я звоню этот метод не выполняется:

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(); 
} 

Этот метод завершается с ошибкой, когда в результате есть объекты с файлами. Я попытался установить в моем persistence.xml

<property name="hibernate.connection.autocommit" value="false" /> 

но это не решит проблему.

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

Любая идея?

Спасибо.

UPDATE

Глядя на ссылку, заданной Шекхар предлагается включить вызов в транзакцию, поэтому я поставил вызов службы внутри транзакции об этом, это работает (я добавил @Transactional аннотация).

@Transactional 
public List<myClass> find(String text) { 
    return myClassDAO.findByDescription(text); 
} 

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

Спасибо.

+0

если вы не хотите сохранять данные, почему у вас есть «файлы»? Разве это не должно быть «@ Transient»? –

+0

@matt b Я хочу сохранить файлы, но только в операции сохранения, а не в прочитанной. Вот почему я не понял, что чтение должно быть в транзакции. – Javi

+0

Вы не просто используете @Transactional, когда хотите сохранить объекты. Обычно требуется транзакция для доступа к базе данных - чтению или письму. – Volksman

ответ

21

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

https://www.postgresql.org/docs/current/static/largeobjects.html

+4

Я не совсем уверен, как это ответ на исходный вопрос? Оригинальный плакат не хочет * писать * LOB без транзакции, он хочет их прочитать без него. –

2

Если вам нужно хранить файлы размером больше 1 ГБ, я предлагаю вам использовать BYTEA как тип данных вместо большого объекта.

bytea в основном, что BLOB находится в других базах данных (например, Oracle), и его обработка намного более совместима с JDBC.

4

Если вы можете создать промежуточное сущность между MyClass и файлом, например. Что-то вроде:

@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; 
} 

Вы не можете использовать @Lob и принесите тип лени. Это не работает. У вас должен быть промежуточный класс.

+0

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

Смежные вопросы