收藏 分销(赏)

2023年Java相关课程系列笔记之十四Hibernate学习笔记.doc

上传人:二*** 文档编号:4711277 上传时间:2024-10-10 格式:DOC 页数:73 大小:1.05MB 下载积分:5 金币
下载 相关 举报
2023年Java相关课程系列笔记之十四Hibernate学习笔记.doc_第1页
第1页 / 共73页
本文档共73页,全文阅读请下载到手机保存,查看更方便
资源描述
Hibernate学习笔记 Java相关课程系列笔记之十四 笔记内容说明 Hibernate(梁建全老师主讲,占笔记内容100%); 目 录 一、 Hibernate的概述 1 1.1 Hibernate框架的作用 1 1.2 Hibernate访问数据库的优点 1 1.3 JDBC访问数据库的缺陷 1 1.4 Hibernate的设计思想 1 二、 Hibernate的基本使用 2 2.1 Hibernate的重要结构 2 2.2 Hibernate重要的API 2 2.3 Hibernate使用环节 2 2.4 HQL语句(简要介绍) 6 三、 数据映射类型 7 3.1映射类型的作用 7 3.2 type映射类型的两种写法 7 四、 Hibernate主键生成方式 8 4.1五种生成方式 8 五、 Hibernate基本特性 9 5.1对象持久性 9 5.2处在持久状态的对象具有的特点 9 5.3三种状态下的对象的转换 9 5.4批量操作:注意及时清除缓存 9 5.5案例:三种状态下的对象使用 10 5.6一级缓存机制(默认启动) 10 5.7一级缓存的好处 10 5.8管理一级缓存的方法 10 5.9延迟加载机制 11 5.10具有延迟加载机制的操作 11 5.11常犯的错误 12 5.12延迟加载的原理 12 5.13 Session的get和load方法的区别 12 5.14延迟加载的好处 12 5.15案例:测试延迟加载 12 5.16案例:重构NetCTOSS资费管理模块 13 5.17 Java Web程序中如何用延迟加载操作(OpenSessionInView) 15 六、 关联映射 18 6.1一对多关系one-to-many 18 6.2多对一关系many-to-one 19 6.3多对多关联映射many-to-many 19 6.4关联操作(查询join fetch/级联cascade) 21 6.5继承关系映射 24 七、 Hibernate查询方法 27 7.1 HQL查询 27 7.2 HQL和SQL的相同点 27 7.3 HQL和SQL的不同点 27 7.4 HQL典型案例 27 7.5 Criteria查询 30 7.6 Native SQL原生SQL查询 31 八、 Hibernate高级特性 32 8.1二级缓存 32 8.2二级缓存启动方法及测试 32 8.3二级缓存管理方法 33 8.4二级缓存的使用环境 33 8.5查询缓存 33 8.6查询缓存启动方法及测试 33 8.7查询缓存的使用环境 33 九、 Hibernate锁机制 34 9.1悲观锁 34 9.2悲观锁的实现原理 34 9.3悲观锁使用环节及测试 34 9.4乐观锁 35 9.5乐观锁的实现原理 35 9.6乐观锁使用环节及测试 35 十、 其他注意事项 36 10.1源码服务器管理工具 36 10.2运用MyEclipse根据数据表自动生成实体类、hbm.xml 36 10.3根据实体类和hbm.xml生成数据表 37 10.4 Hibernate中分页查询使用join fatch的缺陷 37 10.5 Hibernate的子查询映射 38 一、 Hibernate的概述 1.1 Hibernate框架的作用 Hibernate框架是一个数据访问框架(也叫持久层框架,可将实体对象变成持久对象,详见第5章)。通过Hibernate框架可以对数据库进行增删改查操作,为业务层构建一个持久层。可以使用它替代以前的JDBC访问数据。 1.2 Hibernate访问数据库的优点 1)简朴,可以简化数据库操作代码。 2)Hibernate可以自动生成SQL,可以将ResultSet中的记录和实体类自动的映射(转化)。 3)Hibernate不和数据库关联,是一种通用的数据库框架(支持30多种数据库),可以方便数据库移植。任何数据库都可以执行它的API。由于Hibernate的API中是不涉及SQL语句的,它会根据Hibernate的配置文献,自动生成相应数据库的SQL语句。 1.3 JDBC访问数据库的缺陷 1)需要编写大量的复杂的SQL语句、表字段多时SQL也繁琐、设立各个问号值。 2)需要编写实体对象和记录之间的代码,较为繁琐。 3)数据库移植时需要修改大量的SQL语句。 1.4 Hibernate的设计思想 Hibernate是基于ORM(Object Relation Mapping)思想设计的,称为对象关系映射。负责Java对象和数据库表数据之间的映射。 Hibernate是一款主流的ORM工具,尚有其他很多ORM工具,如:MyBatis(以前叫iBatis)、JPA。Hibernate功能比MyBatis强大些,属于全自动类型,MyBatis属于半自动。但全自动会有些不可控因素,因此有些公司会用MyBatis。 ORM工具在完毕Java对象和数据库之间的映射后: 1)在查询时,直接运用工具取出“对象”(不管是查询一条记录还是多条记录,取出的都是一个个对象,我们不用再去转化实体了)。 2)在增删改操作时,直接运用工具将“对象”更新到数据库表中(我们不用再去把对象转成数据了)。 3)中间的SQL+JDBC细节,都被封装在了工具底层,不需要程序员参与。 u 注意事项: v Java程序想访问数据库,只能通过JDBC的方式,而Hibernate框架也就是基于ORM思想对JDBC的封装。 v Hibernate是以“对象”为单位进行数据库的操作。 二、 Hibernate的基本使用 2.1 Hibernate的重要结构 1) hibernate.cfg.xml(仅1个):Hibernate的主配置文献,重要定义数据连接参数和框架设立参数。 u 注意事项:就是个xml文献,只是名字比较奇葩! 2) Entity实体类(n个,一个表一个):重要用于封装数据库数据。 3)hbm.xml映射文献(n个):重要描述实体类和数据表之间的映射信息。描述表与类,字段与属性的相应关系。 u 注意事项:hbm.xml是个后缀,如:命名可写Cost.hbm.xml。 2.2 Hibernate重要的API 1)Configuration:用于加载hibernate.cfg.xml配置信息。用于创建SessionFactory。 2)SessionFactory:存储了hbm.xml中描述的信息,内置了一些预编译的SQL,可以创建Session对象。 3)Session:负责对数据表执行增删改查操作。表达Java程序与数据库的一次连接会话,是对以前的Connection对象的封装。和JSP中的session不是一回事,就是名字同样而已。 4)Query:负责对数据表执行特殊查询操作。 5)Transaction:负责Hibernate操作的事务管理。默认情况下Hibernate事务关闭了自动提交功能,需要显式的追加事务管理(如调用Transaction对象中的commit();提交事务)! u 注意事项: v 这些API都是在Hibernate包下的,导包别导错! v 第一次访问数据库比较慢,比较耗资源,由于加载的信息多。 2.3 Hibernate使用环节 step1:建立数据库表。 step2:建立Java工程(Web工程也可),引入Hibernate开发包和数据库驱动包。必须引入的包:hibernate3.jar、cglib.jar、dom4j.jar、commons-collections.jar、commons-logging.jar…等 step3:添加hibernate.cfg.xml配置文献,文献内容如下: <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" ""> <hibernate-configuration> <session-factory> <property name="dialect"><!-- 指定方言,决定Hibernate生成哪种SQL --> org.hibernate.dialect.OracleDialect<!-- 不知道数据库版本就写OracleDialect --> </property><!-- 可在hibernate3.jar中org.hibernate.dialect包下查看名字 --> <property name="connection.url"> jdbc:oracle:thin:@localhost:1521:dbchang </property> <property name="connection.username">system</property> <property name="connection.password">chang</property> <property name="connection.driver_class"> oracle.jdbc.driver.OracleDriver </property> <!-- 框架参数,将hibernate底层执行的SQL语句从控制台显示 --> <property name="show_sql">true</property> <!-- 格式化显示的SQL --> <property name="format_sql">true</property> <!-- 指定映射描述文献 --> <mapping resource="org/tarena/entity/Cost.hbm.xml" /> </session-factory> </hibernate-configuration> u 注意事项:应当放在源文献的src目录下,默认为hibernate.cfg.xml。文献内容是Hibernate工作时必须用到的基础信息。 step4:编写Entity实体类(也叫POJO类),例如:资费实体类Cost private Integer id; //资费 ID private String feeName; //资费名称 private Integer baseDuration; //基本时长 private Float baseCost; //基本定费 private Float unitCost; //单位费用 private String status; //0:开通;1:暂停; private String descr; //资费信息说明 private Date createTime; //创建日期 private Date startTime; //启用日期 private String costType; //资费类型 ……getter/setter方法 u 注意事项:POJO类表达普通类(Plain Ordinary Old Object),没有格式的类,只有属性和相应的getter/setter方法,而没有任何业务逻辑方法的类。这种类最多再加入equals()、hashCode()、toString()等重写父类Object的方法。不承担任何实现业务逻辑的责任。 step5:编写hbm.xml映射(文献)描述信息:映射文献用于指明POJO类和表之间的映射关系(xx属性相应xx字段),一个类相应一个映射文献。例如:Cost.hbm.xml内容如下: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" ""> <!-- 定义COST_CHANG表和Cost类型之间的映射信息 --> <hibernate-mapping><!-- <hibernate-mapping package="包名写这也行"> --> <!-- name:包名.类名,指定是哪个类;table:数据库中哪个表;catalog:对Oracle而言为哪个数据库,对MySQl而言为某个用户(MySQl是在用户下建表,Oracle是在库中建表), 不写也行(若用工具则会自动生成)。例如,select * from cost_chang则会在hibernate.cfg配置文献中定义的库(或用户)下去找表。若写了则为select * from system.cost_chang --> <class name="org.tarena.entity.Cost" table="COST_CHANG" catalog="system"> <!-- <id></id>表白此为主键列,且必须写否则xml报错,主键映射 --> <id name="id" type="java.lang.Integer"> <column name="ID" /><!-- 或双标签<column name="ID"></column> --> <!-- 指定主键值生成方式,采用序列方式生成主键,仅对添加操作有效--> <generator class="sequence"> <param name="sequence">COST_SEQ_CHANG</param> <!--指定序列名--> </generator> </id> <property name="name" type="java.lang.String"><!-- 以下为非主键映射 --> <column name="NAME" /><!--可有length、not-null属性,如:length="20" --> </property> <property name="baseDuration" type="java.lang.Integer"><!-- 映射顺序没关系 --> <column name="BASE_DURATION" /> </property> <property name="baseCost" type="java.lang.Float"><!-- 类型要和实体定义的相同 --> <column name="BASE_COST" /> </property> <property name="startTime" type="java.sql.Date"><!--列名写错则报错读不到实体--> <column name="STARTIME" /><!--junit测试右键点Copy Trace查看错误列--> </property> <!--也可写成<property name=" " type=" " column=" "></property> ,主键列同理!--> …………其他省略………… </class> </hibernate-mapping> u 注意事项: v 映射文献默认与POJO类放在一起;命名规则为:类名.hbm.xml。 v hbm.xml中已写出的属性与字段的映射要一一相应,若表中没有某个字段,却写了映射关系,则报错:找不到实体类。 step6:运用Hibernate API实现DAO 1) 新建HibernateUtil类,用于封装创建Session的方法。如下:每个用户会相应一个Session,但是SessionFactory是共享的。 public class HibernateUtil { private static SessionFactory sf; static{//不用每次都加载配置信息,所以放static块中,否则每次都加载会花费资源 Configuration conf=new Configuration();//加载主配置hibernate.cfg.xml conf.configure("/hibernate.cfg.xml"); sf=conf.buildSessionFactory();//获取SessionFactory } public static Session getSession(){//获取Session Session session =sf.openSession(); return session; } } 2) 新建CostDAO接口 public Cost findById(int id); public void save(Cost cost); public void delete(int id); public void update(Cost cost); public List<Cost> findAll(); 3) 新建CostDAOImpl类,用于实现CostDAO接口 public class CostDAOImpl implements CostDAO { private Session session; public CostDAOImpl () {//不想老写获得session的方法,就写在构造器中 session=HibernateUtil.getSession(); } /** get方法执行查询,按主键当条件查询,如何判断是主键,是根据写的描述文献来定,get方法就是findById,就是按主键去查,需指定:操作哪个类和id(主键)条件值即可,其他条件查询做不了 */ public Cost findById(int id) { //Session session=HibernateUtil.getSession(); Cost cost=(Cost)session.get(Cost.class,id); session.close(); return cost; } /** save方法执行增长操作,注意1:获取事务并启动,增删改要注意,查询可以不管事务,由于没对数据库进行修改;注意2:主键值根据hbm.xml中的<generator>定义生成,执行后,会先获取序列值,再去做insert操作。 即先:select COST_SEQ_CHANG.nextval from dual; 然后:insert into …… */ public void save(Cost cost) { //Session session=HibernateUtil.getSession(); Transaction tx=session.beginTransaction();//打开事务 session.save(cost); mit();//提交事务 session.close();//释放 } /** delete方法执行删除操作,由于Hibernate以“对象”为单位进行数据库操作,所以这里要传进去一个对象,虽然是个对象,但还是按主键做条件删除,只要把主键值设立上就行,其他非主键值不用管。也可先通过id查再删 */ public void delete(int id) { //Session session=HibernateUtil.getSession(); Transaction tx=session.beginTransaction(); Cost cost=new Cost(); cost.setId(id); session.delete(cost); mit(); session.close(); } /** update方法执行修改操作, */ public void update(Cost cost) { //Session session=HibernateUtil.getSession(); Transaction tx=session.beginTransaction(); session.update(cost);//将cost对象更新到数据库 mit(); session.close(); } /** 特殊查询,SQL语句:String sql="select * from COST_CHANG"; HQL语句:String hql="from Cost"; (Hibernate Query Language)是面向对象的查询语句。 from后写映射的类名,它是Hibernate中特有的查询语句,根据映射的类去查询。 */ public List<Cost> findAll() { //Session session=HibernateUtil.getSession(); String hql="from Cost";//HQL语句 Query query=session.createQuery(hql); List<Cost> list=query.list();//执行查询,返回List集合 session.close(); return list; } } 4) 新建TestCostDAO类,使用junit测试 @Test public void testFindById(){//当get方法没有记录时,返回null CostDAO costDao = new CostDAOImpl(); Cost cost = costDao.findById(1); System.out.println(cost.getName());System.out.println(cost.getBaseDuration()); System.out.println(cost.getBaseCost()); System.out.println(cost.getUnitCost()); System.out.println(cost.getDescr()); } @Test public void testSave(){//id主键列由Hibernate管理,这里不用设立 Cost cost=new Cost(); cost.setName("2023计时"); cost.setUnitCost(0.8f); cost.setDescr("2023-08-09计时,0.8元/小时。"); cost.setStatus("0"); cost.setCreaTime(new Date(System.currentTimeMillis())); CostDAO costDao = new CostDAOImpl(); costDao.save(cost); } @Test public void testUpdate(){//开通某个资费,把状态由0变为1 CostDAO costDAO=new CostDAOImpl(); /** 注意事项:更新部分字段,不能和实现类中的删除那样,做一个对象出来!否则没设立的字段将被改为空! 即不能:Cost cost=new Cost(); cost.setId(90); cost.setStatus("1"); cost.setStartTime(new Date(System.currentTimeMillis())); */ Cost cost=costDAO.findById(90);//只能先通过id找到带有所有值的对象 cost.setStatus("1");//然后再对部分字段进行更新,才干避免把其他字段更新为空 cost.setStartTime(new Date(System.currentTimeMillis())); costDAO.update(cost); } @Test public void testDelete(){ CostDAO costDAO=new CostDAOImpl(); costDAO.delete(90); } @Test public void testFindAll(){ CostDAO costDAO=new CostDAOImpl(); List<Cost> list=costDAO.findAll(); for(Cost c:list){ System.out.println(c.getName()); } } 2.4 HQL语句(简要介绍) 简要介绍见2.3节中step6中的3)特殊查询(本页最上)。具体介绍见第七章。 三、 数据映射类型 hbm.xml在描述字段和属性映射时,采用type属性来指定映射类型。 3.1映射类型的作用 重要负责实现属性和字段值之间的互相转化。 3.2 type映射类型的两种写法 1)指定Java类型,例如:java.lang.String、java.lang.Integer …,不能写成String … 2)指定Hibernate类型,例如: ①整数:byte、short、integer、long; ②浮点数:float、double; ③字符串:string; ④日期和时间:date(只解决年月日),time(只解决时分秒),timestamp(解决年月日时分秒); ⑤布尔值:true/false<-yes_no->char(1)(数据库存Y/N,显示时自动转为true/false)、 true/false<-true_false->char(1)(数据库存T/F,显示时自动转为true/false)、 true/false<-boolean->bit(数据库存1/0,显示时自动转为true/false); ⑥其他:blob(以字节为单位存储大数据)、clob(以字符为单位存储大数据)、 big_decimal、big_integer; u 注意事项:Hibernate类型都是小写!建议使用Hibernate类型。 3)所以2.3节中step5的Cost.hbm.xml内的type也可这样写: <property name="name" type="string"><column name="NAME" /></property> <property name="baseCost" type="float"><column name="BASE_COST" /></property> <property name="startTime" type="date"><column name="STARTIME" /></property> u 注意事项: v java.util.Date有年月日时分秒毫秒,但假如用date映射,则只把年月日存进数据库;java.sql.Date只有年月日。java.sql.Timestamp有年月日时分秒毫秒。 v 若在页面显示按特定格式显示则用Struts2标签: <s:date name="属性名" format="yyyy-MM-dd HH:mm:ss"/> 四、 Hibernate主键生成方式 Hibernate负责管理主键值。它提供了多种主键生成方式。 4.1五种生成方式 1)sequence:可以按指定序列生成主键值。只合用于Oracle数据库。不紧张并发量! 例如:<generator class="sequence"> <param name="sequence">序列名字</param></generator> u 注意事项:创建序列时假如不指定参数,默认从1开始,步进是1。 2)identity:按数据库自动增长机制生成主键值。一般合用于MySql、SQLServer数据库。 例如:<generator class="identity"></generator> 3) native:Hibernate会根据方言类型不同,选择不同的主键生成方式。假如是OracleDialect则会选择sequence,假如是MySQLDialect则会选择identity。 例如:<generator class="native"></generator> u 注意事项:假如是MySql数据库,<param name="sequence">序列名字</param>是不起作用的,但也不会犯错;假如是Oracle数据库,<param name="sequence">序列名字</param>就会起作用,所以一般我们会加上这句话,这样通用性更强。 4) assigned:Hibernate会放弃主键生成,采用此方法,需要在程序中指定主键值。 例如:<generator class="assigned"></generator> 5)increment:Hibernate先执行select max(id)...语句获取当前主键的最大值,执行加1操作,然后再调用insert语句插入。Oracle和MySQL都可用。但不适合并发量很大的情况! 例如:<generator class="increment"></generator> 6)uuid/hilo:uuid:按UUID算法生成一个主键值(字符串类型);hilo:按高低位算法生成一个主键值(数值类型)。 例如:<generator class="hilo"></generator> u 注意事项: v 主键一般都是自动生成的。我们一般不使用业务数据作为主键,由于业务逻辑的改变有也许会改变主键值。 v 主键生成方式是枚举类型,只能从一个有限的范围内选择,不能自定义。其中,sequence是使用序列生成主键(Oracle数据库经常使用)。 五、 Hibernate基本特性 5.1对象持久性 在Hibernate使用过程中,实体对象可以具有以下三种状态: 1) 临时状态:采用new关键字创建的对象,该对象未与Session发生关联(未调用 Session的API)。也叫临时对象。临时状态的对象会被Java的垃圾回收机制回收。 2) 持久状态:实体对象与Session发生关联(调用了Session的get、load、save、update等API)。也叫持久对象。 3) 游离状态:本来是持久状态,后来脱离了Session的管理。如:Session被关闭,对象将从持久状态变为游离状态,同时垃圾回收机制可以回收掉,不再占用缓存空间了。 5.2处在持久状态的对象具有的特点 1)对象生命期持久,垃圾回收机制不能回收。 2)对象的数据可以与数据库同步(即对象中的数据发生改变,则数据库中的数据自动同步)。由Session对象负责管理和同步。 3)对象在Session的一级缓存中存放(或者说在Session缓存中的对象都是持久对象)。 u 注意事项:Session.close();有两个作用:①关闭连接、释放资源②使对象变为游离状态,当对象的引用不存在时,对象才被回收。没被回收时,对象中的数据还在! 5.3三种状态下的对象的转换 5.4批量操作:注意及时清除缓存 Transaction tx = session.beginTransaction(); for(int i=0;i<100000;i++){ Foo foo = new Foo(); session.save(foo);//设立foo属性 if(i%50==0){//够50个对象,与数据库同步下,并清除缓存 session.flush();//同步 session.clear();//清除缓存 } } mit(); 5.5案例:三种状态下的对象使用 当持久对象数据改变后,调用session.flush()方法,会与数据库同步更新。 commit()方法,内部也调用了flush()方法,因此使用commit()方法可以省略flush()方法的调用。 @Test public void test1(){//Foo实体有id、name、salary、hireDate、marry等属性 Session session=HibernateUtil.getSession(); Transaction tx=session.beginTransaction(); Foo foo=(Foo)session.get(Foo.class, 1);//foo具有持久性 foo.setName("chang"); foo.setSalary(6000); /** 提交事务,若后面不写flush,只写提交commit,则也能执行更新操作。由于commit在内部会先调用flush,再提交事务,所以此时flush可不写 */ mit(); /** 触发同步动作,同步和提交是两回事。数据有变化才同步(更新),没变化不会更新 */ session.flush(); session.close();//关闭session释放资源 } @Test public void test2(){ Foo foo=new Foo(); foo.setName("tigger"); foo.setSalary(8000); foo.setMarry(true); foo.setHireDate(new Date(System.currentTimeMillis())); Session session=HibernateUtil.getSession(); Transaction tx=session.beginTransaction(); session.save(foo);//以上都是临时状态,此时由临时状态转为持久状态 foo.setSalary(10000);//修改foo持久对象的数据,也是更新操作,可不写update方法 mit();//同步、提交 session.close(); } @Test public void test3(){
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 通信科技 > 开发语言

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服