java - 一个存储用户上传图片的Hibernate+Spring+MySQL项目操作性能调优

标签 java mysql hibernate spring blob

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

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

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

这是我在提交时保存文件的 Controller :

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 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.

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

谢谢

最佳答案

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

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.

希望这对您有所帮助。

关于java - 一个存储用户上传图片的Hibernate+Spring+MySQL项目操作性能调优,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2753387/

相关文章:

php - 无法获取 DynamicSalt 值以正确输入到 mysql

java - 使用递归方法对数组进行排序

java - 为什么我的服务器响应状态代码是 200 而不是 200 ok?

java - 如何在 Spring boot FilterHandlerFunction 提交之前处理响应

php - 需要创建像 facebook 中的消息传递系统 - 数据库设计的任何想法

java - Hibernate递归获取连接不递归获取所有子项

java - 如何将泛型与spring data jpa的JpaRepository一起使用

mysql更新字段的字符

java - 如何指定由通配符包围的 JPA 命名参数?

hibernate 4 : One class mapping Two tables - How to persist one object on both tables?