数据库大字段(Clob, Blob)不适合存储超过1MB的数据

通常数据库都提供Clob,Blob,Text,Long等大字段类型来存放超过4K的数据,然而这绝不意味着应该使用大字段来保存超过1MB以上的数据文件。之所以有大字段,往往是因为varchar类型有一定的长度限制,例如4K。超过此长度的文本和二进制数据必须使用大字段保存。不过通常情况下,大字段不意味着保存很大的文件,通常只是几十到几百KB的数据,例如很长的文章,图标,小图片等等。超过1MB以上的数据保存在数据库有诸多的性能问题:

速度慢
Web Server可以直接读取硬盘文件,然后返回文件给客户端,或者应用服务器读硬盘文件返回客户端,其效率要远远超过应用服务器访问数据库读取数据返回客户端。

操作不方便
必须把数据库打开一个流,构造一个Buffer,然后再输出一个ServletOutputStream。占用数据库连接,加重数据库访问负载不说,如果用户突然中断下载,还需要处理数据库关闭动作,容易造成性能问题。如果把整个数据读入内存再输出,则内存占用非常客观。如果是硬盘文件,只要返回一个URL就可以了。即使你不希望用户直接访问到文件,你也可以构造一个IOStream来输出文件,既不会占用数据库资源,传输速度也快。

性能有问题
特别的情况是,如果并发很多用户来下载大文件的时候,应用服务器要占用非常多的内存来缓存文件内容,假设并发10个用户,下载10MB的文件,JVM的峰值就至少需要100MB内存来支撑,很容易造成JVM崩溃。

Oracle其实还有一种File的Blob类型,虽然也是Blob,但是实际上File是保存在硬盘上的,这种方式的你可以试试看,只不过我觉得这种方式还不如直接操作文件方便,既然原理是一样的。

另外补充一点,常规的数据库备份都是无法备份Blob数据的,所以如果你把文件都保存到Blob里面去的话,数据库的备份是一个很头疼的大问题,你必须单独写程序把blob数据读出来,再写到硬盘文件去,再备份文件。而你如何把文件放在硬盘某个目录下面,而不是做为blob放在数据库里面,那备份简直易如反掌。

当然保存文件的方式的缺点就是文件不能重名,否则会覆盖,这个问题也不难解决,一般的fileupload API碰到重名都会有很多改名保存的策略;另外一点就是操作系统一个目录下面可以放的文件数量有限制,这个限制通常和文件系统的inode数量有关系,例如一个目录下面只能放1024个文件之类,然而这个问题同样可以通过file upload的一些保存策略解决掉,例如再增加一个子目录存放什么的。Oracle其实还有一种File的Blob类型,虽然也是Blob,但是实际上File是保存在硬盘上的,这种方式的你可以试试看,只不过我觉得这种方式还不如直接操作文件方便,既然原理是一样的。