导航:首页 > 编程大全 > hibernate存储图片到数据库

hibernate存储图片到数据库

发布时间:2023-11-05 10:55:42

❶ 求struts和hibernate实现图片上传保存到数据库中,并可以在页面显示出来,并显示上传人的名字的代码

struts.xml中
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<constant name="sruts.il8n.encoding" value="UTF-8" />
<!--<constant name="struts.multipart.maxSize" value="102400" />
<constant name="struts.multipart.saveDir" value="d:/upload" /> -->
<constant name="struts.ui.theme" value="simple"></constant>
<package name="struts" extends="struts-default" namespace="/">
<action name="add2" class="DomeWeb2">
<!-- 限制图片的格式和图片的大小 -->
<interceptor-ref name="fileUpload">
<param name="allowedTypes">
image/bmp,image/png,image/gif,image/jpeg,image/pjpeg
</param>
</interceptor-ref>
<!-- 默认的拦截器,必须要写 -->
<interceptor-ref name="defaultStack" />
<result name="input">add2.jsp</result>
<result name="success">showUpload1.jsp</result>
</action> </package>
</struts>
applicationContext.xml中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName"
value="com.microsoft.sqlserver.jdbc.SQLServerDriver">
</property>
<property name="url" value="jdbc:sqlserver://localhost:1433;databaseName=bookshop">
</property>
<property name="username" value="sa"></property>
<property name="password" value="chen"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.SQLServerDialect
</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>entity/Dome.hbm.xml</value></list>
</property></bean>
<bean id="DomeDAO" class=".impl.DomeDaoImpl">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
<bean id="DomeWeb2" class="web.UploadOneAction">
<property name="domeBiz" ref="DomeBiz"></property>
</bean>
<!-- 配置事务 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" propagation="REQUIRED"
read-only="true" />
<tx:method name="find*" propagation="REQUIRED"
read-only="true" />
<tx:method name="search*" propagation="REQUIRED"
read-only="true" />
<tx:method name="query*" propagation="REQUIRED"
read-only="true" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="submit*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="check*" propagation="REQUIRED" />
<tx:method name="do*" propagation="REQUIRED" />
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethod"
expression="execution(* biz.impl.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />
</aop:config>
</beans>
UploadOneAction.java类中
package web;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;

import org.apache.struts2.ServletActionContext;

import biz.DomeBiz;

import com.opensymphony.xwork2.ActionSupport;

import entity.Dome;

public class UploadOneAction extends ActionSupport {
private static final long serialVersionUID = 572146812454l;
private static final int BUFFER_SIZE = 16 * 1024;
private File myFile; //文件
private String contentType; //内容类型
private String fileName; //文件名
private String imageFileName; //新文件名
private String caption; //标题

DomeBiz domeBiz ;
public void setDomeBiz(DomeBiz domeBiz) {
this.domeBiz = domeBiz;
}
private static void (File src, File dst) {
try {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(new FileInputStream(src),
BUFFER_SIZE);
out = new BufferedOutputStream(new FileOutputStream(dst),
BUFFER_SIZE);
byte[] buffer = new byte[BUFFER_SIZE];
while (in.read(buffer) > 0) {
out.write(buffer);
}
} finally {
if (null != in) {
in.close();
}
if (null != out) {
out.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

private static String getExtention(String fileName) {
int pos = fileName.lastIndexOf(".");
return fileName.substring(pos);
}

public String execute() {
if (myFile == null)
return INPUT;
System.out.println(this.getMyFileFileName()+"123");
imageFileName=new Date().getTime()+ getExtention(this.getMyFileFileName());
//得到图片保存的位置(根据root来得到图片保存的路径在tomcat下的该工程里)
File imageFile = new File(ServletActionContext.getServletContext().getRealPath("images")+ "/" + imageFileName);
(myFile, imageFile); //把图片写入到上面设置的路径里
Dome dome = new Dome();
dome.setPicture(this.getImageFileName());
domeBiz.save(dome);
return SUCCESS;
}
//得到原文件名称
public String getMyFileFileName() {
return fileName;
}

public void setMyFileFileName(String fileName) {
this.fileName = fileName;
}

public File getMyFile() {
return myFile;
}
public void setMyFile(File myFile) {
this.myFile = myFile;
}
public String getContentType() {
return contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getImageFileName() {
return imageFileName;
}
public void setImageFileName(String imageFileName) {
this.imageFileName = imageFileName;
}
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this.caption = caption;
}
}
add2.jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib prefix="s" uri="/struts-tags"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>上传</title>
</head>
<body>
<s:form action="add2.action" method="POST"
enctype="multipart/form-data">
<s:fielderror />
<s:file name="myFile" label="Image File1" />
<s:textfield name="caption" label="Caption" />
<s:submit />
</s:form>
</body>
</html>
showUpload1.jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">

<title>显示图片</title>
</head>

<body>
<div
style="padding: 3px; border: solid 1px #cccccc; text-align: center">
<img src='images/<s:property value ="imageFileName" /> ' />
<br />
<s:property value="caption" />
</div>
<s:property value="caption" />
</body>
</html>

❷ hibernate如何保存blob数据

首先你得搞清楚一点BLOB是二进制大对象,是ORACLE的数据类型,它对应到java中有两种方式:

byte[] 和java.sql.Blob(先搞清楚这重点哦)

我给你直接复制重点代码,希望可以帮到你

1 数据库中定义成BLOB类型,这个你自己定义吧(表名叫bigobject),~~~~~不过给你截个图吧


2 综上,把oracle数据库中的BLOB映射到java中有两种情况的,即java.sql.Blob和byte[],下面先说byte[]的映射

++++++++++++++++++++++++Bigobject.hbm.xml映射文件+++++++++++++++++++++++

<hibernate-mapping>

<class name="entity.Bigobject" table="BIGOBJECT" >

<id name="id" type="java.lang.Integer">

<column name="ID" precision="6" scale="0" />

<generator class="native" />

</id>

<property name="tclob" type="java.lang.String">

<column name="TCLOB" />

</property>

<property name="tblob" type="byte[]"> //!!!!!注意,这里是byte[]

<column name="TBLOB" />

</property>

</class>

</hibernate-mapping>

++++++++++++++++++++以下是bigobject实体类(用hibernate映射的)+++++++++++


public class Bigobject implements java.io.Serializable {

// Fields


private Integer id;

private String tclob;

private byte[] tblob; //!!!!!注意,这里是byte[]



// Constructors


/** default constructor */

public Bigobject() {

}


/** full constructor */

public Bigobject(String tclob, byte[] tblob) {

this.tclob = tclob;

this.tblob = tblob;

}


// Property accessors


public Integer getId() {

return this.id;

}

public void setId(Integer id) {

this.id = id;

}


public String getTclob() {

return this.tclob;

}

public void setTclob(String tclob) {

this.tclob = tclob;

}


public byte[] getTblob() {

return this.tblob;

}

public void setTblob(byte[] tblob) {

this.tblob = tblob;

}

========================控制台测试代码(读取图片到数据库,

再从数据库读取图片到特定路径下)=======================================

/**

* 按大对象数据类型BLOB的byte[]类型

* CLOB的java.lang.String

* 映射 并插入数据

* @author Administrator

*

*/

public class Test {

Session session=null;

Transaction tx=null;


/**

* 持久化数据,读取本地图片到数据库

*/

public void get1(){

try {

session=HibernateSessionFactory.getSession();

//前提是文件必须放在src路径下,读取的是当前项目的根目录

// InputStream input=this.getClass().getResourceAsStream("/file.txt");

//加载任意路径下的图片、大文件、视屏等(括号里的参数图片是绝对路径)

InputStream input=new FileInputStream("G:/在线拍卖/page/images/gou1.jpg");

tx=session.beginTransaction();

byte[] byteArray=new byte[input.available()];

input.read(byteArray);

input.close();

Bigobject b=new Bigobject();

b.setId(1);

b.setTblob(byteArray);

b.setTclob("一条狗");

session.save(b);

tx.commit();

} catch (HibernateException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

/**

* 从数据库bigObject表中按主键读取一条数据

* @throws IOException

*/

public void get2() throws IOException{

session=HibernateSessionFactory.getSession();

Bigobject b=(Bigobject)session.get(Bigobject.class, 1);

System.out.println("文本内容是:"+b.getTclob());

//吧字节数组数据通过字节流,输出到当前工程根目录下2.jpg中

if(b.getTblob()!=null){

FileOutputStream out=new FileOutputStream("dog1.jpg");

out.write(b.getTblob());

out.close();

}

}

public static void main(String[] args) throws IOException {

test6 t=new test6();

t.get1();

t.get2();

}

===================hibernate.cfg.xml的代码页给你贴一下吧,不过这都是自动生成的,你自己动手生成吧,一下是我自己的,想用的话得改参数的=======================

<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">


<!-- Generated by MyEclipse Hibernate Tools. -->

<hibernate-configuration>


<session-factory>

<property name="dialect">

org.hibernate.dialect.Oracle9Dialect

</property>

<property name="connection.url">

jdbc:oracle:thin:@localhost:1521:accp7 //!!!数据库名称

</property>

<property name="connection.username">scott</property>//!!!!!用户名

<property name="connection.password">accp</property>//!!!!!!密码

<property name="connection.driver_class">

oracle.jdbc.OracleDriver

</property>

<property name="myeclipse.connection.profile">scott</property>//!!!!!数据库实例名

<mapping resource="entity/Bigobject.hbm.xml" />

</session-factory>


</hibernate-configuration>


3 上面介绍了BLOB的byte[]存储,下面介绍另一种方式java.lang.Blob方式,还是直接粘贴代码

++++++++++++++++++++数据库还是上面图片上的,保持不变++++++++++++++++++++++

====================Bigobject.hbm.xml映射文件======================

<hibernate-mapping>

<class name="bean.Bigobject" table="BIGOBJECT">

<id name="id" type="java.lang.Integer">

<column name="ID" precision="6" scale="0" />

<generator class="native" />

</id>

<property name="tclob" type="java.sql.Clob">//这里用的是Clob的另一种方式,有疑问再问

<column name="TCLOB" />

</property>

<property name="tblob" type="java.sql.Blob">//!!!!!注意,这里是java.sql.Blob

<column name="TBLOB" />

</property>

</class>

</hibernate-mapping>


========================以下是bigobject实体类=======================

import java.sql.Blob;

import java.sql.Clob;


/**

* Bigobject entity. @author MyEclipse Persistence Tools

*/


public class Bigobject implements java.io.Serializable {


// Fields


private Integer id;

private Clob tclob;

private Blob tblob;


// Constructors


/** default constructor */

public Bigobject() {

}


/** full constructor */

public Bigobject(Clob tclob, Blob tblob) {

this.tclob = tclob;

this.tblob = tblob;

}


// Property accessors


public Integer getId() {

return this.id;

}


public void setId(Integer id) {

this.id = id;

}


public Clob getTclob() {

return this.tclob;

}


public void setTclob(Clob tclob) {

this.tclob = tclob;

}


public Blob getTblob() {

return this.tblob;

}


public void setTblob(Blob tblob) {

this.tblob = tblob;

}

}


==========================对应的控制台测试代码===========================


/**

* 讲字符串大对象声明为java.sql.Clob类型,二进制大对象声明为java.sql.Blob类型

* @author Administrator

*

*/

public class test7 {

Session session=null;

Transaction tx=null;

public void get1(){

try {

session=HibernateSessionFactory.getSession();

//前提是文件必须放在src路径下

InputStream input=this.getClass().getResourceAsStream("/upload.txt");

//加载任意路径下的图片、大文件、视屏等

// InputStream input=new FileInputStream("F:/1.jpg");

tx=session.beginTransaction();

byte[] byteArray=new byte[input.available()];

input.read(byteArray);

input.close();

Bigobject b=new Bigobject();

//依据二进制数据创建一个Blob对象 !!!!!重点 务必看清楚

b.setTblob(Hibernate.createBlob(byteArray));

//依据字符串数据创建一个Clob对象 !!!!!重点务必看清楚

b.setTclob(Hibernate.createClob("上传图片"));

session.save(b);

tx.commit();

} catch (HibernateException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public void get2(){

session=HibernateSessionFactory.getSession();

Bigobject obj=(Bigobject)session.get(Bigobject.class, 131);

//把Clob对象通过字符流读入到内存,并输出


try {

if(obj.getTclob()!=null){

Reader read=obj.getTclob().getCharacterStream();

char[] chArray=new char[1];

StringBuilder sb=new StringBuilder();

while(read.read(chArray)!=-1){

sb.append(new String(chArray));

}

System.out.println(sb.toString().trim());

}

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

//把Blob对象通过字节流读输出,并保存到当前工程根目录下,取名为upload.txt

try {

if(obj.getTblob()!=null){

InputStream in=obj.getTblob().getBinaryStream();

FileOutputStream fos=new FileOutputStream("upload.txt");

int b=-1;

while((b=in.read())!=-1){

fos.write(b);

}

fos.close();

in.close();

}

} catch (FileNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public static void main(String[] args) {

test7 t=new test7();

t.get1();

t.get2();

}

}

++++++++++++++++++++hibernate.cfg.xml同上++++++++++++++++++++++++++++



===================================================================

综上,Blob与Clob(字符串大对象)的写入读出的两种方法都有了(Clob的两种方法你自己捎带看看),都是完整代码,粘贴即可用,整理了两个多小时,希望对你有帮助!

❸ 怎么把数据保存到数据库

1.要下载一个对应你复数据制库的驱动包,如 sqlserver2008.java; 灵魂伴侣手写.
2.然后写个连接数据库的类.如JDBC.(连接数据库方法有很多种, 按照技术来分,首先学会JDBC连接数据库,然后连接池,然后框架技术Hibernate.) 灵魂伴侣手写.
3.每个数据库的表对应一张实体类,实体类是干什么用的? 1.用它可以OOP的思想的去操作数据库.
(增删改查), 表中的字段就封装成实体类里面的一个属性. 如表里是name char(10),那么实体类对应的是private String name;

❹ 怎样在把jsp页面中用户输入的数据的通过hibernate存入到数据库

这个问题步骤比较多
首先你要通过页面的表单提交到后台 后台或者直接用servlet 或者用回struts 或者用Springmvc 接受到答前台的参数
你想用hibernate来将数据存到数据库 你要引入hibernate的jar包 然后配置好hibernate的配置文件和映射文件 然后调用hibernate的保存的api即可。。。。。。。。。。。。

不知道这个基本的操作流程你是否满意

❺ hibernate如何实现 文件上传到指定路径 并将路径保存到数据库

文件上传步骤:

1、创建文件上传的Action....
在其方法(execute())中写文件上传代码:

try {
UploadForm uploadForm = (UploadForm) form;// TODO Auto-generated method stub
//获得文件
FormFile file1=uploadForm.getFile1();
//获得webroot 文件夹的绝对路劲
String path=request.getRealPath("/");
//request.getSession().getServletContext().getRealPath("/")
FileOutputStream fos=
new FileOutputStream(path+"/"+file1.getFileName());
//保存文件
fos.write(file1.getFileData());
//关流
fos.close();

response.getWriter().print("ok");

} catch (Exception e) {
e.printStackTrace();
}
return null;

2、在jsp页面中:
1、 表单的提交方式必须为post 提交;(必须的)
2 、 给表单加上一个属性 enctype="multipart/form-data";(必须的)
3 、在formbean 加入 FormFile 类型 如 private FormFile file1;

❻ hibernate缓存的详细配置

很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了。
我的经验主要来自hibernate2.1版本,基本原理和3.0、3.1是一样的,请原谅我的顽固不化。

hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。

二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查询缓存,加上
hibernate.cache.use_query_cache=true

缓存可以简单的看成一个Map,通过key在缓存里面找value。

Class的缓存
对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。假设是读写缓存,需要设置:
<cache usage="read-write"/>
如果你使用的二级缓存实现是ehcache的话,需要配置ehcache.xml
<cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" />
其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO)的超时时间,如果eternal="false",超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put的元素超过500个时,如果overflowToDisk="true",就会把缓存中的部分数据保存在硬盘上的临时文件里面。
每个需要缓存的class都要这样配置。如果你没有配置,hibernate会在启动的时候警告你,然后使用defaultCache的配置,这样多个class会共享一个配置。
当某个ID通过hibernate修改时,hibernate会知道,于是移除缓存。
这样大家可能会想,同样的查询条件,第一次先list,第二次再iterate,就可以使用到缓存了。实际上这是很难的,因为你无法判断什么时候是第一次,而且每次查询的条件通常是不一样的,假如数据库里面有100条记录,id从1到100,第一次list的时候出了前50个id,第二次iterate的时候却查询到30至70号id,那么30-50是从缓存里面取的,51到70是从数据库取的,共发送1+20条sql。所以我一直认为iterate没有什么用,总是会有1+N的问题。
(题外话:有说法说大型查询用list会把整个结果集装入内存,很慢,而iterate只select id比较好,但是大型查询总是要分页查的,谁也不会真的把整个结果集装进来,假如一页20条的话,iterate共需要执行21条语句,list虽然选择若干字段,比iterate第一条select id语句慢一些,但只有一条语句,不装入整个结果集hibernate还会根据数据库方言做优化,比如使用mysql的limit,整体看来应该还是list快。)
如果想要对list或者iterate查询的结果缓存,就要用到查询缓存了

查询缓存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
<cache name="net.sf.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="7200" overflowToDisk="true"/>
<cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/>
然后
query.setCacheable(true);//激活查询缓存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可选
第二行指定要使用的cacheRegion是myCacheRegion,即你可以给每个查询缓存做一个单独的配置,使用setCacheRegion来做这个指定,需要在ehcache.xml里面配置它:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
如果省略第二行,不设置cacheRegion的话,那么会使用上面提到的标准查询缓存的配置,也就是net.sf.hibernate.cache.StandardQueryCache

对于查询缓存来说,缓存的key是根据hql生成的sql,再加上参数,分页等信息(可以通过日志输出看到,不过它的输出不是很可读,最好改一下它的代码)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
参数是"tiger%",那么查询缓存的key*大约*是这样的字符串(我是凭记忆写的,并不精确,不过看了也该明白了):
select * from cat c where c.name like ? , parameter:tiger%
这样,保证了同样的查询、同样的参数等条件下具有一样的key。
现在说说缓存的value,如果是list方式的话,value在这里并不是整个结果集,而是查询出来的这一串ID。也就是说,不管是list方法还是iterate方法,第一次查询的时候,它们的查询方式很它们平时的方式是一样的,list执行一条sql,iterate执行1+N条,多出来的行为是它们填充了缓存。但是到同样条件第二次查询的时候,就都和iterate的行为一样了,根据缓存的key去缓存里面查到了value,value是一串id,然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。
可以看出来,查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候,都是既填充查询缓存又填充class缓存的。
这里还有一个很容易被忽视的重要问题,即打开查询缓存以后,即使是list方法也可能遇到1+N的问题!相同条件第一次list的时候,因为查询缓存中找不到,不管class缓存是否存在数据,总是发送一条sql语句到数据库获取全部数据,然后填充查询缓存和class缓存。但是第二次执行的时候,问题就来了,如果你的class缓存的超时时间比较短,现在class缓存都超时了,但是查询缓存还在,那么list方法在获取id串以后,将会一个一个去数据库load!因此,class缓存的超时时间一定不能短于查询缓存设置的超时时间!如果还设置了发呆时间的话,保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况,比如class缓存被程序强制evict了,这种情况就请自己注意了。

另外,如果hql查询包含select字句,那么查询缓存里面的value就是整个结果集了。

当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢?
hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。
当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。
可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。

Collection缓存
需要在hbm的collection里面设置
<cache usage="read-write"/>
假如class是Cat,collection叫children,那么ehcache里面配置
<cache name="com.xxx.pojo.Cat.children"
maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
overflowToDisk="true" />
Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。
这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新。

缓存策略
只读缓存(read-only):没有什么好说的
读/写缓存(read-write):程序可能要的更新数据
不严格的读/写缓存(nonstrict-read-write):需要更新数据,但是两个事务更新同一条记录的可能性很小,性能比读写缓存好
事务缓存(transactional):缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境,这个我没有怎么研究过

读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁,其他事务如果去取相应的缓存数据,发现被锁住了,然后就直接取数据库查询。
在hibernate2.1的ehcache实现中,如果锁住部分缓存的事务发生了异常,那么缓存会一直被锁住,直到60秒后超时。
不严格读写缓存不锁定缓存中的数据。

使用二级缓存的前置条件
你的hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。你操作数据库必需直接通过hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。hibernate3.0的大批量更新和删除是不更新二级缓存的,但是据说3.1已经解决了这个问题。
这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧。
SessionFactory也提供了移除缓存的方法,你一定要自己写一些JDBC的话,可以调用这些方法移除缓存,这些方法是:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
不过我不建议这样做,因为这样很难维护。比如你现在用JDBC批量更新了某个表,有3个查询缓存会用到这个表,用evictQueries(String cacheRegion)移除了3个查询缓存,然后用evict(Class persistentClass)移除了class缓存,看上去好像完整了。不过哪天你添加了一个相关查询缓存,可能会忘记更新这里的移除代码。如果你的jdbc代码到处都是,在你添加一个查询缓存的时候,还知道其他什么地方也要做相应的改动吗?

----------------------------------------------------

总结:
不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据。
如果受不了hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧。
在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。

阅读全文

与hibernate存储图片到数据库相关的资料

热点内容
手机语言编程用什么键盘 浏览:599
java环境已配置好了找不到文件 浏览:565
w10系统修改文件格式 浏览:179
桌面怎么把两个文件夹压缩成一个 浏览:293
u盘为什么存文件这么慢 浏览:807
手机的下拉菜单代码 浏览:384
宁波ug编程培训中心哪里好 浏览:565
描述性别是属于什么数据 浏览:752
听力障碍人群用哪些app 浏览:932
中国邮政ems微信号 浏览:699
win10删除更新补丁 浏览:870
哪里有卖二手电脑的app 浏览:139
希腊雅典数据中心在哪里 浏览:513
pad背景文件 浏览:608
dellwin7开机图片文件 浏览:638
linux进度条定时 浏览:619
重建路径文件 浏览:642
买房提前准备什么文件 浏览:926
cmd查看oracle版本 浏览:767
苹果用什么软件搜番号 浏览:409

友情链接