码迷,mamicode.com
首页 > Web开发 > 详细

hibernate基础知识

时间:2015-08-28 00:38:44      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:

Hibernate

1.ormhibernate 

orm (object relation mapping)对象关系数据库映射 ,是面向对象编程和数据库的桥梁.当我们采用ORM框架以后,应用程序不在直接访问底层数据库,而是以面向对象的方式操作持久化对象(PO),orm将面向对象的操作转化成Sql操作

orm的映射关系:: 数据表映射类,即持久化类被映射到表中

数据表行映射对象(实例)即表的每一行是一个实例

数据表的列对应类的属性

目前流行的orm框架: JPA:官方标准

Hibernate  :最流行的

iBatis 不是纯粹的面向对象,但更加灵活,允许使用sql语句

TopLink

 

2.

为了能够操作持久化对象,必须给持久化对象类添加映射文件xxx.hbm.xml

 <hibernate-mapping package=” cn.my.domain”>

<class name=” 类名” table=” 对应的表名”>

<id name=”id”>

<generator class=”identity” /> //配置主键生成策略

</id>

//配置一般属性

<property name=”title” />

<property name= “telephone” />

</class>

</hibernate-mapping>

3,有了映射文件还不行,还要配置连接的数据库是哪一个,数据库的相关信息,需要Hibernate配置文件 默认名为 hibernate.cfg.xml

<hibernate-configuration>

<session-factory>

//数据库信息 ,数据库方言 ,自动创建表,数据库连接池

<property name=””></property>

//罗列映射文件

<mapping resource=”cn.my.domain.xxx.hbm.xml”>

</session-factory>

</hibernate-configuration>

 

4.持久化操作依赖的关键对象

configuration

sessionFactory

Session

Transaction

往数据库的插入操作

Configuration conf=new Configuration().configure();

SessionFactory sf=conf.buildSessionFactory();

Session se=sf.openSession();

Transaction tx==se.beginTransaction();

Person p=new Person();

p.setName(“tom”);

se.save(p);

tx.commit();

se.close();

sf.close();

 

 

对象的三种状态:  瞬时态:没有和session关联过的状态

持久态   和session关联起来并对应到数据库中的状态

脱管态 曾经和session关联过,session关闭,脱离了session的管理

4.数据库方言

虽然所有关系型数据库都遵循标准SQL,但不同数据库有差异的,数据库方言就是告诉hibernate底层使用哪一种数据库

5.深入理解持久化对象

 

将瞬时态转化成持久态:

save()   load()   get()

Person p=session.load( Person.class,new Integer(pk));//通过标识属性加载持久化实例,延迟加载 如果使用了延迟加载,那么在调用load方法时返回的是一个代理对象,此时并不会访问数据库,当代理对象的方法被调用的时候,才去加载数据库.

如果希望在某个对象里面创建另外一个对象的关联,而从数据库中加载这个对象时,不想让其关联的对象也加载,就可以使用延迟加载

get()方法也是根据标识属性装载持久化对象,他是立即装载

对持久化对象做的修改会自动更新到数据库,可以不执行update()方法

因此修改对象的最简单方法是get()或者load()后直接修改即可

 

脱管状态的对象要修改 需要修改完成后执行 update() updateOrSave() 或者merge()方法来保存到数据库 ,这样脱管状态又回到了持久态

updateOrSave()方法会自动判断对象是脱管态还是瞬时态,如果是脱管态执行update,如果是瞬时态执行save.

merge()方法会将数据保存到数据库,但对象没有持久化

 

 

还可以通过delete()方法删除某个实例,数据库中的信息也被删除

 

 

 

主键生成策略: native 根据底层自动选择

identity  mysql

sequence oracle 

uuid

 

6.映射文件的集合属性

用集合接口声明集合属性

 有list  用于映射list集合的属性

set

 map

 array 用于映射数组的属性

  映射集合属性时通常指定name属性,用于表面该集合属性的名称,此为还有其他属性:   table   指定保存集合属性的表名,如果不指定,默认和集合属性 的名称相同

lazy  懒加载 默认为true

cascade  是否级联

orderby  设置数据库对集合元素的排序   该属性的值是指定表的指定字段                     加上asc 或者desc

 

这些集合属性都需要保存到另一张表中,所以需要一个外键,使用<key />标签表示 这个标签有下面属性:

column 指定外键字段的列名

unique 指定外键列是否有唯一约束

对应listmap还要指定索引列

  <list-index />

 <map-key />

 

用于集合映射的元素大概包含以下几种

<element /> 集合元素是基本类型以及他的包装类 ,字符串类型 ,日期类 型使用该元素

<composite-element />集合元素是复合类型时候,使用

<one- to- many>  <many-to-many> 集合元素是其他持久化对象的引用,主    要用于进行关联关系映射

6.1 list集合的映射

list是有序的,因此持久化到数据库后必须增加一列索引列来表示集合的顺序

 

public class Person {

private List<String> schools=new ArrayList<String>();

}

 

 

 

 

Person.hbm.xml

<list name=”school” table=”school”>

<key column=”personId” />

<list-index  column=”list_order”/>

<element type=”String” column=”school_name”/>

</list>

数组属性类似于list属性

6.2 set集合属性

pivate Set<String> schools= new HashSet<String>();

<set  name=”school” table=”school”>

<key column=”personId” />

 

<element type=”String” column=”school_name”/>

</set>

 

6.3map集合属性映射

private Map<String,Float> scores= new HashMap<String,Float>();

  <map name=”scores” table=”score”>

<key column=”personId”/>

<map-key column=”subject” type=”string” />

<element column=”grade” type=”float” />

</map>

 

 

有时候不需要加载集合属性,或者只加载一部分,因此为了在初始化时候不让它加载,采用延迟加载

数组不可以使用延迟加载 ,list map性能最高,set 其次

6.4 组件属性的映射

private Name name;

component标签

 这里不作详细研究

 

也可以采用JPAannotation来代替xxx.hbm.xml文件来配置持久化对象,这里不做研究,请参考<<经典javaEE 企业应用实战>>

 

 

 

 

 

 

 

 

 

 

7.hibernate的关联映射

单向关联

双向关联

7.1单向N-1关联

通过N的一方找到1的一方使用< many-to-one>标签

 public class Person{

private Address address;

 

}

 

public class Address{}

Address不是普通的组件,而是一个持久化对象

 

<class name=”Person ” table=” person”>

<many-to-one name=”address” class=”Address”  cascade=”all” column=”address_id” />

</class>

column在这里指定的是外键

 

 

7.2单向1-1关联

只需在N-1关联的<many-to-one>增加一个属性 unique=true 即可

 

7.3单向1-N关联

public class Person{

private Set<Address>  addresses=new HashSet<Address>();

}

 

<class name=”Person” table=”person”>

<set name=”addresses” >

<key column=”personId” />

<one-to-many class=”Address”>

</set>

 

</class>

 

 

 

 

 

 

7.4单向 N-N关联

单向N-N的持久化类和1-N的代码完全相同,N-N必须使用连接表

<class name=”Person” table=”person”>

<set name=”addresses” table=”person_address”>

<key column=”personId”/>

<many-to-many class=”Address” column=”addressId”/>

</set>

</class>

 

7.5双向1-N关联

public claas Person{

private Set<Address> addresses = new HashSet<Address>();

}

 

public class Address{

private Person person;

 

}

 

<class name=”Person” table=”person”>

<set name=”addresses” >

<key column=”personId” />

<one-to-many class=”Address”>

</set>

 

</class ”>

<class name=”Address” table=”address”>

<many-to-one name=”person” class=”Person” column=”personId”/>

</class>

 

7.5双向N-N关联

 

public claas Person{

private Set<Address> addresses = new HashSet<Address>();

}

 

public class Address{

private Set<Person> persons=new HashSet<Person>();;

 

}

 

 

 

Person.hbm.xml

<class name=”Person” table=”person”>

<set name=”addresses” table=”person_address”>

<key colunm=”personId”/>

<many-to-many class=”Address” column=”addressId” />

</set>

</class>

 

Address.hbm.xml

<class name=”Address” table=”addresss”>

<set name=”persons” table=”person_address”>

<key colunm=”addressId”/>

<many-to-many class=”Person” column=”personId” />

</set>

</class>

 

7.6双向1-1关联

需要 属性设置setter getter方法

Person.hbm.xml

<one-to-one  name=”address”  property-ref=”person”>

Address.hbm.xml

 

<many-to-one  name=”person”  column=”personId” unique=”true”>

 

 

7.7组件属性包含的关联

public class Person

{

private Address address;

 

}

public class Address

{

private String addressDetail;

private Set<String> schools=new HashSet<String> ();

 

}

这里address是一个组件,不是持久化类,因此无法进行和person的映射关联,school是一个持久化类,person也是一个持久化类

 

 

<class name=”Person” table=”person”>

<component name=”address” class=”Address”>

<parent  name=”person” />

<property name=”addressDetail”/>

<set name=”schools”>

<key column=”addressId”/>

<one-to-many calss =”School”/>

</set>

</component>

</class>

 

8.继承映射

两个持久化对象存在继承关系

8.1使用subclass元素进行映射

这种映射 父类和子类的持久类实例保存到一张表中,通过辨别者列(discriminator)区分属于哪个类

 

其实class属性用来映射普通持久化类,subclass用来映射子持久化类

使用subclass进行映射,不能指定子类持久化类的字段属性为非空约束,否则会造成数据完整性冲突,但这种策略,由于所有数据保存到一张表中,无需进行多表链接查询,也无需进行union查询,因此性能较高

public class Employee extends Person{}

 

<class name=”Person” table=”person” disciriminator-value=”普通人” >

<id name=”id” column=”personId”>

<generator class=”identity” />

</id>

<discriminator column=”wawa” type=”string” />

 

<property name=”name” length=”80” />

<subclass name=” Employee” disciriminator-value=”雇员”>//使用subclass映射 Employee

...

</subclass>

...

</class>

 

8.2使用joined-subclass元素进行继承映射

该策略会将父类实例保存到父类表中,而子类实例的继承来的属性保存在父类表中,

子类特有的属性保存在子类表中

该策略无需使用辨别者列,但需要在子类表中有一个<key /> 指定共有主键

<class>

<joined-subclass  name=”Employee”>

<key column=”employeeId” />

</joined-subclass>

</class> 

子类增加的字段可以指定非空约束 ,由于要多表查询,性能有一定影响

8.3使用union-subclass 继承映射

这种策略将父类属性保存到父类表中,将子类属性保存到子类表中,不需要辨别者列名,也不需要在子类中使用<key />元素 ,这种映射比较简洁

<class name=”Person” table=”person”>

<union-subclass  name=”Employee” table=”employee”>

</union-subclass>

</class>

 

使用该方法主键生成策略不能使用identity native 

 

 

9.hibernate的批量处理

问题:如果同时处理一百万条数据,我们还用一条条更新么?答案是不用,我们采用批处理

 

共有三种 :批量插入

批量更新

批量删除

9.1批量插入

如果往数据库中插入100000条数据,那么有可能内存溢出异常,因此我们要设置一个累积器,定时将缓存中的数据刷入到数据库中

Sesseion session=HibernateUntil.currentSessioin();

Transaction tx=session.beginTransaction();

for(int i=0;i<1000000;i++)

{

User u=new User();

u.setName(“xxx” +i);

session.save(u);

if(i%20==0)

{

session.flush();

session.clear();

}

}

tx.commit();

HibernateUtil.closeSession();

此外,批量插入时最好关闭二级缓存

9.2DML风格的批量删除和批量更新

需要使用HQL语句

Sesseion session=HibernateUntil.currentSessioin();

Transaction tx=session.beginTransaction();

String hqlUpdate=”update User set name=:newName”;

int updateEntities=session.createQuery(hqlUpdate)

.serString(“newName”,”新名字”)

.excuteUpdate();//批量更新

tx.commit();

HibernateUtil.closeSession();

 

//批量删除

String hqlDelete=”delete User”

其他代码和批量更新相同

 

 

10   HQL查询

 

hibernate可以使用hql查询,也可以使用条件查询,还可以使用原生的sql查询,HQL查询是面向对象的查询

使用HQL查询的基本步骤:

1)获取 hibernate session对象

2)编写HQL语句

3)以hql语句为参数,调用session.createQuery()方法,创建queryd对象

4)如果hql语句包含参数,调用QuerysetXXX方法为参数赋值

5)调用Query对象的list()等方法,返回查询结构列表

 

10.1 hql查询的几个例子

1)  第一个查询方法

Session sess=HibernateUtil.currentSession();

Transaction tx=sess.beginTransaction();

List p1=sess.createQuery(“select disticnt p from Person p  join p.myEvents where title=:eventTitle”).setString(“eventTitle”,”很普通的事情”)//

.list();

 

for(Iterator pit=p1.iterator();pit.hasNext();)

{

Person p= (Person) pit.next();

System.out.println(p.getName());

}

tx.commit();

HibernateUtil.closeSessio();

 

 

2) 第二个查询方法

Session sess=HibernateUtil.currentSession();

Transaction tx=sess.beginTransaction();

SimpleDateFormat sdf=new SimpleDateFormat(“yyyy-MM-dd”);

Date start=sdf.parse(“2005-01-01”);

List p1=sess.createQuery(“select distinct p from Person p inner jion p.myEvents event where  event.happenDate between :firstDate and :lastDate”)//

.setDate(“firstDate”,start)

.setDate(“lastDate”,new Date())//

.list();

 

 

 

for(Iterator pit=p1.iterator();pit.hasNext();)

{

Person p= (Person) pit.next();

System.out.println(p.getName());

}

tx.commit();

HibernateUtil.closeSessio();

 

 

3) 第三个查询 属性

 

List p1=session.createQuery(“select distinct p.id ,p.name.p.age from Person p join  p.myEvents”).list();

 

for(pit=p1.iterator();pit.hasNext();)

{

Object [] objs= (Object [])pit.next();

System.out.println(Arrays.toString(objs));

}

 

 

此外Query还有两个方法

   setFirstResult(int firstResult) //返回的结果从第几条记录开始

setMaxResults( int maxResults)//返回本次查询的条数

 

10.2  from 子句

from 后面紧跟的是持久化类名

  例: from Person as p; //person类中选出全部实例

from后面可以跟多个持久化类,表示跨表链接,但是一般不这么用,因为我们可以使用隐式连接或显式连接,不用这种from的方式

 

 

10.3关联和连接

当需要多表查询时,hibernate通过关联来连接,支持两种关联连接(join) :隐式关联和显式关联

隐式连接不使用join,而是使用英文点号

 

隐式: from Person p where p.myEvent.title < :title:

显示连接使用join :   from Person p inner join p.myEvent event where event.happenDate  <:endDate

使用join可以为相关联的实体指定别名

常用的join有 内连接  inner join 简写为join 

左外连接 left outer join  简写为 left join 

右外连接 right outer join 简写为 right join 

可以使用with 关键字为显式连接指定额外的条件 

with连接的是不等条件

例 from Person p join p.myEvent event with p.id> event.id;

 

 

fetch关键字常用在懒加载时候 ,关联持久化类中的集合

from Person p join fetch p.scores  

 fetch 不能和with setFirstResult  setMaxResults 关键字一起使用

 

 

10.4HQLselect语句

select 后面如果只有一项属性或者实例 那么返回的结果就是这个属性或实例的集合

 select后面如果有多项,那么返回的集合的每个元素是数组

select p.name p from Person p;

那么集合的每一项都是一个数组[string, Person]

 默认是数组 ,也可以指定为list,则每一项都是list

select new list(p.name,p) from Person p;

 

10.5  HQL的聚集函数

 

  avg:平均数

 sum

min 

max

count 统计个数

 

10.6 多态查询 

如果Person Teacher 完成了继承映射

 那么 from Person ;不仅会查询出Person实例,还会查询出Teacher实例

 

10.7  HQL查询 where 子句

where用于筛选结果,缩小范围

如果没有为持久化实例命别名,那么可以直接使用属性 ,如果有别名,要用别名引用属性

from Person where name like’tom%’;等价于

from Person p where p.name like “tom%”;

 

where 后面支持的表达式比较多:

数学运算符

逻辑运算符 and or not 

 in not in  between  ...and ... is null  is not null is empty is not empty 

case , case... when...then...else...end

时间操作函数current_timestamp() second() 

...

 

10.8 order by子句 

按属性排序  desc asc默认是asc(升序)

 

10.9 group by 子句

 分组

 类似SQL的规则,select后面的属性要么出现在聚集函数中,要么出现在group by子句中

select cat.color, count(cat), sum(cat.weight) from Cat cat group by cat.color having cat.color in( eg.Color.TABBY,eg.Color.BLACK);

 

having 是用来对分组条件进行过滤,因此,在有group by 时后,才有having

 

10.10子查询 要使用括号

 from Cat fatcat  where fatcat.weight> ( select avg(cat.weight) from DomesticCat  cat      );

10.11命名查询

 

将查询语句放在配置文件中,这样可以解耦和

hibernate-mapping标签内的query标签可以定义HQL语句

 

<query name=”myNameQuery”>

form Person p where p.age>?

</query>

 

怎样使用这个配置的hql

Query query= session.getNamedQuery(“myNameQuery”);

 

 

 

11条件查询

 

是更具有面向对象特色的查询方式

  条件查询步骤:

1)获得hibernatesession对象

2)以session对象创建Criteria对象

3)使用Restrictions的静态方法创建查询条件 Criterion查询条件

4)向Criteria里添加Criterion查询条件

5)执行Criterialist()方法返回结果集

 

11.1例子

 

 

list l= session.createCriteria(“Student.class”)//

.add(Restrictions.gt(“studentNumber”,”20004444”))//

//如果要增加student关联类的属性限制,则需要重新createCriteria()

.createCriteria(“enrolments”)//

.add(Restrictions.gt(“semester”,2))

.list();

 

分页查询方法 setFirstResult(int firstResult)

setMaxResults(int maxResults)

add( Criteria criteria)增加条件

addOrder(Order order)增加排序规则

11.2投影 聚合 和分组  离线查询  子查询

  此处暂不讨论

 

12  SQL查询

 

SQL查询是通过SQLQuery 接口来查询的,该接口继承自Query接口,因此具有Query接口的一下方法,同时自己特有的两个方法是:addEntity()  将查询到的记录和特定的实体关联

 

addScalar() 将查询到的记录关联成标量值

SQL查询的步骤:

1)获取hibernate session对象

2)编写SQL语句

3)以sql语句为参数,调用sessioncreateSQLQuery()方法创建查询对象

4)调用addEntity()addScalar()方法将查询到的结果与标量值或者实体关联,进行标量查询或者实体查询

5)如果sql语句包含参数,还要调用setXXX()方法.设置参数

6)通过list方法返回结果集

 

12.1标量查询

最基本的SQL查询是返回一个标量(数值)列表

session.createSQLQuery(“select * from student”).list();

返回的list集合的每个元素是一个Object [] 的数组元素,系统会自己判断数组里面的类型,但是这样做会大大降低性能,因此我们用addScalar()方法指定类型

 

session.createSQLQuery(“select * from student”))//

.addScalar(“name”,”StandardBasticTypes.STRING”)//

.list();

 

该语句只是返回name的字段列表

12.2实体查询

实体查询将查询结果转换成对象

List l= session.createSQLQuery(select * form enrolment_inf where year=:year)//

.addEntity(Enrolment.class)//

.setInt(“year”,2015)//

.list();

 

 

12.3命名sql查询 调用存储过程  数据过滤

暂不讨论

 

 

13.事务控制

 

 

13.1事务的概念

 事务是最小的逻辑执行单元,要么都一起执行,要么都不执行

比如转账操作要使用事务

事务的4个特性:  ACID

原子性

一致性 

隔离性 不同事务之间互不干扰

持续性 永久的保存到数据库中

13.2 session和事务

 

session.beginTransaction() 开启事务的

 从底层看hibernate的事务石油TransactionFactory 实例产生的

由于SessionFactory 底层封装了TransactionFactory,因此无需手动操作事务工厂

SessionFactory在应用程序启动时候创建,被所有线程共享,一旦创建不会轻易关闭,知道应用程序关闭

 

session会定期被清理

如果想在视图显示层一直打开session, Spring框架提供了OpenSessionInViewFilter

使用HibernateUtil类获得的session使线程不安全的session一直处于当前线程内

HibernateUtil.currentSession()

hibernate3.1提供的方法SessionFactory.getCurrentSession()可以直接获得上下文的session

 

13.3二级缓存 

一级缓存是session级别的局部缓存,是一定开启的,当修改实体类时,修改后的数据不会立即flush到数据库,先放到缓存里面

二级缓存是SessionFactory 级别的全局缓存,默认是不开的,需要配置开启,二级缓存是对所有session起作用

session需要抓取数据时优先从二级缓存抓取

开发中使用第三方提供的开源缓存,因此要设置二级缓存的实现类

在持久类的映射文件里指定开启策略

 

一级缓存和二级缓存都是对整个实体的缓存,如果想缓存普通属性可以使用查询缓存

 

14.hibernate的事件框架和拦截器

     此处不作讨论

hibernate基础知识

标签:

原文地址:http://www.cnblogs.com/chuanqimessi/p/4765154.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!