存储用户上传图像的 Hibernate+Spring+MySQL 项目操作的性能调优

发布于 2024-08-31 04:56:08 字数 1838 浏览 4 评论 0原文

我正在开发一个基于Spring+Hibernate+MySQL的Web项目。我陷入了必须将用户上传的图像存储到数据库的困境。虽然我已经编写了一些目前运行良好的代码,但我相信当项目上线时事情会变得一团糟。

这是我的域类,它携带图像字节:

@Entity
public class Picture implements java.io.Serializable{
    long id;
    byte[] data;
    ... // getters and setters
}

这是我的控制器,用于在提交时保存文件:

public class PictureUploadFormController extends AbstractBaseFormController{
    ...
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception{
         MutlipartFile file; 
         // getting MultipartFile from the command object
         ...
         // beginning hibernate transaction
         ...
         Picture p=new Picture();
         p.setData(file.getBytes());
         pictureDAO.makePersistent(p); // this method simply calls getSession().saveOrUpdate(p)

         // committing hiernate transaction
         ...
    }
    ...
}

显然是一段糟糕的代码。无论如何,我可以使用 InputStreamBlob 来保存数据,而不是首先将用户的所有字节加载到内存中,然后将它们推入数据库中?

我对 Hibernate 对 Blob 的支持做了一些研究,并在《Hibernate In Action》一书中找到了这一点:

java.sql.Blob 和 java.sql.Clob 是 处理大件最有效的方法 Java 中的对象。不幸的是,一个 Blob 或 Clob 的实例只是 直到 JDBC 事务为止都可用 完成。 所以如果你的持久类 定义 java.sql.Clob 的属性或 java.sql.Blob(不是一个好主意 无论如何),你将受到限制 可以使用该类的实例。 特别是,你将无法使用 该类的实例是分离的 对象。此外,许多 JDBC 驱动程序不提供工作支持 对于 java.sql.Blob 和 java.sql.Clob。 因此,绘制地图更有意义 使用二进制或文本的大对象 映射类型,假设检索 将整个大对象放入内存 不是性能杀手。

注意你 可以找到最新的设计模式 以及关于大对象使用的提示 Hibernate 网站,有技巧 特定平台。

现在显然不能使用Blob,因为无论如何都不是一个好主意,还有什么可以用来提高性能呢?我在 Hibernate 网站上找不到任何最新的设计模式或任何有用的信息。因此,来自 stackoverflowers 的任何帮助/建议将不胜感激。

谢谢

I am working on a web project that is Spring+Hibernate+MySQL based. I am stuck at a point where I have to store images uploaded by a user into the database. Although I have written some code that works well for now, but I believe that things will mess up when the project would go live.

Here's my domain class that carries the image bytes:

@Entity
public class Picture implements java.io.Serializable{
    long id;
    byte[] data;
    ... // getters and setters
}

And here's my controller that saves the file on submit:

public class PictureUploadFormController extends AbstractBaseFormController{
    ...
    protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception{
         MutlipartFile file; 
         // getting MultipartFile from the command object
         ...
         // beginning hibernate transaction
         ...
         Picture p=new Picture();
         p.setData(file.getBytes());
         pictureDAO.makePersistent(p); // this method simply calls getSession().saveOrUpdate(p)

         // committing hiernate transaction
         ...
    }
    ...
}

Obviously a bad piece of code. Is there anyway I could use InputStream or Blob to save the data, instead of first loading all the bytes from the user into the memory and then pushing them into the database?

I did some research on hibernate's support for Blob, and found this in Hibernate In Action book:

java.sql.Blob and java.sql.Clob are
the most efficient way to handle large
objects in Java. Unfortunately, an
instance of Blob or Clob is only
useable until the JDBC transaction
completes. So if your persistent class
defines a property of java.sql.Clob or
java.sql.Blob (not a good idea
anyway), you’ll be restricted in how
instances of the class may be used.
In
particular, you won’t be able to use
instances of that class as detached
objects. Furthermore, many JDBC
drivers don’t feature working support
for java.sql.Blob and java.sql.Clob.
Therefore, it makes more sense to map
large objects using the binary or text
mapping type, assuming retrieval of
the entire large object into memory
isn’t a performance killer.

Note you
can find up-to-date design patterns
and tips for large object usage on the
Hibernate website, with tricks for
particular platforms.

Now apparently the Blob cannot be used, as it is not a good idea anyway, what else could be used to improve the performance? I couldn't find any up-to-date design pattern or any useful information on Hibernate website. So any help/recommendations from stackoverflowers will be much appreciated.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

黄昏下泛黄的笔记 2024-09-07 04:56:08

该书的修订版(Java Persistence with Hibernate)说:

表 5.3 列出了用于处理二进制数据和大值的 Hibernate 类型。注意
仅支持 binary 作为标识符属性的类型。

Mapping type   Java type   Standard SQL built-in type
binary         byte[]               VARBINARY
text           java.lang.String     CLOB
clob           java.sql.Clob        CLOB
blob           java.sql.Blob        BLOB
serializable   Any Java class that  VARBINARY
               implements
               java.io.Serializable

如果持久化 Java 类中的属性是 byte[] 类型,Hibernate 可以映射
它到具有二进制映射类型的 VARBINARY 列。 (请注意,真正的 SQL 类型取决于方言;例如,在 PostgreSQL 中,SQL 类型是 BYTEA,
在 Oracle 中它是 RAW。)如果持久 Java 类中的属性是类型
java.lang.String,Hibernate可以将其映射到SQL CLOB列,其中包含文本
映射类型。

请注意,在这两种情况下,Hibernate 都会立即初始化属性值,
当保存属性变量的实体实例被加载时。这很不方便
当您必须处理潜在的大值时。

一种解决方案是通过按需拦截字段访问来延迟加载。
然而,这种方法需要持久化的字节码检测
用于注入额外代码的类。我们将讨论通过字节码进行延迟加载
第 13 章第 13.1.6 节“延迟加载”中的检测和拦截
拦截。”

第二个解决方案是在 Java 类中使用不同类型的属性。 JDBC支持
直接定位器对象 (LOB)。1 如果您的 Java 属性属于类型
java.sql.Clob 或 java.sql.Blob,可以使用 clob 或 blob 映射来映射它
type 来延迟加载大值而无需字节码检测。什么时候
属性的所有者已加载,属性值是一个定位器对象 - 实际上,
指向尚未实现的实际值的指针。一旦您访问
财产,价值得以实现。这种按需加载仅在以下情况下有效
数据库事务是开放的,因此您需要访问此类类型的任何属性
当拥有实体实例处于持久性和事务性状态时,而不是处于
分离状态。您的域模型现在也绑定到 JDBC,因为
需要导入java.sql包。尽管领域模型类是
在隔离的单元测试中可执行,没有数据库就无法访问 LOB 属性
连接。

希望这有帮助。

The revised edition of the book (Java Persistence with Hibernate) says:

Table 5.3 lists Hibernate types for handling binary data and large values. Note that
only binary is supported as the type of an identifier property.

Mapping type   Java type   Standard SQL built-in type
binary         byte[]               VARBINARY
text           java.lang.String     CLOB
clob           java.sql.Clob        CLOB
blob           java.sql.Blob        BLOB
serializable   Any Java class that  VARBINARY
               implements
               java.io.Serializable

If a property in your persistent Java class is of type byte[], Hibernate can map
it to a VARBINARY column with the binary mapping type. (Note that the real SQL type depends on the dialect; for example, in PostgreSQL, the SQL type is BYTEA,
and in Oracle it’s RAW.) If a property in your persistent Java class is of type
java.lang.String, Hibernate can map it to an SQL CLOB column, with the text
mapping type.

Note that in both cases, Hibernate initializes the property value right away,
when the entity instance that holds the property variable is loaded. This is inconvenient
when you have to deal with potentially large values.

One solution is lazy loading through interception of field access, on demand.
However, this approach requires bytecode instrumentation of your persistent
classes for the injection of extra code. We’ll discuss lazy loading through bytecode
instrumentation and interception in chapter 13, section 13.1.6, “Lazy loading
with interception.”

A second solution is a different kind of property in your Java class. JDBC supports
locator objects (LOBs) directly.1 If your Java property is of type
java.sql.Clob or java.sql.Blob, you can map it with the clob or blob mapping
type to get lazy loading of large values without bytecode instrumentation. When
the owner of the property is loaded, the property value is a locator object—effectively,
a pointer to the real value that isn’t yet materialized. Once you access the
property, the value is materialized. This on-demand loading works only as long as
the database transaction is open, so you need to access any property of such a type
when the owning entity instance is in a persistent and transactional state, not in
detached state. Your domain model is now also bound to JDBC, because the
import of the java.sql package is required. Although domain model classes are
executable in isolated unit tests, you can’t access LOB properties without a database
connection.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文