代码之家  ›  专栏  ›  技术社区  ›  Javi

大对象不能在自动提交模式下使用

  •  21
  • Javi  · 技术社区  · 16 年前

    我有一个Spring应用程序,它在PostgreSQL数据库上使用Hibernate。我正试图将文件存储在数据库的一个表中。它似乎将行与文件一起存储(我只是在EntityManager上使用persist方法),但是当从数据库加载对象时,会出现以下异常:

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

    为了加载数据,我使用了一个MultipartFile transient atribute,并在它的setter中设置了我想要保存的信息(byte[],fileName,size)。

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

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

    但这并不能解决问题。

    一般来说,应用程序工作得很好,它只在事务完成时提交数据,如果出现故障,它会执行回滚,所以我不明白为什么会发生这种情况。

    谢谢。

    更新

    查看Shekhar给出的链接,建议将调用包含在事务中,因此我将服务调用设置在一个事务中,它可以工作(我添加了@Transactional注释)。

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

    问题是我不想保留任何数据,所以我不明白为什么应该将其包含在事务中。当我只从数据库中加载了一些数据时进行提交有意义吗?

    4 回复  |  直到 16 年前
        1
  •  37
  •   MichielB    9 年前

    一个大对象可以存储在多个记录中,这就是为什么必须使用事务。所有记录都是正确的,或者根本没有。

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

        2
  •  6
  •   bbviana    13 年前

    比如:

    @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和fetch类型Lazy。它不起作用。你必须有一个中级班。

        3
  •  6
  •   Philip John    7 年前

    @Transactional oid 键入到 bytea 键入并添加 @Type 对于 @Lob 现场。

    ALTER TABLE person DROP COLUMN image;
    ALTER TABLE person ADD COLUMN image bytea;
    

    改变了

    @Lob
    private byte[] image;
    

    @Lob
    @Type(type = "org.hibernate.type.ImageType")
    private byte[] image;
    
        4
  •  5
  •   a_horse_with_no_name    16 年前

    除非您需要存储大于1GB的文件,否则我建议您使用bytea作为数据类型,而不是使用大对象。

    bytea基本上就是BLOB在其他数据库(例如Oracle)中的作用,它的处理与JDBC兼容得多。

        5
  •  3
  •   Raj Shukla    5 年前

    @Transactional

        6
  •  0
  •   Stephan Berg    7 年前

    您应该用方法检查auto commit是否真的设置为false getAutoCommit() 在你的连接上。

    对我来说

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

    不起作用,因为我的数据库连接类型要求自动提交为true。

    this post 更多细节。