hibernate基础教程2

第四部分:使用hibernate操作数据

包括:Session缓存,持久化对象状态,hibernate的持久化操作,使用OID加载对象,HQL查询

Session缓存:

         Hibernate对其持久化对象实现了缓存管理,来提高系统性能,hibernate支持两级缓存管理,一级缓存是由Session提供的,是Session内置的,不能被卸载

         Hibernate的二级缓存是由SessionFactory提供的,默认是不支持的,必须明确配置。

         Session缓存的作用:

                   降低访问数据库的频率

                   保证缓存中的对象与数据库中的相关记录保持同步

持久化对象的状态:

         临时状态(Transient):刚刚用new创建,还没有被持久化,不处于Session缓存中

                   临时对象的特征:

                            不处于Session的缓存中

                            在数据库中没有对应的记录

                            进入临时状态的情况:

                                     当通过new语句刚创建了一个对象

                                     Session的delete方法会使一个对象从(持久化/ 游离)状态进入临时状态

         持久化状态(Persistent):已经被持久化,加入到Session缓存中

                   持久化对象的特征:

                            位于一个Session实例的缓存中

                            持久化对象和数据库中相关的记录对应

                            Session在清理缓存时,会根据持久对象的属性的变化来同步更新数据库

                            Session的save方法把临时对象变为持久化对象

                            Session的load或get方法返回的是持久化对象,find方法返回的List元素

                            Session的update,saveOrUpdate,lock使对象从游离状态变为持久化状态

         游离状态(Detached):已经被持久化,但不再处于Session缓存中

                   游离对象的特征:

                            不再处于Session的缓存中

                            游离对象是从持久化对象转变过来的

                            调用Session的close方法时,Session的缓存被清空,缓存中的持久化对象会变成游离对象

持久化对象:

save()://保存对象

把临时对象加入到缓存中,使之成为持久化对象

使用指定的ID生成器为持久化对象分配OID

当对象处于持久化状态,Hibernate不允许修改其OID

update()://修改对象

把游离对象加入到缓存中,使一个游离对象变成持久化对象

计划执行update SQL语句,根据对象的OID来更新对象所对象的数据

update()不能更新一个在session中已经关联的相同OID的对象

saveOrUpdate()://保存或修改对象

同时包含了save()和update()方法的功能,根据对象的状态自动执行相应的功能

若对象为临时状态,执行save()方法,若为游离状态则执行update()方法

merge()     //合并对象

直接修改表中的记录,并不影响该对象原来的状态

contains()          //判断实体对象是否与Sesison关联

可以用此方法判断对象是否处理持久化状态

evict()        //把实体对象从Session缓存中移除

clear()        //清除Session缓存中所有的持久化对象

delete()     //删除指定的对象

配置级联删除:

1. 设置cascade为“delete” 或 “all” 或 “save-update,delete”。 “all”与“save-update,delete”相同

学生和地址之间存在一对一的关系,如果希望删除学生信息时,同时删除地址信息,可以在学生这一头这样配置。

2.设置cascade=“delete-orphan”

班级和学生是一对多的关系,在班级的set元素中进行配置。更新班级对象时,检查set集合中缺少的学生对象,删除数据库中对应的学生记录。

根据OID加载对象:

get()

load()

两个方法的区别:

都是根据指定的OID从数据库中加载一个持久化状态对象

当数据库中不存在与OID相对应的记录时,get()返回一个null引用,而load()方法会抛出ObjectNotFoundException异常

load()方法可以返回一个实体的代理类实例(当class的lazy=true时),而get()方法只是直接返回实体类对象。

Hibernate查询:

         三种查询方式:

                   HQL(Hibernate QueryLanguage)检索

                   QBC(Query ByCriteria)检索

                   Native SQL检索

         注:以上三种查询方式都是通过Session对象来操作的

         HQL查询:

                   是完全面向对象的查询语句,查询功能非常强大,具备继承,多态和关联等特性

                   Hibernate使用Query接口来执行HQL语句,类似JDBC中使用的PreparedStatement

                   HQL语句不区分大小写,但实体类及其属性除外

         HQL查询步骤:

                   创建Query对象    Query query=session.createQuery(“hql”);

                   绑定动态参数

                            使用占位符?指定参数 eg:”from User u whereu.age>?”

                                     query.setInteger(0,20);

                                     参数的索引从0开始

                            使用命名参数指定参数 eg:”from User uwhere u.age>:age”

                                     query.setInteger(“age”,20);

                            每种参数类型都有两种绑定形式

                            设置时间类型:

                                     query.setTime               时分秒

query.setDate               日期

query.setTimestamp    日期+时分秒

                           设置实体属性:

                                     query.setEntity

                   执行查询/更新语句:

                  list():返回List对象,可以按索引随机访问对象

iterator():返回Iterator对象,只能按从前到后的顺序依次访问对象

uniqueResult():返回一个结果对象,一般确认结果集中只有一个符合条件的对象才使用此方法

技巧:可以使用setMaxResults()来限制个数

executeUpdate() :执行delete/update语句

HQL实体查询:

查询一个实体的信息,返回包含全部属性的实体对象的实例,也可以是一个List集合对象,其元素是实体对象的实例

如果是同一种类型的实体查询,可以省略select子句

如果实体类命名冲突,可使用完全类名形式“from com.ourchr.hib.entity.User ”

查询所有用户信息session.createQuery(“fromUser”).list();

查询年龄大于20的所有用户信息

                  session.createQuery(“fromUser u where u.age > 20”).list();

单个属性查询:

                  session.createQuery(“selectu.name from User u”).list();

返回的结果集中的对象是String类型

多属性查询:

                  session.createQuery(“selectu.name, u.password from User u”).list();

返回的结果集中是Object[]类型的数据,其长度等于属性列的个数

实体和属性混合查询:

                  session.createQuery(“selectu, u.name from User u”).list();

返回一个Object[]类型结果集,第一个元素是User对象,第二个是一个String对象

使用Query.executeUpdate()来执行操作:

示例:让所有用户的年龄加1

session.createQuery(“update Userset age = age + 1”).executeUpdate();

示例:删除所有年龄小于10的用户

                            session.createQuery(“delete User where age <10”).executeUpdate();

HQL-方法链编程:

Query接口支持方法链编程风格,它的setXXX()等方法都返回Query自身的实例,这样可直接通过“.”来调用下一个方法,从而使用程序更简洁

示例:

常规风格

Query query =session.createQuery(“from User u where u.age > ?”);

query.setInteger(0, 10);

List users = query.list();

方法链风格

List users =session.createQuery(“from User u where u.age > ?”).setInteger(0, 10).list();

第五部分:使用hibernate查询数据

         包括:分页查询,级联查询,条件查询,聚合查询,表达式

分页查询:

设置最多查询多少条记录

query.setMaxResults(n)

设置从原始结果集中取最终结果的开始下标

query.setFirstResult(n)

Eg: 查询第10到19条记录

query.setFirstResult(10).setMaxResult(10)

级联查询:

session.createQuery("from Student s left joinfetch s.clazz where s.name=:name"

注意不能使用left join Clazz con …

以下配置对HQL查询不起作用:

<set name="students" fetch="join">…

级联查询:一对一

如果StudentAddress之间存在一对的关联,则只要查询Student,系统会自动查询出对应的Address,不管是使用session.get还是query进行查询。

使用get查询时,如果希望使用连接查询,则需要配置fetch=“join”

使用query查询时,如果希望使用连接查询,则查询方式类似如下:

                    from Student s left join fetch s.address where …

级联查询:一对多

           假定ClazzStudent存在一对多关联,则查询Clazz时并不会自动查询Student

 如果希望使用get方法查询 Clazz时同时查询到Student,则有如下两种方案:

方案一:

Clazz c = (Clazz)session.get(Clazz.class, id);

c.getStudents().size();

//以上第一行代码将查询到班级信息,第二行代码将查询到班级对应的学生信息,共执行两次查询。

方案二:

在配置文件中的set元素上配置属性:fetch=“join”

这时使用get查询clazz时,将自动通过左外连接查询对应的学生信息。共执行一次查询。

使用query查询对应的班级信息时,set元素中的fetch配置将不起作用。默认情况下也不会级联查询学员信息。可以使用如下方案来实现级联查询。

方案一:

Clazz c = (Clazz)session.createQuery(“from Clazz cwhere …”).uniqueResult();

c.getStudents().size();

//以上第一行代码将查询到班级信息,第二行代码将查询到班级对应的学生信息,共执行两次查询。

方案二:

Clazz c = (Clazz)session.createQuery(“from Clazz c left join fetch c.studentswhere …”).uniqueResult();

//以上查询班级时将自动通过左外连接查询对应的学生信息。共执行一次查询

级联查询:多对多

           多对多的情况与一对多类似。可以通过配置fetch=“join”或者执行两次查询来实现。

 假设课程与教师存在多对多的关系

在教师对应的配置文件中配置fetch=“join”,可以实现通过get获取教师对象的同时获取到所有的课程。

通过query查询教师时,使用left join fetch可以在查询教师对象的同时查询到课程。

条件查询:

条件中的属性:

           一对一的情况:查询学生时希望根据学生的地址信息来查询

from Student s where s.name = :n and s.address.info= :I

注:我们可以直接使用关联的对象的属性来进行查询

一对多的情况:查询班级时希望根据学生的信息来查询

from Clazz c left join c.students s where s.name =:n

聚合查询:

支持的聚合函数

avg(...), sum(...),min(...), max(...), count(*)

 支持groupby

select s.sex, count(*)from Student s group by s.sex

表达式:

查询学生人数多于3的班级

from Clazz c where size(c.students)> 3

    or

from Clazz c where c.students.size> 3

其他问题:

多表查询

查询班级名和学生名相同的班级

select c from Clazz c, Student s where c.name = s.name

 直接查询得到对象

select new entity.Some(c.id, c.name) from Clazz c

第六部分:使用hibernate其他查询语句

包括:OBC,Example,Native Query

QBC查询:

QBC中,使用Criteria接口来查询,条件由Restrictions定义,排序则以Order指定Criteria本身只是一个查询容器,具体的查询条件通过调用Criteriaadd()方法进行添加。

Eg查询年龄大于20的所有姓wang的用户信息,并按年龄升序排序。

List users =session.createCriteria(User.class)

.add(Restrictions.like(“name”,”wang%”))

.add(Restrictions.gt(“age”,20))

.addOrder(Order.asc(“age”))

.list();

Restrictions:

用于生成Criteria接口执行数据库查询时所使用的查询条件Criterion对象,它提供了一系列的静态方法来生成各种Criterion接口的实现类对象。

Criterion restriction= Restrictions.between(“age”,10,20);

String[]  address = {“hefei”,”nanjing”};

Criteria  criteria = session.createCriteria(User.class)

.add(restriction).add(Restrictions.in(“address”, address ));

//再增加email不为空的条件

criteria.add(Restrictions.isNotNull(“email”));

Order类:用于使用Criteria设置查询时的排序规则一般只用到两个静态方法asc()、desc()。

List list = Criteria.createCriteria(User.class)

.add(Order.asc(“age”)).add(Order.asc(“name”)).list();

使用QBC级联查询:

例如,查询名称为“class1”的班级并关联查询该班级的所有学生信息。

     List<Clazz>clazz = (List<Clazz> )session.createCriteria(Clazz.class)

     .add(Restrictions.eq(“name”,”class1”))

     .setFetchMode(“students”,FetchMode.JOIN)

     .list();

使用Criteria动态获取关联实体或实体集合与HQL不同,它不会忽略映射文件中指定的获取策略。如果在配置students集合属性时加上fetch=“join”,则以下的查询也会通过外连接获取关联的Student集合:

List<Clazz> clazz= (List<Clazz> )session.createCriteria(Clazz.class)          .add(Restrictions.eq(“name”,”class1”)).list();

使用setFetchMode动态获取关联对象和集合是通过连接来实现的,这样导致返回的List中包含重复的记录。

解决方案:

1、将查询结果列表clazz进行如下转换:

Set c = newLinkedHashSet(clazz);

clazz = newArrayList(c);

使用ResultTransformer对结果过滤,使用方式如下:

List<Clazz>clazz = session.createCriteria(Clazz.class)    .add(Restrictions.eq("name",name))    .setFetchMode("students",FetchMode.JOIN).setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();

QBC查询—使用关联指定约束:

例如,查询有姓wang学生的班级:

Criteria criteria =session.createCriteria(Clazz.class)

    .createAlias("students","s")

    .add(Restrictions.like("s.name","wang", MatchMode.START))

    .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

    List<Clazz> c =criteria.list();

投影查询:

Projections类主要用于帮助Criteria接口完成数据的分组查询和统计功能。

List users =session.createCriteria(User.class)

    .setProjection(Projections.projectionList()

    .add(Projections.rowCount())

    .add(Projections.avg(“age”))

    .add(Projections.max(“age”))

    .add(Projections.min(“age”))

    .add(Projections.groupProperty(“sex”))//设置分组字段

).list();

Example查询:

Example对象提供了另一种指定查询条件的方式,只要用于创建Example对象的某属性不为空,就会成为查询条件的一部分。

Clazz cla = newClazz(); cla.setName("class1"); cla.setInfo(“info”);

cla.setId(1L);

Example e =Example.create(cla);

List<Clazz> r =session.createCriteria(Clazz.class).add(e).list();

注:上例中用一个clazz对象做为参数创建了Example,因为clazz对象中属性name和info不为null,因此查询条件中会有name=“class1”及info=“info”这二项。

Example会忽略主键属性,因此上例中设置的id值不会包含到查询条件中。

Example对象还可以指定是否在查询条件中使用like进行比较,是否忽略大小写,及指定哪些属性不包括到查询条件中。

Example example = Example.create(cat)
    .excludeZeroes()           //
排除值为0的属性
    .excludeProperty(“color”)  //不包括“color”属性
    .ignoreCase()              //比较时不区分大小写
    .enableLike();             //使用like进行比较

Native Query查询:

有时我们并不能通过HQLQBC解决一些特殊的问题,如调用存储过程,或访问数据库提供的一些特性。Hibernate允许我们直接使用sql来访问数据库。

SQLQuery query = session.createSQLQuery("select * fromClAZZ");

List<Object[]> r = query.list();

SQLQuery也可以查询出实体对象:

List<Clazz> r =

 session.createSQLQuery(“select *from ClAZZ”)

.addEntity(Clazz.class)

.list();

前提是Clazz类进行了配置,同HQL一样。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值