Project Trouble Shooting : File image Upload API - File Size Problems With MySQL + Tomcat
Table of contents
#Foreword
We've decided to develop File Image Upload APIs, we didn't have specific API design, I needed to develop this on my own. We didn't use Amazon S3, therefore we decided to use Spring Data Jpa for File Image upload API.
When trying to add Image File that is 675.66KB that is less than 1MB, MySQL returns error : MysqlDataTruncation : "Data too long for column"
+After adding @Column(columnDefinition = "MEDIUMBLOB"), It could resolve MySQL column size limitation, but Tomcat return another error : FileSizeLimitExceededException: The field image exceeds its maximum permitted size of 1048576 bytes.(1048576 bytes is equivalent to 1 megabytes)
Reference URL : File Image APIs and API Design
(Image File Upload Using JPA With MySQL _ Url)
: https://joo.hashnode.dev/project-file-image-apis-with-jpamysql-api-design
#Problem 1 : MySQL - MysqlDataTruncation
: MysqlDataTruncation: Data truncation: Data too long for column 'image_data' at row1
DB error : 675.66KB is too big.
36.3KB is relatively small, successfully uploaded.
#Bytes, KiloBytes, MegaBytes, GigaBytes
1 Gigabyte (GB) to Megabytes (MB) and Kilobytes (KB)
1 GB = 1024 MB
1 GB = 1024 MB x 1024 KB/MB = 1,048,576 KB
1 Megabyte (MB) to Kilobytes (KB)
- 1 MB = 1024 KB
1 Kilobyte (KB) to Bytes
- 1 KB = 1024 Bytes
Here's a summary in ascending order:
1 Kilobyte (KB) = 1024 Bytes
1 Megabyte (MB) = 1024 Kilobytes (KB)
1 Gigabyte (GB) = 1024 Megabytes (MB) = 1,048,576 Kilobytes (KB)
For example, 1 gigabyte is equal to 1,048,576 kilobytes.
So, if you want to upload an image of size 1 GB, you would need a byte array of approximately 1,048,576 kilobytes.
In fact, 1MB isn't small size for Image File.
#Solution1 : ColumnDefinition "MEDIUMBLOB"
It stands for Medium Binary Large Object
.
A. new byte[4*1024] - [1000*1024] ==> Fail
4 * 1024 -> 4096 bytes : It's equivalent to 4 kilobytes.
what If i set this 1000*1024 -> it's equivalent to 1000kb, but 688.66KB image can't be uploaded.
B. Set ColumnDefinition = MEDIUMBLOB (16MB)
ImageData Entity before modification
ImageData Entity after adding@Column(columnDefinition = "MEDIUMBLOB")
POSTMAN Test Result (For solution 1)
: Success..........................! This is supposed to acommodate 16MB file size.
Below Image Size is 872.77KB
Success !
#Problem 2 : Tomcat - FileSizeLimitExceededException
I tried to upload a 1.4MB file, MEDIUMBLOB
was supposed to accept this file size, but................Tomcat returns FileSizeLimitExceededException
, refer to image below.
Although MEDIUMBLOB resolved DB size limitation, which can increase the size up to 16MB, Tomcat is throwing another exception: FileSizeLimitExceededException.
Caused by: java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field image exceeds its maximum permitted size of 1048576 bytes.
-> 1048576 bytes
is equivalent to 1 megabyte
#Solution2 : application.yml + 2 config class
import jakarta.servlet.MultipartConfigElement;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;
@Configuration
public class FileUploadConfig {
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
factory.setMaxFileSize(DataSize.ofMegabytes(16));
factory.setMaxRequestSize(DataSize.ofMegabytes(16));
return factory.createMultipartConfig();
}
}
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
@Component
public class TomcatCustomizer implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(connector -> {
connector.setMaxPostSize(16 * 1024 * 1024); // 16MB
});
}
}
spring:
servlet:
multipart:
max-file-size: 16MB # Set desired maximum file size
max-request-size: 16MB # Set desired maximum request size
server:
tomcat:
max-swallow-size: 16MB # This sets the maximum size, Tomcat will swallow
POSTMAN Test Result (For solution 2)
7.87MB size file (It's for test, but I don't think we need such a big size image)
#conclusion
In conclusion, To resolve file size limitations of MySQL and Tomcat, 2 step solutions were needed.
Problem 1. Data too long for Column by DB MySQL
--> Solved by @Column(columnDefinition = "MEDIUMBLOB") : 16MB file size
Problem 2.FileSizeLimitExceededException by Tomcat(When file size is over 1MB)
--> Solved by application.yml file configuration + FileUploadConfig.class + TomcatCustomizer.class
Both solutions should be used for this. Like my trace, When using MEDIUMBLOB
can increase DB's column size up to 16MB, but we can't upload a file that is over 1MB if we don't use application.yml configuration + other 2 classes config file.
#+Filtering Specific File Size On Window (For Exact Test)
Hm,,, Suddenly, it just came to my mind, How to find out Image File between 15MB and 16MB.............................? (For exact Test)
(On Window)
We can filter images like below.