一、Oracle中Blob和Clob的作用
Blob是指二进制大对象也就是英文Binary Large Object的所写,而Clob是指大字符对象也就是英文Character Large Object的所写。由此可见这辆个类型都是用来存储大量数据而设计的,其中BLOB是用来存储大量二进制数据的;CLOB用来存储大量文本数据。
那么有人肯定要问既然已经有VARCHAR和VARBINARY两中类型,为什么还要再使用另外的两种类型呢?其实问题很简单,VARCHAR和VARBINARY两种类型是有自己的局限性的。首先说这两种类型的长度还是有限的不可以超过一定的限额,以VARCHAR再ORA中为例长度不可以超过4000;那么有人又要问了,LONGVARCHAR类型作为数据库中的一种存储字符的类型可以满足要求,存储很长的字符,那为什么非要出现CLOB类型呢?其实如果你用过LONGVARCHAR类型就不难发现,该类型的一个重要缺陷就是不可以使用LIKE这样的条件检索。(稍候将介绍在CLOB中如何实现类似LIKE的模糊查找)另外除了上述的问题外,还又一个问题,就是在数据库中VARCHAR和VARBINARY的存取是将全部内容从全部读取或写入,对于100K或者说更大数据来说这样的读写方式,远不如用流进行读写来得更现实一些。
在JDBC中有两个接口对应数据库中的BLOB和CLOB类型,java.sql.Blob和java.sql.Clob。和你平常使用数据库一样你可以直接通过ResultSet.getBlob()方法来获取该接口的对象。与平时的查找唯一不同的是得到Blob或Clob的对象后,我们并没有得到任何数据,但是我们可以这两个接口中的方法得到数据
例如:
Blob b=resultSet.getBlob(1);
InputStream bin=b.getBinaryStryeam();
Clob c=resultSet.getClob(2);
Reader cReader=c.getCharacterStream():
关于Clob类型的读取可以使用更直接的方法,就是直接通过ResultSet.getCharacterStream();方法获得字符流,但该方法并不安全,所以建议还是使用上面例子的方法获取Reader。
另外还有一种获取方法,不使用数据流,而是使用数据块。
例如
Blob b=resultSet.getBlob(1);
byte data=b.getByte(0,b.length());
Clob c=resultSet.getClob(2);
String str=c.getSubString(0,c.length()):
在这里我要说明一下,这个方法其实并不安全,如果你很细心的话,那很容易就能发现getByte()和getSubString()两个方法中的第二个参数都是int类型的,而BLOB和CLOB是用来存储大量数据的。而且Bolb.length()和Clob.length()的返回值都是 long类型的,所以很不安全。这里不建议使用。但为什么要在这里提到这个方法呢?稍候告诉你答案,这里你需要记住使用数据块是一种方法。
在存储的时候也同样的在PreparedStatement和CallableStatememt中,以参数的形式使用setBlob()和 setClob方法把Blob和Clob对象作为参数传递给SQL。这听起来似乎很简单对吧,但是并非我们想象的这样,很不幸由于这两个类型的特殊,JDBC并没有提供独立于数据库驱动的Blob和Clob建立对象。因此需要自己编写与驱动有关的代码,但这样又牵掣到移植性。怎样才是解决办法呢?这就要用到前面说过的思想了使用数据块进行写操作。同样用PreparedStatement和CallableStatememt类,但参数的设置可以换为setAsciiStream、setBinaryStream、setCharacterStream、setObject(当然前3个同样存在长度的问题)
下面给大家个例子以方便大家理解
public void insertFile(File f) throws Exception{
FileInputStream fis=new FileInputStream(f,Connection conn);
byte[] buffer=new byte[1024];
data=null;
int sept=0;int len=0;
while((sept=fis.read(buffer))!=-1){
if(data==null){
len=sept;
data=buffer;
}else{
byte[] temp;
int tempLength;
tempLength=len+sept;
temp=new byte[tempLength];
System.arraycopy(data,0,temp,0,len);
System.arraycopy(buffer,0,temp,len,sept);
data=temp;
len=tempLength;
}
if(len!=data.length()){
byte temp=new byte[len];
System.arraycopy(data,0,temp,0,len);
data=temp;
}
}
String sql="insert into fileData(filename,blobData) value(?,?)";
PreparedStatement ps=conn.prepareStatement(sql);
ps.setString(1,f.getName());
ps.setObject(2,data);
ps.executeUpdate();
}
最后由于刚刚说过Clob类型读取字符的长度问题,这里再给大家一段代码,希望对你有帮助
public static String getClobString(ResultSet rs, int col){
try{
Clob c=resultSet.getClob(2);
Reader reader=c.getCharacterStream():
if(reader== null){
return null;
}
StringBuffer **= new StringBuffer();
char[] charbuf= new char[4096];
for(int i= reader.read(charbuf); i> 0; i= reader.read(charbuf)){
**.append(charbuf, 0, i);
}
return **.toString();
} catch(Exception e){
return"";
}
}
另外似乎前面还提到过LIKE检索的问题。LONGVARCHAR类型中不可以用LIKE查找(至少ORA中不可以使用,其他的数据库我没有试过),在ORA中我们可以使用这样一个函数dbms_lob.instr来代替LIKE来个例子吧
select docid,dat0 from text where dbms_lob.instr(dat0,'魏',1,1)>0
在text表中有两个字段docid用来放文档编号dat0为clob类型存放文章内容;这句话的意思就是检索第一条dat0中出现第一次"魏"字的数据。听起来这个检索的数据有点象google的“手气不错”
二、如何用ResultSet.getBlob得到解密后的数据
1.使用jdk中的方法进行传输。在ResultSet中有getBlob()方法,在PreparedStatement中有setBlob()方法,所以大多数人都会尝试setBlob
(),getBlob()进行读写,或者两个数据库之间BLOB的传输。这种方法实际上是行不通的,据网上的一些资料介绍,说sun官方的文档有些方法
都是错误的。
2.使用ResultSet.getBinaryStream和PreparedStatement.setBinaryStream对BLOB进行读写或两个数据库间的传输。这种方法我自己尝试过,
发现,如果BLOB中存储的是文本文件的话,就没问题,如果是二进制文件,传输就会有问题。
根据自己的经验,以及查阅了Oracle的官方文档,都是使用如下处理方法:
1.新建记录,插入BLOB数据
1.1首先新建记录的时候,使用oracle的函数插入一个空的BLOB,假设字段A是BLOB类型的:
insert xxxtable(A,B,C) values(empty_blob(),'xxx','yyyy')
1.2后面再查询刚才插入的记录,然后更新BLOB,在查询前,注意设置Connection的一个属性:
conn.setAutoCommit(false);如果缺少这一步,可能导致fetch out of sequence等异常.
1.3查询刚才插入的记录,后面要加“ for update”,如下:
select A from xxxtable where xxx=999 for update,如果缺少for update,可能出现row containing the LOB value is not locked
的异常
1.4从查询到的 BLOB字段中,获取blob并进行更新,代码如下:
BLOB blob=(BLOB) rs.getBlob("A");
OutputStream os= blob.getBinaryOutputStream();
BufferedOutputStream output= new BufferedOutputStream(os);
后面再使用output.write方法将需要写入的内容写到output中就可以了。例如我们将一个文件写入这个字段中:
BufferedInputStream input= new BufferedInputStream(new File("c://hpWave.log").toURL().openStream());
byte[] buff= new byte[2048];//用做文件写入的缓冲
int bytesRead;
while(-1!=(bytesRead= input.read(buff, 0, buff.length))){
output.write(buff, 0, bytesRead);
System.out.println(bytesRead);
}
上面的代码就是从input里2k地读取,然后写入到output中。
1.5上面执行完毕后,记得关闭output,input,以及关闭查询到的ResultSet
1.6最后执行conn.commit();将更新的内容提交,以及执行conn.setAutoCommit(true);改回Connction的属性
2.修改记录,方法与上面的方法类似,
2.1首先更新BLOB以外的其他字段
2.2使用1.3中类似的方法获取记录
2.3修改的过程中,注意以下:a需要更新的记录中,BLOB有可能为NULL,这样在执行blob.getBinaryOutputStream()获取的值可能为
null,那么就关闭刚才select的记录,再执行一次update xxxtable set A= empty_blob() where xxx,这样就先写入了一个空的BLOB(不是null),然后再
使用1.3,1.4中的方法执行更新记录.b注意别忘了先执行setAutoCommit(false),以及"for update",以及后面的conn.commit();等。
3.读取BLOB字段中的数据.
3.1读取记录不需要setAutoCommit(),以及 select....for update.
3.2使用普通的select方法查询出记录
3.3从ResultSet中获取BLOB并读取,如下:
BLOB b_to=(BLOB) rs.getBlob("A");
InputStream is= b_from.getBinaryStream();
BufferedInputStream input= new BufferedInputStream(is);
byte[] buff= new byte[2048];
while(-1!=(bytesRead= input.read(buff, 0, buff.length))){
//在这里执行写入,如写入到文件的BufferedOutputStream里
System.out.println(bytesRead);
}
通过循环取出blob中的数据,写到buff里,再将buff的内容写入到需要的地方
4.两个数据库间blob字段的传输
类似上面1和3的方法,一边获取BufferedOutputStream,另外一边获取BufferedInputStream,然后读出写入,需要注意的是写入所用的
Connection要执行conn.setAutoCommit(false);以及获取记录时添加“ for update”以及最后的commit();
总结以上方法,其根本就是先创建空的BLOB,再获取其BufferedOutputStream进行写入,或获取BufferedInputStream进行读取
(1)对数据库clob型执行插入操作
*************************************************
java.sql.PreparedStatement pstmt= null;
ResultSet rs= null;
String query="";
conn.setAutoCommit(false);
query="insert into clobtest_table(id,picstr) values(?,empty_clob())";
java.sql.PreparedStatement pstmt= conn.prepareStatement(query);
pstmt.setString(1,"001");
pstmt.executeUpdate();
pstmt= null
query="select picstr from clobtest_table where id='001' for update";
pstmt= con.prepareStatement(query)
rs= pstmt.executeQuery();
oracle.sql.CLOB clobtt= null;
if(rs.next()){
clobtt=(oracle.sql.CLOB)rs.getClob(1);
}
Writer wr= clobtt.getCharacterOutputStream();
wr.write(strtmp);
wr.flush();
wr.close();
rs.close();
con.commit();
(2)通过sql/plus查询是否已经成功插入数据库
*************************************************
PL/SQL的包DBMS_LOB来处理LOB数据。察看刚才的插入是否成功。使用DBMS_LOB包的getlength这个procedure来检测是否已经将str存入到picstr字段中了。如:
SQL> select dbms_lob.getlength(picstr) from clobtest_table;
(3)对数据库clob型执行读取操作
*************************************************
读取相对插入就很简单了。基本步骤和一半的取数据库数据没有太大的差别。
String description=""
query="select picstr from clobtest_table where id='001'";
pstmt= con.prepareStatement(query);
ResultSet result= pstmt.executeQuery();
if(result.next()){
oracle.jdbc.driver.OracleResultSet ors=
(oracle.jdbc.driver.OracleResultSet)result;
oracle.sql.CLOB clobtmp=(oracle.sql.CLOB) ors.getClob(1);
if(clobtmp==null|| clobtmp.length()==0){
System.out.println("======CLOB对象为空");
description="";
}else{
description=clobtmp.getSubString((long)1,(int)clobtmp.length());
System.out.println("======字符串形式"+description);
}
}
三、Hibernate上手指南
Hibernate上手
Hibernate,很久以前我就听说过这个名词,但是似乎没什么动力让我去接近它,感觉它是一个很复杂的东西,一直没搞明白它到底是用来做什么的。直到接手了一个项目在技术选型的时候我再一次的看到了Hibernate。我尝试着去使用它,发现它并不是我想像中的那么深奥,它很易用。你并不需要了解它的内部结构,它一样能为你工作的很好,如果你理解了它到底能为你做什么的话
本文着重讲述了为什么要使用Hibernate,此外也简单的介绍了如何使用Hibernate,以及Hibernate中的一些基本概念。我想借这篇文章来向还没有接触过Hibernate的开发者推荐款优秀的开源ORM产品,如果你已经实践过Hibernate,那么我想你没有必要再看下去。
一、Why Hibernate?
现在流行“测试驱动开发”,相似的我觉得“目的驱动学习”是一种比较好的接受新技术,新知识的途径。在学习一样新的技术之前,首先得明确到底有没有必要学习,已有的技术是否已经工作的很好,学习这个新的技术是为了解决什么问题。如果你明确了以上问题,那么寻找并学习新的技术将会事半功倍,并且能快速应用到实际的开发当中来提高效益。
要说Hibernate,就得先介绍一下Object/Relation Mapper(ORM),中文翻译为对象关系映射。之所以会产生这样的概念是源于目前软件开发中的一些不协调的思想。目前流行的编程模型是OOP(Object Oriented Programming),面向对象的编程,而目前流行的数据库模型是Relational Database,这两者思考的方式不一样,这必然产生了开发过程中的不协调。ORM框架(也称为持久层框架,)的出现就是为了解决这样的问题,屏蔽底层数据库的操作,以面向对象的方式提供给开发者操作数据库中数据的接口。目前流行的ORM框架有Apach OJB,Hibernate,iBatis等等,当然最完善,最好用的是Hibernate,至少我这样认为。或许你对“持久层”感到迷惑,其实说白了很简单,把数据放到数据库中叫做持久化(内存种的数据当然不是持久的),那么负责这一操作的结构层面就叫做持久层。你以前应该听说过表现层,业务层,数据层,那么持久层是在业务层和数据层之间的一层,或者说持久层是数据层的一部分。
接下来,我想通过一个实际开发中的例子来说明ORM带给我们的好处。先来讲一下我们的需求,数据库中有三张表,一张student,一张course,另外一张course_slection。其中student用来保存学生信息,course用来表示课程信息,course_selection用来表示学生的选课信息。(表的详细结构这里我就省略了,因为这并不重要)现在要求编写一个程序,用来选出指定学号学生所选的课程名字,那么可能会出现以下几种程序编写的方式:
1.菜鸟级
代码片段1:
public List selectCourses(String studentId)
{
Connection con= null;
Statement sta= null;
try
{
Class.forName("oracle.jdbc.driver.OracleDriver");
con= DriverManager.getConnection("jdbc:oracle:thin:@10.85.33.199:1521:glee",
"test","test");
String sql="select* from course_selection";
String sql2="select name from course where id='";
sta= con.createStatement();
ResultSet rs= sta.executeQuery(sql);
List list= new LinkedList();
while(rs.next())
{
ResultSet rs2= sta.executeQuery(sql2+
rs.getString("course_id")+"'");
if(rs2.next())
{
list.add(rs2.getString("name"));
}
}
return list;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
这段程序你一定看的很晕吧,什么乱七八糟的都搞在一起,那么接下来看一段改进过的程序。
2.改进后的代码
代码片段2:
class DBHelper
{
public static Connection getConnection()
{
try
{
Class.forName(Constants.DB_DRIVER);
return DriverManager.getConnection(Constants.DB_URL,
Constants.DB_USER, Constants.DB_PWD);
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
}
public List selectCourses(String studentId)
{
Connection con= null;
Statement sta= null;
try
{
con= DBHelper.getConnection();
String sql="select* from course_selection";
String sql2="select name from course where id='";
sta= con.createStatement();
ResultSet rs= sta.executeQuery(sql);
List list= new LinkedList();
while(rs.next())
{
ResultSet rs2= sta.executeQuery(sql2+ rs.getString("course_id")+"'");
if(rs2.next())
{
list.add(rs2.getString("name"));
}
}
return list;
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
这段代码的形式是一种被广泛采用的形式,相对第一段代码来说,应该已经有所进步,分离了数据库连接操作,并把数据库连接信息交给单独的类完成(一般放在配置文件里面),往往在开发中还会引入数据库连接池(Connection Pool)来提高性能,我这里都尽量简化了。但这些并不能从根本上改善程序的结构,在业务代码中仍然混杂了很多数据库操作,结构不清晰。下面来看一段彻底分离数据库操作的代码:
3. DAO模式
代码片段3:
public List selectCourses(String studentId)
{
StudentDAO sd= new StudentDAO();
Student student= sd.findById(studentId);
Set set= student.getCourseSelections();
List courseNames= new LinkedList();
for(Iterator iter= set.iterator(); iter.hasNext();)
{
CourseSelection element=(CourseSelection) iter.next();
courseNames.add(element.getCourse()。getName());
}
return courseNames;
}
是不是感觉代码少了很多?或许你对这段代码有点迷惑,没关系,后文会详细解释。我想先解释一下DAO。其实DAO和Hibernate没有必然联系,只不过一般用Hibernate的程序都用DAO模式。DAO的全称是Data Access Object,程序要访问数据库中的数据(包括获取,更新,删除)都通过DAO来访问,实际上DAO才是真正屏蔽了所有数据库操作的东西,这样在业务代码中就可以完全隔离数据层的代码。如果我告诉你,在真正用Hibernate开发的时候,要完成上文提到的功能,需要手写的代码就是“代码片段3”这么多,甚至更少,你是不是有很大的动力去学习Hibernate?那么好吧,让我们开始Hibernate之旅。
二、持久层的组成
这一节的名字应该换成“基于Hibernate的持久层的组成”更合适一点,可是它太长了。既然Hibernate是用来开发持久层,那么我先介绍一下这个持久层中的各个元素。
1. POJO:Plain Old Java Object,你可以把它看作是简单的JavaBean。一般说来,一张数据库表对应一个POJO,也就是对象/关系的一一映射。
2. DAO:对于每一个POJO,一般都有一个DAO与之对应,承担所有关于该POJO的访问控制。实际上也就是控制了对数据库中一张表的访问控制。
3.*.hbm.xml文件:这个文件定义了POJO和数据库中的表是如何映射的,比如POJO中的字段对应数据库表中的哪个字段等等。一般每个映射都用单独的文件来描述,也就是有一个POJO就有一个*.hbm.xml文件。
4.*.cfg.xml文件:这个文件定义了Hibernate的基本信息,比如数据库驱动,用户名,密码等等连接信息,也包括了所有要用的*.hbm.xml文件,在初始化的时候,Hibernate会读取这个文件来找相应的映射文件完成对象/关系。
我们还是以上文的例子来详细描述一下这里提到的各个元素的内容。
1. Student.java:
代码片段4:
public class Student implements java.io.Serializable
{
private String id;
private String name;
private Set courseSelections= new HashSet(0);
public Student()
{
}
public String getId()
{
return this.id;
}
public void setId(String id)
{
this.id= id;
}
public String getName()
{
return this.name;
}
public void setName(String name)
{
this.name= name;
}
public Set getCourseSelections()
{
return this.courseSelections;
}
public void setCourseSelections(Set courseSelections)
{
this.courseSelections= courseSelections;
}
}
#p#副标题#e#
这个类就是一个POJO,你可以很明显的看出来它就是一个JavaBean。我想解释它的courseSelection字段。很显然,在数据库表student中,没有这个字段。这里的这个字段是因为一个外键引用,course_selection的student_id是一个外键,引用了student表中的id字段。那么在Student类中courseSelection来记录这样的外键关系,也就是说,当我们获取了Student对象以后,就可以直接获取他的选课记录,这样就为上层的调用提供了很大的方便。这里有点模糊没关系,我在介绍映射定义文件(*.hbm.xml)的时候还会提到这个问题。
2. StudentDAO.java
代码片段5:
public class StudentDAO
{
Session session;
public StudentDAO()
{
Configuration cfg= new Configuration();
cfg.configure("/hibernate.cfg.xml");
SessionFactory sessionFactory= cfg.buildSessionFactory();
session= sessionFactory.openSession();
}
public void save(Student transientInstance)
{
session.save(transientInstance);
}
public void delete(Student persistentInstance)
{
session.delete(persistentInstance);
}
public Student findById(java.lang.String id)
{
List list= session.createCriteria(Student.class)。add(Expression.eq("id", id))。list();
if(list.size()
0)
{
return(Student)list.get(0);
}
return null;
}
}
这里的构造函数是用来启动Hibernate,并获取session。打开一个session就相当于打开了一个数据库连接,然后我们就可以对这个session进行操作,完成数据库操作,完全不用写SQL语句。我这里Hibernate的启动方式写的很不规范,系统应该只需要完成一次Hibernate启动就可以在不同的DAO中使用,我把它写在构造函数里面纯粹是为了简化演示代码。
你可以看到save和delete方法都很简单直接对对象操作,而findById就有些麻烦,因为这里有一个查询过程在里面。Hibernate里面查询可以用Criteria这个类来完成,我们也常用Hibernate独有的HQL(Hibernate Query Language)来完成查询。当然Hibernate也是支持原生SQL的。关于查询的详细信息请参考其他文章或书籍,我只是演示一个流程,介绍一些概念。
3. Student.hbm.xml
代码片段6:
hibernate-mapping
class name="Student" table="STUDENT"
id name="id" type="string"
column name="ID" length="10"/
generator class="assigned"/
/id
property name="name" type="string"
column name="NAME" not-null="true"/
/property
set name="courseSelections" inverse="true"
key
column name="STUDENT_ID" length="10"
not-null="true"/
/key
one-to-many class="CourseSelection"/
/set
/class
/hibernate-mapping
这个文件定义了Student类和Student表是如何映射的。class元素定义了Sudent类和STUDENT表映射,然后就定义了各个属性是如何映射的。如果一个属性是数据库的key,那么会用id标签来定义,column定义了当前类的属性和数据库中的哪个字段对应,generator是id特有的。一般来说id是自增的,由于我的数据库是用的Oracle,它没有自增字段,要实现自增必须用Sequence,这超出了本文的范围,所以我就用assigned来简化示例代码。assigned表示id是用户给定的。
有一个比较特别的标签是set,它对应着数据库中的外键关系,上文我提到的通过Student对象可以获得所有相关的选课记录就是通过这里的定义实现的。name属性对应了Student类中的字段名,key表示哪个字段是外键,one-to-many表示Student和CourseSelection是一对多关系,这和事实相符。类似的还有many-to-one,many-to-many,不过这些都不常用,我不介绍了。Hibernate根据这个映射定义文件,在实例化一个POJO(比如Student)的时候,会自动的把定义过映射的属性用数据库中的数据填充,set也包括在内。
4. hibernate.cfg.xml
代码片段7:
hibernate-configuration
session-factory
property name="connection.username"test/property
property name="connection.url"
jdbc:oracle:thin:@10.85.33.199:1521:glee/property
property name="dialect"
org.hibernate.dialect.Oracle9Dialect/property
property name="connection.password"test/property
property name="connection.driver_class"
oracle.jdbc.OracleDriver/property
mapping resource="Student.hbm.xml"/mapping
mapping resource="CourseSelection.hbm.xml"/mapping
mapping resource="Course.hbm.xml"/mapping
/session-factory
/hibernate-configuration
这个文件我不解释了,自己看吧。结合上文StudentDAO的例子,我想你应该能看明白。
看了这么多,或许你会有点头皮发麻,POJO,DAO,配置文件好像要写的东西还是很多。值得庆幸的是现在Hibernate已经发展的比较成熟了,有很多工具来帮助我们完成这些工作,比如MiddleGen,Hibernate Synchronizer等等。我使用的开发工具是Eclipse+MyEclipse,我所要做的只是把数据库表建好,然后MyEclipse提供的工具会自动根据数据库表生成POJO,DAO,*.hbm.xml,甚至hibernate.cfg.xml都是自动完成的(前提是MyEclipse知道你的数据库连接信息)。我并不打算介绍如何用IDE来开发Hibernate,你可以参考IDE的帮助文档。
到这里为止,使用Hibernate进行开发的基本组成元素我都介绍好了,强烈建议你马上实践一遍,即使有些不理解,也先依葫芦画瓢一个。对了,别忘了把Hibernate的包down下来放到classpath里面。
三、Session与SessionFactory
Session可以说是Hibernate的核心,Hibernate对外暴露的接口就是Session。所以我这里讲一下有关Session的常用函数和特性。
在讲Session之前,我想先提一下SessionFactory,这个东西不复杂,只要配置好就行了。顾名思义,SessionFactory就是用来创建Session的。SessionFactory是线程安全的,也就是说对于同一个数据库的所有操作共享一个SessionFactory就行了。回头看代码片段5,我们可以看到SessionFactory的常用配置方式。
代码片段8:
Configuration cfg= new Configuration();
cfg.configure("/hibernate.cfg.xml");
SessionFactory sessionFactory= cfg.buildSessionFactory();
我们通过Configuration来读取配置文件,然后就可以创建SessionFactory,这段代码在所有系统中都大同小异,一般就是xml配置文件的名字不一样,所以也没什么好说的。
当我们有了SessionFactory以后就可以获取Session了。调用SessionFactory.openSession()就会返回一个Session实例,然后我们操作这个Session来访问数据库。值得一提的是Session并不是线程安全的,也就是每一个线程都必须有自己的Session。所以我们一般通过以下方法来获取和关闭Session:
代码片段9:
public static Session currentSession() throws HibernateException
{
Session session=(Session) threadLocal.get();
if(session== null||!session.isOpen())
{
if(sessionFactory== null)
{
try
{
cfg.configure(CONFIG_FILE_LOCATION);
sessionFactory= cfg.buildSessionFactory();
}
catch(Exception e)
{
e.printStackTrace();
}
}
session=(sessionFactory!= null)?
sessionFactory.openSession(): null;
threadLocal.set(session);
}
return session;
}
public static void closeSession() throws HibernateException
{
好了,关于ResultSet的介绍与使用和如何用ResultSet.getBlob得到解密后的数据的问题到这里结束啦,希望可以解决您的问题哈!