版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、一 、第一个应用实例1搭建环境:新建一个名为HibernateDemo的java工程,并导入Hibernate的jar包,特别要注意除了导入lib下的jar包还需导入hibernate3.jar核心jar包。 由于涉及数据库操作,还应导入mysql驱动包。说明,如果使用最新的hibernate,hibernate开发的基本jar包(7个) 来源:hibernate-distribution-3.3.2.GA.zip hibernate3.jar librequired下的所有jar包2简述Hibernate的作用:ORM:Object Relational Mapping,对象关系映射。将ja
2、va程序中的对象自动持久化到关系数据库中。而Hibernate的作用好比就是在java对象与关系数据库之间的一座桥梁,它主要负责两者之间的映射。在Hibernate内部封装了JDBC技术(但只是一个轻量级的封装,因而可以让程序设计人员更方便的以面向对象的思想操纵数据库),并向外提供API接口。3建新一个名为User.java的类,即是上面所说的java对象。我们以后称这种类为实体类(或是持久化类),它的对象为实体对象(或是持久化对象)。User.java内容如下:package com.asm.hibernate.domain;import java.util.Date;public clas
3、s 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编写配
4、置文件:User.hbm.xml。它和User.java放在同一个包下。内容如下:此配置文件,是用来为User.java进行配置的,我们以后称这种文件为实体配置文件(或是持久化类映射文件) 用来关联一个java类,注意在前面的根元素下有一个package属性,这样结合这个package和class标签下所指定的类名,就共同关联映射了一个java类。 其实可以这样理解,每一个包下都有实体配置文件,而这个配置文件开始的根元素package指定了此文件所处的位置(或是说它所关联的包),根元素下可以有多个标签(查阅dtd文件),它们可以分别来关联包下的java类文件。 标签,一般建议至少有两个属性:n
5、ame属性用来关联一个java类,比如这里关联了User类;table属性用来指定这个类所对应的表文件,如果不指定,系统会自动name指定的类文件进行关联(比如上面实际是:) 标签下的子标签:l 子标签实际就是用来映射主键,下的name就是用来指java类中的id属性,而它可以有一个column属性用来指定表中的主键。同时注意在此标签下有一个标签,它是用来指定主键的生成方式。 l 子标签,就是用来指定java类的属性映射到表中的一个字段,默认下此标签没有指定column属性,即是说它会把name所关联的属性名作为字段名。 如果不想java类中的某些属性映射到表中,只要不用这个标签来关联这些属性
6、即可。l 总结:上面的的name属性都分别指定了java类,java类的属性。而table,column是用来指定表,字段名配置文件:hibernate.cfg.xml。它放在当前的项目的根目录下。内容如下:com.mysql.jdbc.Driverjdbc:mysql:/localhost:3306/testroot123456org.hibernate.dialect.MySQLDialectcreate主配置文件,完成了驱动注册,数据库连接,并关联了相应的java对象配置文件。说明:具体指定了关联的所有实体配置文件,关于它的作用可以注释掉此属性看效果。另通过create指定了根据实体配置
7、文件来自动生成表,其中包括: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 com.asm.hibernate.doma
8、in.User;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(u
9、ser);mit(); /提交事务s.close();System.out.println(done);6分析流程:首先抛开Transaction tx=s.beginTransaction()和mit(),因为它们是提交事务得。支持提交事务意味着支持数据回滚。说明,通常情况下,很多数据库都默认支持提交事务,所以加这两句代码非常必要。 下面具体谈流程:第一步:获取SessionFactory对象,它会首先构建一个Configuration对象,此对象调用可以调用configure()和configure(String resource)这两种方法:这两种方法在Confi
10、guration中的源代码如下: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( resourc
11、e );return doConfigure( stream, resource );分析这两个源代码可以知道:无参调用最终也是调用这个有参数的方法,所以我们也可以直接传参数调用。 现在的重点是读配置文件,这个配置文件我们一般放在eclipse的scr根目录下,而当eclipse编译时会自动把这个目录下的文件编译到bin目录下,而这个bin目录下是被配置成classpath环境变量,而configure方法就是在classpath环境变量下查找配置文件。 再来分析,无参调用configure方法时,默认的是传递的hibernate.cfg.xml配置文件,所以只有取名为这个的配置文件,才可以调
12、用无参的configure方法,如果是其它名字的配置文件,则调用含参的配置文件,并且这个参数名应为这个配置文件的名字。 当读取配置文件后的Configuration对象,才是一个真正意义上可操控的实例对象。 然后,再用这个对象来构建一个SessionFactory对象。 强调说明,这一步整个操作最好是放在类的静态代码块中,因为它只在该类被加载时执行一次。第二步:得到一个Session实例,以进行数据库CRUD操作第三步:实例化一个java类第四步:持久化操作第五步:后续操作:主要是关闭连接 7.实体类定义规则:Domain object(java对象)必须要有构造方法,同时建议有一个id属性,
13、为了赖加载,这个java类的声明最好不用final。8.开发流程:官方推荐:先Domain object 再mapping,最后是DB。 常用开发方式:DB开始,由工具来生成mapping和Domain object。9.总结基本步骤:环境搭建(导入相关包等) 实体类及配置文件主配置文件(完成了数据库的配置及通过设置属性创建了相应的表)得到Session测试应用。二、 优化代码1为会么要优化在前面我们已经知道,获取SessionFactory对象是一个重复的过程。因此我们可以把这个操作写成一Util类。下面我们把这一步写成工具类HibernateUtil,内容如下:package com.as
14、m.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();pub
15、lic 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
16、org.hibernate.Transaction;import com.asm.hibernate.domain.User;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 (Hiber
17、nateException 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操作的一个典型模板,只需要修改主方法中的内容即
18、可。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只是准备连接到数据库,当增加上面一句操作时表示有真
19、正的数据库操作,这时它才会去连接数据库 return user; */ finally if (s != null)s.close();以上的代码,实现了数据库的查询操作,这里的get()方法需要传递两个参数,理解传递的参数:由于Session可以管理多个数据库所对应的多个实体对象,如果只是传递id将不能正确定位表,因而必须传递这个实体对象 ,get方法才能去查找这个实体对象所对应的数据库中的表。 用这个方法得到User对象后,便可以用此对象的方法来得到相关属性(也就是数据库表中的字段) 4.load()方法,懒加载。它的特点是:只有实际操作才会被加载,且它是生成的这个User.java的子类
20、,可以从打印结果看出。也正因此,所以前面建议实例类不使用final。强调:如果是懒加载,即使数据库中查不到数据,上面的user对象永远不会为空,因为它的内部实现实际上是new了一个User(子)类对象。下面再在main方法中测试,增加语句如下:User u = getUser(1);System.out.println(id= + u.getId() + t name= + u.getName();5.控制台显示:true在总配置文件中增加这个属性将会在控制台显示数据库操作的“数据库语言”。称这个属性为数据库语言显示。三 、Session中的主要方法1保存数据:save,presist 说明:
21、这两种方法的主要区别主要体现在未开启事务时。save方法如果是没开启事务,会执行相关sql语句,随后再回滚。而presist根本就不执行这些sql语句。2删除对象:delete3更新数据:update 说明,如果数据库中没有记录将会出现异常4查找数据:get,立刻访问数据库 load,返回的是代理,不会立即访问数据库。5选择操作:saveOrUpdate,merge,根据id和version的值来确定是save还是update。saveOrUpdate方法的主要作用:可以把瞬时对象或脱管对象转成持久对象,而不需要具体判断对象是处在瞬时态或是脱管态来选择save或update来让对象变成持久态。
22、只要调用此方法就能由id和version来灵活选择是保存或更新。而merge方法一个对象后,对象仍是脱管态。5持久对象:lock,把对象变成持久对象,但不会同步对象的状态。四 、对象三种状态1瞬时(transient):数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器回收,一般是new出来的且与Session无关系的对象。2脱管-游离(detached):数据库中有数据与之对应,但当前没有Session与之关联:脱管对象状态发生改变,Hibernate不能检测到。3持久(persistent):数据库有数据与之对应,当前与Session有关联,并且相关联的Session没有关闭,事务没
23、有提交:持久对象状态发生改变时,在事务提交时会影响到数据库。理解:与Session是否关联,数据库是否有数据与之对应是判断三种对象状态的依据。比如,瞬时状态跟它们均无关;脱管,只是数据库有数据与之对应,失去了Session对它的管理;而持久与两者者有关。从过程中理解三种对象状态:结合前面的实例,当我们User user=new User()一个对象时,它表示创建一个瞬时对象,当调用save(user)方法时,这个对象成为持久对象,直到事务提交,数据库连接关闭。在这期间,如果我们user.setXXX()时,会对这个持久对象产生影响,最终它也会被提交到数据库,它的最终提交是在提交事务时。比如sa
24、ve(user)方法后,跟user.setName(new name);和user.setPassword(new password);这两句,这样它会在提交时务时,采取对数据库的更新操作,也就是说数据库连接关闭后,数据库存的是“new name”和“new password” 而如果开启了“数据库语言显示”可以发现执行两次操作:一次是save方法的插入操作,一次是setXXX后提交事务时的更新作(特别说明,持久对象在发生改变时,比如setXXX方法改变对象内容时,会在最后,即提交事务时统一进行更新操作,而并非每一次改变就执行一次更新,这样可以保证与数据库的交互更高效合理)。当执行完save方
25、法后,我们关闭数据库连接时,这时的user对象就是脱管状态,因为它在数据库有数据与之对应 而脱管状态的最好例子是当我们用get方法得到一个对象并关闭连接时 补充说明:既然我们已经知道了持久对象可以被Hibernate检测到进行更新操作,那么update是否还有用了?有,比如脱管对象就可以调用update来更新数据库中的数据,而调用update()方法后的脱管对象又变成了持久对象。 下面是三种对象状态相互转换的图例transientpersistentdetachedsava()saveOrUpdate()newdelete()get()load()find()iterate()evict()c
26、lose()clear()update()saveOrUpdate()lock()garbge()再谈saveOrUpdate方法:此方法兼具了save和update两种方法。它根据传递的参数来选择执行其中的一种方法。如果参数对象是瞬时态,则执行save方法,而如果参数对象是脱管态,则执行update方法。最终都是把传递的参数对象转成持久态。 如何判断对象的状态?主要依据是看:实体对象id(或者version)取值与实体配置文件中元素的unsaved-value属性值的匹配情况。 只要满足下面的任一情况则可以说明对象处在瞬时态:情况一,实体对象(持久化对象)的id取值为null形式(比如int
27、型为0,字串为null)。 情况二,实体对象(持久化对象)的id取值与预设的unsaved-value属性值不同。 情况三,实体对象(持久化对象)的具有的versionn属性,并且为null。 情况四,实体对象(持久化对象)的version取值与预设的unsaved-value属性值不同。五、 完善工具类及HQL QBC初步相关1无聊的讨论:在前面我们写了一个工具类:HibernateUtil。其实我们还可以把CRUD操作封装到这个工具类中,并把它们都做成静态的,这样这个工具类就可以直接调用了。但是这样的操作对查询数据可能不是很好,因为它的查询方式很多,除非我们一一考虑这些可能涉及到查询方式,
28、并能以重载的形式进行统一管理。 其实我也试想过把这此数据库操作方法进行二次封装,在工具类写成如下形式:public void operate(int i )if(i=1) 调用更新方法,执行查询操作if(i=2) 调用删除方法,执行查询操作if(i=3) 调用插入方法,执行查询操作if(i=4)查询?可指定一个惯用的查询方法,但返回值如何处理,所以建议不在此处写查询,可再写一个查询的统一操作方法来总括所有的查询方法2HQL的作用概述数据库的操作,难点主要集中在查询操作中,而HQL就是专门用来为查询服务的。3HQL应用的步骤:假定我们已有一个Session对象s步骤一,获得Query对象:Que
29、ry 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 .
30、,如果这里的?较少可以setXXX(0,”.”); setXXX(1,”.”); 但是如果?较多,就容易把这些设置写错,所以可以采取命令参数的方式来决定后面的setXXX的内容。 比如:from User u where =:uname and u.password=:upass and . ,这样后面就可以写setXXX(“uname”,”.”);4一个细节问题:在前面我们的实体类为User类,而在实体配置文件中意为它所关联的表为user表(没有指定名称table),但如果是oracle数据库,我们知道它本身就有一张user表,这样就产生了冲突,如何解决这种冲突?一种方法是设定t
31、able属性为新的名字(首选方法),另一种方法是加(数字1前的那个符号),即这样写,这样我们的表还是user表。同样如果属性名与数据库中的关键字产生这种冲突,也可以按此方法解决。5.分页技术:query.setFirstResult(200);query.setMaxReslut(10);这两句的意思是符合要求的语句有很多条,我们从第200条取,取出10条。我们知道每种数据库的分页语句是不同的,而Hibernate底层判断使用哪种分页语句就是参照前面配置文件的方言属性。6.QBC条件查询:与它相关的是Criteria Interface,Criterion Interface,Expresss
32、on 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); Restrictio
33、ns类中的封装查询条件的方法都有两个参数:前一个参数是指创建Criteria对象时所使用的参数的属性名,后一个是要与属性名比较的值。比如这里是指User类的name属性是否与“new name”相等步骤三,获得带查询条件的Criteria对象:criteria.add(cr); 执行此步才使这个对象具有一个条件限制的查询操作。步骤四,获得List对象以遍历:List clist = criteria.list(); 补充说明:也可以直接返回一个User对象:User user=(User) criteria.uniqueResult();特别说明:Criteria对象也具有分页的功能,方式是和
34、上面Query一样 。六 、基本应用实例:Dao设计1总体设计:设计User对象及相关实体配置文件,工具类(得到一个Session对象),UserDao接口(实现此接口即以操作数据库),编写主配置文件,编写测试类。2UserDao的设计,最初我想打算设计成通用Object的操作,后来发现它的Session对象操作都要传递一个对象,就设计成如下形式。内容如下:package com.asm.dao;import com.asm.domain.User;public interface UserDao public void saveUser(User user);public User quer
35、yById(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这种值就可以实现删除,而Hiberna
36、te的删除操作,必须传递一个对象,操作过程就是我们通过id查出这个对象,再把这个对象传递给删除方法以供删除。而实事上也可以new一个User对象,并设定的id,然后再把这个对象传递给删除方法。 但需要特别注意new出的对象必须完成符合我们通过id查出的对象。3这个实例参照前面的相关,基本可以写出。以下几点需要注意:导包:Hibernate包,数据库包;改写配置文件;查询方法的设计;注意事务,特别是“增删改”要注意事务。七 、关联关系讨论1多对一关系映射:一个部门有可以有多个员工,而一个员工只属于一个部门。从员工角度看,很多员工会隶属一个部门。现以实例说明,实例概要:一个部门类,只有id和部门名
37、称两个属性。有一个员工类,有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) this
38、.name = name;-同包下的实体配置文件:Depart.hbm.xml以上的操作,没的什么可多言的,和前面的配置是一样的形式。步骤二,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
39、() return name;public void setName(String name) = name;public Department getDepart() return depart;public void setDepart(Department depart) this.depart = depart;-同包下的实体配置文件:Employee.hbm.xml先来说这个类文件,它的一个重要属性就是Department对象,这就是它所关联的一个外键,这里我们只必须记住一点,每个实体类对应于一张表,如果一张表想关联另一张表,则只需要在这张表所对应的实体类中引入它
40、想关联表的实体类对象。再进行简单的配置即可。再来看配置文件,这里主要看这个元素,它的name属性仍然是实体类中的属性。column为对应表的外键。可以留意下数据库表中的相关表。修改主配置文件,增加以下内容以便找到相应的实体配置文件。 步骤四,编写测试类。类中省略导入包的内容。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
41、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.
42、close();说明:以前插入新的记录,都要传递一个实体对象,而这里没有这么做,原因是为了体现出一个插入记录的顺序问题,仔细观察add()方法,发现先保存的是Department对象,再保存的是Employee对象,原因是什么?这里略作说明,我们知道此项目设计的是让Employee表来关联Department表,而要想关联此表,必须保证此表已进行存储,这里暂时这样理解,也可以试试颠倒save方法的顺序,或是不保存depart来看看效果,这样也许有助理解。简要说明,以上提到的尝试性操作:颠倒顺序,可以通过,只是增加了一条更新操作;不保存dep则不能通过,原因是此实体对象没有保存;再测试,如果注释
43、掉“depart.setDname(deptName);”后面按正常顺序执行,发现是能正确执行的。只是在数据库的employee表中depart_id字段为null,如果我们在前面设置中增加:not-null=true这个属性,再来执行将会报“不能为空的错误”。通过增加这个属性,可以让我们更好理解如何建立两个对象的关联。步骤五,再探查询方法。接上面,在测试类中增加一个查询方法,内容如下:static Employee query(int empId) Session s = null;try s = HibernateUtil.getSession();Employee emp = (Empl
44、oyee) 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就实现了这一优化,如果我们开启了控制台的数据库显示功能(主配置文件中开启,前面已提到),便可以查看下数据库的执行操作,并切实感受到这
45、里实际执行了两步查询操作,在以后的操作中,建议开启此属性,以便切实体会数据库操作。步骤六,增加一个新的查询方法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 (
46、s != null)s.close();在main方法中增加如下内容进行测试:Employee emp = query2(1);System.out.println(emp.getDepart().getName();2一对多关系映射:上面提到的多个员工对应于一个部门,是多对一的关系,如果一个部门有多个员工,则用“一对多”的关系来表示这个关系,现接上例继续,以实现一对多的关系映射。具体操作步骤如下:步骤一,在Department.java中增加如下内容:private Set emps; 及相应的get/set方法。步骤二,修改Department的实体配置文件。在class元素下增加如下内容:说明: 元素同样是指定一个属性,只不过是指定一个特殊的属性,key中的column为映射文件的外键,这里是指Employee.java相关的实体对象的外键。中的class表示关联的外键为Employ
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论