Java 大对象不能在自动提交模式下使用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3164072/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Large Objects may not be used in auto-commit mode
提问by Javi
I have a Spring application which uses Hibernate on a PostgreSQL database. I'm trying to store files in a table of the database. It seems it stores the row with the file (I just use persist method on EntityManager), but when the object is loaded from the database I get the following exception:
我有一个 Spring 应用程序,它在 PostgreSQL 数据库上使用 Hibernate。我正在尝试将文件存储在数据库表中。它似乎将行与文件一起存储(我只是在 EntityManager 上使用持久方法),但是当从数据库加载对象时,我得到以下异常:
org.postgresql.util.PSQLException: Large Objects may not be used in auto-commit mode.
To load the data I'm using a MultipartFile transient atribute and in its setter I'm setting the information I want to persist (byte[], fileName, size). The entity I'm persisting looks like this one (I've ommitted the rest of getters/setters):
为了加载数据,我使用了 MultipartFile 瞬态属性,并在其设置器中设置了我想要保留的信息(字节 []、文件名、大小)。我坚持的实体看起来像这样(我省略了其余的 getter/setter):
@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());
}
}
}
I can see that when it is persisted I have the data in the row but when I call this method it fails:
我可以看到,当它被持久化时,我在行中有数据,但是当我调用这个方法时它失败了:
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();
}
This method only fails when the result has objects with files. I've tried to set in my persistence.xml
此方法仅在结果包含带有文件的对象时失败。我试图在我的persistence.xml中设置
<property name="hibernate.connection.autocommit" value="false" />
but it doesn't solve the problem.
但它并没有解决问题。
In general the application works well it only commit the data when the transaction is finished and it performs a rollback if something fails, so I don't understand why is this happening.
一般来说,应用程序运行良好,它只在事务完成时提交数据,如果出现故障,它会执行回滚,所以我不明白为什么会发生这种情况。
Any idea?
任何的想法?
Thanks.
谢谢。
UPDATE
更新
Looking at the link given by Shekhar it is suggested to include the call in a transation, so I've set the service call inside a transaction an it works (I've added @Transactional annotation).
查看 Shekhar 给出的链接,建议将调用包含在事务中,因此我在事务中设置了服务调用并使其正常工作(我添加了 @Transactional 注释)。
@Transactional
public List<myClass> find(String text) {
return myClassDAO.findByDescription(text);
}
the problem is that I don't want to persist any data so I don't understand why it should be include inside a transaction. Does it make any sense to make a commit when I've only loaded some data form the database?
问题是我不想保留任何数据,所以我不明白为什么它应该包含在事务中。当我只从数据库加载了一些数据时,进行提交是否有意义?
Thanks.
谢谢。
采纳答案by Frank Heikens
A large object can be stored in several records, that's why you have to use a transaction. All records are correct or nothing at all.
一个大对象可以存储在多个记录中,这就是您必须使用事务的原因。所有记录都是正确的,或者根本没有。
https://www.postgresql.org/docs/current/static/largeobjects.html
https://www.postgresql.org/docs/current/static/largeobjects.html
回答by a_horse_with_no_name
Unless you need to store files large than 1GB I suggest you use bytea as the datatype instead of large object.
除非您需要存储大于 1GB 的文件,否则我建议您使用 bytea 作为数据类型而不是大对象。
bytea is basically what BLOB is in other databases (e.g. Oracle) and it's handling is a lot more compatible with JDBC.
bytea 基本上是 BLOB 在其他数据库(例如 Oracle)中的内容,并且它的处理与 JDBC 更加兼容。
回答by bbviana
If you can, create a intermediate Entity between MyClass and file property for instance. Something like:
如果可以,例如在 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;
}
You can't use @Lob and fetch type Lazy. It doesnt work. You must have a a intermediate class.
您不能使用 @Lob 并获取类型 Lazy。它不起作用。你必须有一个中级班。
回答by Philip John
Instead of using @Transactional
, all I did for this issue was to update this column in PostgreSQL DB from oid
type to bytea
type and added @Type
for the @Lob
field.
@Transactional
我没有使用,我为这个问题所做的只是将 PostgreSQL 数据库中的这一列从oid
类型更新到bytea
类型并@Type
为该@Lob
字段添加。
i.e.
IE
ALTER TABLE person DROP COLUMN image;
ALTER TABLE person ADD COLUMN image bytea;
And changed
并且改变了
@Lob
private byte[] image;
To
到
@Lob
@Type(type = "org.hibernate.type.ImageType")
private byte[] image;
回答by Stephan Berg
You should check if auto-commit is really set false with method getAutoCommit()on your Connection.
您应该使用连接上的getAutoCommit()方法检查自动提交是否真的设置为 false 。
In my case
就我而言
<property name="hibernate.connection.autocommit" value="false" />
did not work, because the type of my db connection required auto-commit to be true.
没有用,因为我的数据库连接类型要求自动提交为真。
In my case the problem was in the JBoss Configuration. I was using an JTA-datasource and that caused the problem. With an XA-datasource it worked fine. See this postfor more details.
就我而言,问题出在 JBoss 配置中。我正在使用 JTA 数据源,这导致了问题。使用 XA 数据源,它运行良好。有关更多详细信息,请参阅此帖子。