使用达梦数据库的大字段前不得不说一下数据库大字段的性能问题:在数据库中,经常需要用到大字段类型,如Oracle中long、blob、clob,SQLServer中的text、image,MySql中的text、longtext、clob、blob以及达梦数据库中的clob、blob类型。存储的信息大概主要是两类,一类是长文本,如大段的文字,普通的varchar最长只能存储4K的数据,已经不能满足要求;另一类是存储二进制信息,如上传的文件等。不过通常情况下,大字段不意味着保存很大的文件,例如很长的文章,图标,小图片等等。数据过大保存在数据库有诸多的问题:
1.速度慢:影响一张表的查询速度的,除了行数,还包括表所占的物理空间的大小。此表在数据量较小时,在查询方面感觉不到明显的差异。但是如果某个字段所存储的数据都是大段文本或较大的文件时,会导致表的物理空间迅速变大,该字段所占用的空间有可能达到整表所占空间的90%以上。在此基础上,如果行数再增加到数十万、上百万级时,整个表所占的空间将达到一个惊人的数字,查询的速度亦会受到非常大的影响。
2.操作不方便:必须把数据库打开一个流,构造一个Buffer,然后再输出一个ServletOutputStream。占用数据库连接,加重数据库访问负载不说,如果用户突然中断下载,还需要处理数据库关闭动作,容易造成性能问题。如果把整个数据读入内存再输出,则内存占用非常可观。如果是硬盘文件,只要返回一个URL 就可以了。即使你不希望用户直接访问到文件,你也可以构造一个IOStream来输出文件,既不会占用数据库资源,传输速度也快。
3.性能有问题:特别的情况是,如果并发很多用户来下载大文件的时候,应用服务器要占用非常多的内存来缓存文件内容,假设并发10个用户,下载10MB的文件,JVM的峰值就至少需要100MB内存来支撑,很容易造成JVM崩溃。
所以说数据库大字段并不适合存储过大的数据,数据过大可能会影响到数据库存储的性能。
下面言归正传,使用Hibernate操作达梦数据库中的大字段应该有如下几步:
1 首先需要一张表存储大字段数据:包括内容,类型;
2 必须得到一个代表上传文件的数据流;
3 进行保存操作
好了我们先建一张表,里面包括达梦数据库的2个大字段类型(CLOB、BLOB)字段:
–创建表
create table TESTLOB(
ID int primary key,
TITLE varchar(50),
CLOBNAME varchar(50),
CLOBCONTENT clob,
BLOBNAME varchar(50),
BLOBCONTENT blob
);
在建立一个序列用于处理表的流水ID:
–创建序列
create SEQUENCE “TESTLOB”.”SEQ_TESTLOB_ID”
INCREMENT BY 1 START WITH 1 MAXVALUE 100000 MINVALUE 1
NOCYCLE
然后编写关于这2个大字段的Java对象文件TestLob.java,分别定义类型为CLOB和BLOB属性字段为String和byte[]类型,其中由于CLOB是处理大文本类型所以它对应了Java中的String类型,BLOB是处理一些以二进制流形势存储的没有严格定义的大文件所以让它使用byte[]类型,然后分别定义这2个属性的Getter和Setter方法,相关代码如下:
package com.dm.lobtest.vo;
public class TestLob {
private int id;
private String title; //记录标题
private String clobName; //clob文件名称
private String clobContent; //clob文件
private byte[] blobContent; //blob文件
private String blobName; //blob文件名称
public byte[] getBlobContent() {
return blobContent;
}
public void setBlobContent(byte[] blobContent) {
this.blobContent = blobContent;
}
public String getClobContent() {
return clobContent;
}
public void setClobContent(String clobContent) {
this.clobContent = clobContent;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBlobName() {
return blobName;
}
public void setBlobName(String blobName) {
this.blobName = blobName;
}
public String getClobName() {
return clobName;
}
public void setClobName(String clobName) {
this.clobName = clobName;
}
}
将对象的映射文件中主健字段元素的内置生成器指定为sequence,并与达梦数据库重的内置序列(sequence)关联,最后指定CLOB类型的属性为”string”类型,BLOB类型的属性为”binary”类型:
<?xml version=”1.0″ encoding=”GB2312″?>
<!DOCTYPE hibernate-mapping PUBLIC
“-//Hibernate/Hibernate Mapping DTD 3.0//EN”
“http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd“>
<hibernate-mapping>
<class name=”com.dm.lobtest.vo.TestLob” table=”TESTLOB”>
<id name=”id” column=”ID” type=”int”>
<generator class=”sequence”>
<param name=”sequence”>SEQ_TESTLOB_ID</param>
</generator>
</id>
<property name=”title” column=”TITLE” type=”string” />
<property name=”clobName” column=”CLOBNAME” type=”string” />
<property name=”blobName” column=”BLOBNAME” type=”string” />
<property name=”clobContent” column=”CLOBCONTENT” type=”string” />
<property name=”blobContent” column=”BLOBCONTENT” type=”binary” />
</class>
</hibernate-mapping>
完成以上这些操作后我们可以开始编写上传文件页面和处理上传文件的业务逻辑了,
定义上传文件页面:
<form name=”myTestLobFrm” method=”post” enctype=”multipart/form-data” action=”/LobTest/testlob.do?method=save”>
<table align=”center”>
<tr>
<td colspan=”2″>
<b>达梦数据库CLOB和BLOB数据类型在Hibernate下使用的示例</b>
</td>
</tr>
<tr>
<td>标题:</td>
<td>
<input type=”text” name=”title” size=”81″>
</td>
</tr>
<tr>
<td>文件内容:</td>
<td>
<textarea rows=”20″ cols=”80″ name=”clobTest” ></textarea>
</td>
</tr>
<tr>
<td>附件:</td>
<td>
<input type=”file” name=”blobTest” size=”71″>
</td>
</tr>
<tr>
<td colspan=”2″ align=”center”>
<input type=”submit” value=” 确 认 “>
</td>
</tr>
<tr>
<td colspan=”2″ align=”center”> <font id=”info” color=”red”><%=message %></font></td>
</tr>
</table>
</form>
处理业务逻辑类:
public class TestLobAction extends DispatchAction{
public ActionForward save(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
try{
//设置文件标题
String title = request.getParameter(“title”);
TestLob testLob = new TestLob();
testLob.setTitle(title);
//处理blob字段
Hashtable files = form.getMultipartRequestHandler().getFileElements();
FormFile blobTestFile = (FormFile) files.get(“blobTest”);//得到文件
String blobName = blobTestFile.getFileName(); //得到文件名
testLob.setBlobName(blobName); //设置文件
byte[] blobContent=blobTestFile.getFileData(); //得到文件内容
testLob.setBlobContent(blobContent); //设置文件内容
//处理clob字段
String clobName = title; //文件名就是标题名
String clobContent = request.getParameter(“clobTest”); //得到文件
testLob.setClobName(clobName); //设置文件名
testLob.setClobContent(clobContent); //设置文件
TestLobService testLobService = TestLobService.getInstance();
if(testLobService.createTestLob(testLob)==0){
request.setAttribute(“message”, “上传失败”);
return list(mapping,form,request,response);
}
}catch(Exception e){
throw new BaseException();
}
request.setAttribute(“message”, “上传成功”);
return list(mapping,form,request,response);
}
}
因为clob字段对应的是String类型,所以可以直接将表单中得到的数据设置到对象的属性中去,而blob类型处理的是二进制类型的文件,我们需要将得到的文件以流的形式存入到对象的属性中,这里我使用了struts的FormFile组件来进行文件的上传,将得到的数据流设置到对象的属性中。
完成以上操作后我们就可以将设置好的对象用以下面的方法保存数据到数据库中:
首先定义一个Hibernate的Session管理类:HibernateUtil.java,它是使用ThreadLocal类建立的一个Session管理的辅助类。
package com.dm.lobtest.util;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
public class HibernateUtil {
private static SessionFactory sessionFactory = null;
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException {
if (sessionFactory == null) {
if (getSystemSessionFactory() == false) {
throw new HibernateException(
“Exception geting SessionFactory ! “);
}
}
Session s = (Session) session.get();
// 如果该线程还不存在,打开一个新的Session
if (s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
最后利用Hibernate的运作中心–Session接口的save()方法保存对象并提交相关的Session实例:
public int createTestLob(TestLob testLob){
Session session = null;
try{
session = HibernateUtil.currentSession();
Transaction tr = session.beginTransaction();
session.save(testLob);
tr.commit();
return 1;
}catch(Exception e){
e.printStackTrace();
return 0;
}finally {
try {
if (session != null) {
HibernateUtil.closeSession();
}
}catch (Exception ex) {}
}
}
现在我们已经利用Hibernate完成了多个不同的大数据类型存储到达梦数据库中的全过程。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
达梦数据库携手赛凡科技全面启动战略合作
2015年10月27日,知名国产数据库厂商北京达梦数据库技术有限公司和国内自主创新存储厂商北京赛凡智慧科技有限公司战略合作协议签约仪式在北京举行。
-
有效的MySQL备份与恢复
如果您接手了一个MySQL生产系统,但不确定它是否运行了MySQL备份策略,这时需要做哪些保障措施呢?
-
Oracle用户:Exadata很强大但并非完美
Oracle Exadata自从两年前V2推出以来,都沉浸在一片溢美之词之中。然而,在由Enkitec举行的两天Exadata大会中,第一天就有人挑起了它的毛病。
-
Navis部署Oracle Pillar Axiom存储系统
Navis利用Oracle Pillar Axiom 600存储系统取代了NetApp存储解决方案,以支持用于其SPARCS N4终端运营系统的集成和开发环境。