Hibernate基础学习记录文本

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

一、第一个应用实例
1.搭建环境:新建一个名为HibernateDemo的java工程,并导入Hibernate的jar包,特别要注意除了导入lib下的jar包还需导入hibernate3.jar核心jar包。

由于涉及数据库操作,还应导入mysql驱动包。

说明,如果使用最新的hibernate,hibernate开发的基本jar包(7个) 来源:hibernate-distribution-3.3.2.GA.zip
hibernate3.jar
lib\required下的所有jar包
2.简述Hibernate的作用:ORM:Object Relational Mapping,对象关系映射。

将java 程序中的对象自动持久化到关系数据库中。

而Hibernate的作用好比就是在java对象与关系数据库之间的一座桥梁,它主要负责两者之间的映射。

在Hibernate内部封装了JDBC 技术(但只是一个轻量级的封装,因而可以让程序设计人员更方便的以面向对象的思想操纵数据库),并向外提供API接口。

3.建新一个名为User.java的类,即是上面所说的java对象。

我们以后称这种类为实体类(或是持久化类),它的对象为实体对象(或是持久化对象)。

User.java内容如下:package com.asm.hibernate.domain;
import java.util.Date;
public class User {
private int id;
private String name;
private Date date;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
4.编写配置文件:User.hbm.xml。

它和User.java放在同一个包下。

内容如下:<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="com.asm.hibernate.domain">
<class name="User">
<id name="id">
<generator class="native"/>
</id>
<property name="name"></property>
<property name="date"></property>
</class>
</hibernate-mapping>
此配置文件,是用来为User.java进行配置的,我们以后称这种文件为实体配置文件(或是持久化类映射文件)<class>用来关联一个java类,注意在前面的根元素下有一个package属性,这样结合这个package和class标签下所指定的类名,就共同关联映射了一个java类。

其实可以这样理解,每一个包下都有实体配置文件,而这个配置文件开始的根元素package指定了此文件所处的位置(或是说它所关联的包),根元素下可以有多个<class>标签(查阅dtd文件),它们可以分别来关联包下的java类文件。

<class>标签,一般建议至少有两个属性:name属性用来关联一个java类,比如这里关联了User类;table属性用来指定这个类所对应的表文件,如果不指定,系统会自动name 指定的类文件进行关联(比如上面实际是:<class name="User" table="user">)
<class>标签下的子标签:
●<id>子标签实际就是用来映射主键,<id>下的name就是用来指java类中的id属性,
而它可以有一个column属性用来指定表中的主键。

同时注意在此标签下有一个
<generator class="native"/>标签,它是用来指定主键的生成方式。

●<property>子标签,就是用来指定java类的属性映射到表中的一个字段,默认下此
标签没有指定column属性,即是说它会把name所关联的属性名作为字段名。


果不想java类中的某些属性映射到表中,只要不用这个标签来关联这些属性即可。

总结:上面的<class><id><property>的name属性都分别指定了java类,java类的属性。

而table,column是用来指定表,字段名
配置文件:hibernate.cfg.xml。

它放在当前的项目的根目录下。

内容如下:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="foo">
<property
name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property
name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property> <property name="ername">root</property>
<property name="hibernate.connection.password">123456</property>
<property
name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <property name="hibernate.hbm2ddl.auto">create</property>
<mapping resource="com/asm/hibernate/domain/User.hbm.xml"/> </session-factory>
</hibernate-configuration>
主配置文件,完成了驱动注册,数据库连接,并关联了相应的java对象配置文件。

说明:<mapping>具体指定了关联的所有实体配置文件,关于它的作用可以注释掉此属性看效果。

另通过<property
name="hibernate.hbm2ddl.auto">create</property>指定了根据实体配置文件来自动生成表,其中包括:create/create-drop/update/validate四种可选方式。

5.编写测试类:UserTest.java 内容如下:
package com.asm.hibernate.test;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import er;
public class UserTest {
public static void main(String []args){
Configuration cf=new Configuration();
cf.configure();
SessionFactory sf=cf.buildSessionFactory();
Session s=sf.openSession();
Transaction ts=s.beginTransaction(); //事务
User user=new User();
user.setName("jack");
user.setDate(new Date());
s.save(user);
mit(); //提交事务
s.close();
System.out.println("done");
}
}
6.分析流程:首先抛开Transaction tx=s.beginTransaction()和mit(),因为它们是提交事务得。

支持提交事务意味着支持数据回滚。

说明,通常情况下,很多数据库都默认支持提交事务,所以加这两句代码非常必要。

下面具体谈流程:
第一步:获取SessionFactory对象,它会首先构建一个Configuration对象,此对象调用可以调用configure()和configure(String resource)这两种方法:这两种方法在Configuration中的源代码如下:
public Configuration configure() throws HibernateException {
configure( "/hibernate.cfg.xml" );
return this;
}
public Configuration configure(String resource) throws HibernateException { ( "configuring from resource: " + resource );
InputStream stream = getConfigurationInputStream( resource );
return doConfigure( stream, resource );
}
分析这两个源代码可以知道:无参调用最终也是调用这个有参数的方法,所以我们也可以
直接传参数调用。

现在的重点是读配置文件,这个配置文件我们一般放在eclipse的scr根目录下,而当eclipse编译时会自动把这个目录下的文件编译到bin目录下,而这个bin目录下是被配置成classpath环境变量,而configure方法就是在classpath环境变量下查找配置文件。

再来分析,无参调用configure方法时,默认的是传递的hibernate.cfg.xml配置文件,所以只有取名为这个的配置文件,才可以调用无参的configure方法,如果是其它名字的配置文件,则调用含参的配置文件,并且这个参数名应为这个配置文件的名字。

当读取配置文件后的Configuration对象,才是一个真正意义上可操控的实例对象。

然后,再用这个对象来构建一个SessionFactory对象。

强调说明,这一步整个操作最好是放在类的静态代码块中,因为它只在该类被加载时执行一次。

第二步:得到一个Session实例,以进行数据库CRUD操作
第三步:实例化一个java类
第四步:持久化操作
第五步:后续操作:主要是关闭连接
7.实体类定义规则:
Domain object(java对象)必须要有构造方法,同时建议有一个id属性,为了赖加载,这个java类的声明最好不用final。

8.开发流程:
官方推荐:先Domain object 再mapping,最后是DB。

常用开发方式:DB开始,由工具来生成mapping和Domain object。

9.总结基本步骤:
环境搭建(导入相关包等) —>实体类及配置文件—>主配置文件(完成了数据库的配置及通过设置属性创建了相应的表)—>得到Session测试应用。

二、优化代码
1.为会么要优化
在前面我们已经知道,获取SessionFactory对象是一个重复的过程。

因此我们可以把这个操作写成一Util类。

下面我们把这一步写成工具类HibernateUtil,内容如下:package com.asm.hibernate.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static SessionFactory sf;
private HibernateUtil() {
}
static {
Configuration cf = new Configuration();
cf.configure();
sf = cf.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sf;
}
public static Session getSession() {
return sf.openSession();
}
}
2.优化测试类
下面复制UserTest.java代码改为UserTest2.java并进行修改修改后的内容如下:package com.asm.hibernate.test;
import java.util.Date;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import er;
import com.asm.hibernate.utils.HibernateUtil;
public class UserTest2 {
static void addUser(User user) {
Session s = null;
Transaction ts = null;
try {
s = HibernateUtil.getSession();
ts = s.beginTransaction();
s.save(user);
mit();
} catch (HibernateException e) {
if (ts != null)
ts.rollback();
throw e;
} finally {
if (s != null)
s.close();
}
}
public static void main(String[] args) {
User user = new User();
user.setName("richie");
user.setDate(new Date());
addUser(user);
}
}
说明,在addUser方法中其实也可以不用catch语句捕获。

因为关键的关闭连接已在finally实现。

上面的例子可以作为以后Hibenate操作的一个典型模板,只需要修改主方法中的内容即可。

3.get方法:可以在UserTest2.java中增加这个方法:
static User getUser(int id) {
Session s = null;
try {
s = HibernateUtil.getSession();
return (User) s.get(User.class, id);
/*
* User user=(User) s.load(User.class,id);
* System.out.println("----load----"+user);
* System.out.println(user.getName());
* //load只是准备连接到数据库,当增加上面一句操作时表示有真正的数据库操作,这时它才会去连接数据库return user;
*/
} finally {
if (s != null)
s.close();
}
}
以上的代码,实现了数据库的查询操作,这里的get()方法需要传递两个参数,理解传递的参数:由于Session可以管理多个数据库所对应的多个实体对象,如果只是传递id将不能正确定位表,因而必须传递这个实体对象,get方法才能去查找这个实体对象所对应的数据库中的表。

用这个方法得到User对象后,便可以用此对象的方法来得到相关属性(也就是数据库表中的字段)
4.load()方法,懒加载。

它的特点是:只有实际操作才会被加载,且它是生成的这个User.java的子类,可以从打印结果看出。

也正因此,所以前面建议实例类不使用final。

强调:如果是懒加载,即使数据库中查不到数据,上面的user对象永远不会为空,因为它的内部实现实际上是new了一个User(子)类对象。

下面再在main方法中测试,增加语句如下:
User u = getUser(1);
System.out.println("id=" + u.getId() + "\t name=" + u.getName());
5.控制台显示:
<property name="show_sql">true</property>在总配置文件中增加这个属性将会在控制台显示数据库操作的“数据库语言”。

称这个属性为数据库语言显示。

三、Session中的主要方法
1.保存数据:save,presist 说明:这两种方法的主要区别主要体现在未开启事务时。

save 方法如果是没开启事务,会执行相关sql语句,随后再回滚。

而presist根本就不执行这些sql语句。

2.删除对象:delete
3.更新数据:update 说明,如果数据库中没有记录将会出现异常
4.查找数据:get,立刻访问数据库load,返回的是代理,不会立即访问数据库。

5.选择操作:saveOrUpdate,merge,根据id和version的值来确定是save还是update。

saveOrUpdate方法的主要作用:可以把瞬时对象或脱管对象转成持久对象,而不需要具体判断对象是处在瞬时态或是脱管态来选择save或update来让对象变成持久态。

只要调用此方法就能由id和version来灵活选择是保存或更新。

而merge方法一个对象后,对象仍是脱管态。

5.持久对象:lock,把对象变成持久对象,但不会同步对象的状态。

四、对象三种状态
1.瞬时(transient):数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器回收,一般是new出来的且与Session无关系的对象。

2.脱管-游离(detached):数据库中有数据与之对应,但当前没有Session与之关联:脱管对象状态发生改变,Hibernate不能检测到。

3.持久(persistent):数据库有数据与之对应,当前与Session有关联,并且相关联的Session没有关闭,事务没有提交:持久对象状态发生改变时,在事务提交时会影响到数据库。

理解:与Session是否关联,数据库是否有数据与之对应是判断三种对象状态的依据。


如,瞬时状态跟它们均无关;脱管,只是数据库有数据与之对应,失去了Session对它的管理;而持久与两者者有关。

从过程中理解三种对象状态:结合前面的实例,当我们User user=new User()一个对象时,它表示创建一个瞬时对象,当调用save(user)方法时,这个对象成为持久对象,直到事务提交,数据库连接关闭。

在这期间,如果我们user.setXXX()时,会对这个持久对象产生影响,最终它也会被提交到数据库,它的最终提交是在提交事务时。

比如save(user)方法后,跟user.setName("new name");和user.setPassword("new password");这两句,这样它会在提交时务时,采取对数据库的更新操作,也就是说数据库连接关闭后,数据库存的是“new name”和“new password”而如果开启了“数据库语言显示”可以发现执行两次操作:一次是save方法的插入操作,一次是setXXX后提交事务时的更新作(特别说明,持久对象在发生改变时,比如setXXX方法改变对象内容时,会在最后,即提交事务时统一进行更新操作,而并非每一次改变就执行一次更新,这样可以保证与数据库的交互更高效合理)。

当执行完save方法后,我们关闭数据库连接时,这时的user对象就是脱管状态,因为它在数据库有数据与之对应而脱管状态的最好例子是当我们用get方法得到一个对象并关闭连接时
补充说明:既然我们已经知道了持久对象可以被Hibernate检测到进行更新操作,那么update是否还有用了?有,比如脱管对象就可以调用update来更新数据库中的数据,而调用update()方法后的脱管对象又变成了持久对象。

下面是三种对象状态相互转换的图例
再谈saveOrUpdate方法:此方法兼具了save和update两种方法。

它根据传递的参数来选择执行其中的一种方法。

如果参数对象是瞬时态,则执行save方法,而如果参数对象是脱管态,则执行update方法。

最终都是把传递的参数对象转成持久态。

如何判
断对象的状态?主要依据是看:实体对象id(或者version)取值与实体配置文件中<id>元素的unsaved-value属性值的匹配情况。

只要满足下面的任一情况则可以说明对象处在瞬时态:情况一,实体对象(持久化对象)的id取值为null形式(比如int型为0,字串为null)。

情况二,实体对象(持久化对象)的id取值与预设的unsaved-value属性值不同。

情况三,实体对象(持久化对象)的具有的versionn属性,并且为null。

情况四,实体对象(持久化对象)的version取值与预设的unsaved-value属性值不同。

五、完善工具类及HQL QBC初步相关
1.无聊的讨论:
在前面我们写了一个工具类:HibernateUtil。

其实我们还可以把CRUD操作封装到这个工具类中,并把它们都做成静态的,这样这个工具类就可以直接调用了。

但是这样的操作对查询数据可能不是很好,因为它的查询方式很多,除非我们一一考虑这些可能涉及到查询方式,并能以重载的形式进行统一管理。

其实我也试想过把这此数据库操作方法进行
二次封装,在工具类写成如下形式:
public void operate(int i ){
if(i==1){ 调用更新方法,执行查询操作}
if(i==2){ 调用删除方法,执行查询操作}
if(i==3){ 调用插入方法,执行查询操作}
if(i==4){查询?可指定一个惯用的查询方法,但返回值如何处理,所以建议不在此处写查询,可再写一个查询的统一操作方法来总括所有的查询方法}
}
2.HQL的作用概述
数据库的操作,难点主要集中在查询操作中,而HQL就是专门用来为查询服务的。

3.HQL应用的步骤:
假定我们已有一个Session对象s
>>步骤一,获得Query对象:Query query=s.createQuery(“HQL SELECT Sentence”); >>步骤二,为参数赋值:query.setXXX();
>>步骤三,获得List对象:LIST list=query.list(); 说明,除了此方法外,Query接口还有一个常用的方法uniqueResult,如果明确查询的结果只有一个,便选择使用此方法。

如果查询结果有多个使用此方法会报异常。

>>步骤四,遍历查询结果:即遍历上面list对象。

关于步骤二为参数赋值的问题:比如步骤一中的“HQL Sentence”内容为:from User u where =? and u.password=? and ...,如果这里的?较少可以setXXX(0,”...”); setXXX(1,”...”); 但是如果?较多,就容易把这些设置写错,所以可以采取命令参数的方式来决定后面的setXXX的内容。

比如:from User u where =:uname and u.password=:upass and ... ,这样后面就可以写setXXX(“uname”,”...”); 4.一个细节问题:
在前面我们的实体类为User类,而在实体配置文件中<class name="User">意为它所关联的表为user表(没有指定名称table),但如果是oracle数据库,我们知道它本身就有一张user表,这样就产生了冲突,如何解决这种冲突?一种方法是设定table属性为新的名字(首选方法),另一种方法是加`(数字1前的那个符号),即这样<class name="User" table="`user`">写,这样我们的表还是user表。

同样如果属性名与数据库中的关键字产生这种冲突,也可以按此方法解决。

5.分页技术:
query.setFirstResult(200);query.setMaxReslut(10);这两句的意思是符合要求的语句有很多条,我们从第200条取,取出10条。

我们知道每种数据库的分页语句是不同的,而Hibernate底层判断使用哪种分页语句就是参照前面配置文件的方言属性。

6.QBC条件查询:
与它相关的是Criteria Interface,Criterion Interface,Expressson Class。

其实它的操作和HQL很相似。

同样我们假定已有一个Session对象s.
>>步骤一,获得Criteria对象:Criteria criteria = s.createCriteria(User.class);
>>步骤二,封装查询条件为一个Criterion对象:Criterion cr = Expression.eq("name", "new name"); (说明Expression继续于org.hibernate.criterion.Restrictions类),所以也可以这样写:Criterion cr=Restrictions.eq("name","new name"); Restrictions 类中的封装查询条件的方法都有两个参数:前一个参数是指创建Criteria对象时所使用的参数的属性名,后一个是要与属性名比较的值。

比如这里是指User类的name属性是否与“new name”相等
>>步骤三,获得带查询条件的Criteria对象:criteria.add(cr); 执行此步才使这个对象具有一个条件限制的查询操作。

>>步骤四,获得List对象以遍历:List clist = criteria.list(); 补充说明:也可以直接返回一个User对象:User user=(User) criteria.uniqueResult();
特别说明:Criteria对象也具有分页的功能,方式是和上面Query一样。

六、基本应用实例:Dao设计
1.总体设计:设计User对象及相关实体配置文件,工具类(得到一个Session对象),UserDao接口(实现此接口即以操作数据库),编写主配置文件,编写测试类。

2.UserDao的设计,最初我想打算设计成通用Object的操作,后来发现它的Session对象操作都要传递一个对象,就设计成如下形式。

内容如下:
package com.asm.dao;
import er;
public interface UserDao {
public void saveUser(User user);
public User queryById(int id);
public User queryByName(String name);
public void update(User user);
public void delete(User user);
}
按此设计,意思是此类专门针对User对象的数据库操作,传递User对象,所以后面它的实现类的query相关方法可以直接user = (User) s.get(User.class, name);写name为传递的参数,而我们知道操作的是User对象,所以直接可以User.class。

值得一提的是,在JDBC操作中,delete,传递id这种值就可以实现删除,而Hibernate的删除操作,必须传递一个对象,操作过程就是我们通过id查出这个对象,再把这个对象传递给删除方法以供删除。

而实事上也可以new一个User对象,并设定的id,然后再把这个对象传递给
删除方法。

但需要特别注意new出的对象必须完成符合我们通过id查出的对象。

3.这个实例参照前面的相关,基本可以写出。

以下几点需要注意:导包:Hibernate包,数据库包;改写配置文件;查询方法的设计;注意事务,特别是“增删改”要注意事务。

七、关联关系讨论
1.多对一关系映射:
一个部门有可以有多个员工,而一个员工只属于一个部门。

从员工角度看,很多员工会隶属一个部门。

现以实例说明,实例概要:一个部门类,只有id和部门名称两个属性。

有一个员工类,有id和员工名称及部门对象三个属性。

操作步骤如下:
>>步骤一,建立Depatment.java及实体配置文件:
package com.asm.hibernate.domain;
public class Department {
private int id ;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
----同包下的实体配置文件:Depart.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="com.asm.hibernate.domain">
<class name="Department">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
</class>
</hibernate-mapping>
以上的操作,没的什么可多言的,和前面的配置是一样的形式。

>>步骤二,Employee.java内容如下及实体配置文件
package com.asm.hibernate.domain;
public class Employee {
private int id;
private String name;
private Department depart;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
public Department getDepart() {
return depart;
}
public void setDepart(Department depart) {
this.depart = depart;
}
}
----同包下的实体配置文件:Employee.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.asm.hibernate.domain">
<class name="Employee">
<id name="id">
<generator class="native" />
</id>
<property name="name"></property>
<many-to-one name="depart" column="depart_id" />
</class>
</hibernate-mapping>
先来说这个类文件,它的一个重要属性就是Department对象,这就是它所关联的一个外键,这里我们只必须记住一点,每个实体类对应于一张表,如果一张表想关联另一张表,则只需要在这张表所对应的实体类中引入它想关联表的实体类对象。

再进行简单的配置即可。

再来看配置文件,这里主要看这个<many-to-one name="depart"
column="depart_id"></many-to-one>元素,它的name属性仍然是实体类中的属性。

column为对应表的外键。

可以留意下数据库表中的相关表。

>>修改主配置文件,增加以下内容以便找到相应的实体配置文件。

<mapping resource="com/dep/emp/Employee.hbm.xml"/>
<mapping resource="com/dep/emp/Depart.hbm.xml"/>
>>步骤四,编写测试类。

类中省略导入包的内容。

package com.asm.hibernate.test;
public class ManyToOneTest {
public static void main(String[] args) {
add();
}
static void add() {
Session s = null;
Transaction tx = null;
try {
Department depart = new Department();
depart.setName("departName");
Employee emp = new Employee();
emp.setName("empName");
emp.setDepart(depart);
s = HibernateUtil.getSession();
tx = s.beginTransaction();
s.save(depart);
s.save(emp);
// 交换以上两句的位置,看Hibernate执行的sql语句。

会再增加一条更新操作。

mit();
} finally {
if (s != null)
s.close();
}
}
}
说明:以前插入新的记录,都要传递一个实体对象,而这里没有这么做,原因是为了体现出一个插入记录的顺序问题,仔细观察add()方法,发现先保存的是Department对象,再保存的是Employee对象,原因是什么?这里略作说明,我们知道此项目设计的是让Employee表来关联Department表,而要想关联此表,必须保证此表已进行存储,这里暂时这样理解,也可以试试颠倒save方法的顺序,或是不保存depart来看看效果,这样也许有助理解。

简要说明,以上提到的尝试性操作:颠倒顺序,可以通过,只是增加了一条更新操作;不保存dep则不能通过,原因是此实体对象没有保存;再测试,如果注释掉
“depart.setDname("deptName");”后面按正常顺序执行,发现是能正确执行的。

只是在数据库的employee表中depart_id字段为null,如果我们在前面设置<many-to-one name="depart" column="depart_id">中增加:not-null="true"这个属性,再来执行将会报“不能为空的错误”。

通过增加这个属性,可以让我们更好理解如何建立两个对象的关联。

>>步骤五,再探查询方法。

接上面,在测试类中增加一个查询方法,内容如下:static Employee query(int empId) {
Session s = null;
try {
s = HibernateUtil.getSession();
Employee emp = (Employee) s.get(Employee.class, empId);
System.out.println("Department Name:" +
emp.getDepart().getName());
return emp;
} finally {
if (s != null)
s.close();
}
}
随后再在主方法中增加如下内容:便可以测试结果:
query(1);
对结果的说明分析:如果在以往的JDBC操作中,我们想得到这个部门的信息,需要查两次才能得到,这里的Hibernate就实现了这一优化,如果我们开启了控制台的数据库显示功能(主配置文件中开启,前面已提到),便可以查看下数据库的执行操作,并切实感受到这里实际执行了两步查询操作,在以后的操作中,建议开启此属性,以便切实体会数据库操作。

>>步骤六,增加一个新的查询方法query2,内容如下,注意和query区别:static Employee query2(int empId) {
Session s = null;
try {
s = HibernateUtil.getSession();
Employee emp = (Employee) s.get(Employee.class, empId);
Hibernate.initialize(emp.getDepart());
//上一句作用后面会作说明,这里略作了解
return emp;
} finally {
if (s != null)
s.close();
}
}
在main方法中增加如下内容进行测试:
Employee emp = query2(1);
System.out.println(emp.getDepart().getName());
2.一对多关系映射:
上面提到的多个员工对应于一个部门,是多对一的关系,如果一个部门有多个员工,则用“一对多”的关系来表示这个关系,现接上例继续,以实现一对多的关系映射。

具体操作步骤如下:
>>步骤一,在Department.java中增加如下内容:private Set<Employee> emps; 及相应的get/set方法。

>>步骤二,修改Department的实体配置文件。

在class元素下增加如下内容:
<set name="emps">
<key column="depart_id"></key>
<one-to-many class="Employee"/>
</set>
说明:<set>元素同样是指定一个属性,只不过是指定一个特殊的属性,key中的column 为映射文件的外键,这里是指Employee.java相关的实体对象的外键。

<one-to-many class="Employee"/>中的class表示关联的外键为Employee对象,也即Set中泛型机制指定的类。

>>步骤三,修改主配置文件,关联上面的实体配置文件。

>>步骤四,编写测试类,OneToManyTest.java 内容(省略导入的包)如下:package com.asm.hibernate.test;
public class OneToManyTest {
public static void main(String[] args) {。

相关文档
最新文档