ORM 对象/关系型数据库映射, ORM工具的唯一作用是:把对持久化对象的保存、删除、修改等操作,转换成对 数据库的操作。持
久化对象是一种中间媒介,应用程序只需操作持久化对象。Hibernate是ORM的一种。
Hibernate采用POJO作为持久化类,只需为POJO添加一些注解。即有:PO=POJO+持久化注解
通过注解,Hibernate可以理解持久化类和数据库表之间的对应关系,连接数据库的信息可以使用配置文件指定,
hibernate.properties
PO实例若与Session关联起来,且该实例对应到数据库记录,则该实例处于持久化状态。Session由SessionFactory工厂产生, SessionFactory对象由Configuration对象生成,Configuration对象负责生成Hibernate配置文件。hibernate.cfg.xml文件中添加 了Hibernate持久化类,实例化Configuration实例可通过加载hibernate.cfg.xml文件
持久化类的要求:
1、提供一个无参数的构造器,Hibernate用来实例化持久化类的实例
2、提供一个标志属性,通常映射到数据库表的主键字段
3、为持久化类的每个成员提供setter和getter方法
4、使用非final的类,在运行时生成代理是Hibernate的重要功能,该代理对象是持久化类的子类的实例
5、重写equals()、hashcode()方法,如果需要把持久化类的实例放入set中,则要;
持久化对象的状态:
1、瞬态:对象由new创建,尚未与Hibernate Session关联的对象,如果程序中失去了该对象的引用,则会被垃圾 回收 机制销毁
2、持久化:与指定的Hibernate Session关联,在数据库中有对应的记录,开发者不需要手动执行update
3、托管:某实例曾经处于持久化状态,但与之关联的Session被关闭后变成托管状态。托管对象的引用依然有效,对象可以被修改,
当该实例重新与Session关联后,托管期间的修改不会丢失,能够被写入数据库。这个性能使得逻辑上的长事务成为可能。
改变持久化对象的状态的方法:
1、根据主键加载持久化实体:News news=session.load(News.class,pk);
2、更新持久化实体:news.setTitle("新标题"); session.flush();
3、更新托管实体:News news=session.load(News.class,pk);
session.close();
news.setTitle("新标题");
Session secondSession=..
secondSession.update(news);//或者用merge
merge()方法可将程序对托管对象所做的修改保存到数据库,和update()的区别是,merge不会持久化给定的对象,merge方法会返回一个对象的副本--该副本处于持久化状态。
4、删除持久化实体:session.delete(news);
使用@Transient修饰不想持久化保存的属性,所有现代数据库建模理论都推荐不要使用具有实际意义的屋里主键,而是推荐使用没有
任何实际意义的逻辑主键。
使用传统的映射文件管理实体类:PO=POJO+映射文件;
Hibernate的映射关系:
cascade:指定Hibernate采用的级联策略CascadeType.ALL,指定Hibernate将所有的持久化操作都级联到关联实体
CascadeType.MERGE,.....merge操作....; PERSIST REFRESH
FetchType.EAGER:抓取实体,立即抓取关联实体
FetchType.LAZY:抓取实体时,延迟抓取关联实体,等到真正要用到关联实体时采取抓取
无连接表的N-1单向关联:多个人对应一个地址,person.java中(不管哪种,关联关系始终在多端维护)
// 定义该Person实体关联的Address实体
@ManyToOne(targetEntity=Address.class)
// 映射外键列,指定外键列的列名为address_id、不允许为空
@JoinColumn(name="address_id" , nullable=false)
@Cascade(CascadeType.ALL)
有连接表的N-1单向关联:
// 定义该Person实体关联的Address实体
@ManyToOne(targetEntity=Address.class)
// 显式使用@JoinTable映射连接表
@JoinTable(name="person_address", // 指定连接表的表名为person_address
// 指定连接表中person_id外键列,参照到当前实体对应表的主键列
joinColumns=@JoinColumn(name="person_id", referencedColumnName="person_id", unique=true),
// 指定连接表中address_id外键列,参照到当前实体的关联实体对应表的主键列
inverseJoinColumns=@JoinColumn(name="address_id", referencedColumnName="address_id"))
1-N单向关联性能低,尽量少用,要用也应该采用有连接表的
mappedBy属性用于表明该实体不管理关联关系,这段对应的表应作为主表使用,而增加了@JoinColumn注解的表变成从表,级联操作
应该是主表记录传播到从表记录
继承映射:
方案一:一个子类对应一张表。每一个子类对应的数据库表都包含了父类的信息,并且包含了自己独有的属性。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从 父类继承下来的属性映射的字段。
方案二:使用一张表表示所有继承体系下的类的属性的并集。类继承体系下会有许多个子类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。
Hibernate中的这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。
方案三:每个子类使用一张表只存储它特有的属性,然后与父类所对应的表以一对一主键关联的方式关联起来。父类、子类都对应一张数据库表。在父类对应的数据库表中,它存储 了所有记录的公共信息,实际上该父类对应的表会包含所有的记录,包括父类和子类的记录;在子类对应的数据库表中,这个表只定义了子类中所特有的属性映射的字段 。 子类对应的数据表与父类对应的数据表,通过一对一主键关联的方式关联起来。
HQL查询:每个Quary实例对应一个查询对象。使用HQL的步骤如下:
1、获取Hibernate Session对象
2、编写HQL语句
3、以HQL语句作为参数,调用Session的createQuary()方法创建查询对象
4、如果HQL语句包含参数,则调用Quary的setXxx()方法为参数赋值。
5、调用Quary对象的list()或者uniueResult()方法返回查询结果列表(持久化实体
fetch就是及时加载,与延迟加载相对
在我们查询Parent对象的时候,默认只有Parent的内容,并不包含childs的信息,如果在Parent.hbm.xml里设置lazy="false"的话
才同时取出关联的所有childs内容. 问题是我既想要hibernate默认的性能又想要临时的灵活性该怎么办? 这就是fetch的功能。我
们可以把fetch与lazy="true"的关系类比为事务当中的编程式事务与声明式事务,不太准确,但是大概是这个意思。
总之,fetch就是在代码这一层给你一个主动抓取得机会.
hibernate 中 Criteria: 即使不会SQL,也可以使用它所提供的API来进行SQL语句查询,org.hibernate.Criteria对SQL进行封装
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.gt("age", new Integer(20)));
criteria.add(Restrictions.lt("age", new Integer(40)));
List users = criteria.list();
使用Criteria进行查询时,不仅仅能组合出SQL中where子句的功能,还可以组合出如排序、统计、分组等的查询功能。