Hibernate学习_017_Hibernate查询语言(QL)的几点说明

在Hibernate整个查询体系中,存在以下几种查询语言:NativeSQL、HQL、EJBQL(JPQL)、QBC、QBE。他们之间的关系式NativeSQL>HQL>EJBQL(JPQL)>QBC>QBE。可以简单认为后者为前者的子集,NativeSQL功能最为强大。下面对于在Hibernate中用的查询需要注意的几点做一个总结:

第一:NativeSQL 与本地数据库有关,由于是针对具体数据库,所以不可以跨越数据库平台,但是也是功能最为强大和最为灵活的。一般在做本地报表系统的时候,会大量的使用NativeSQL。

第二:HQL,Hibernate Query Language ,这种语句在执行的时候,在系统内部会根据设置的Hibernate方言将其转化为具体的本地SQL。

第三:EJBQL(JPQL),95%以上的时候,都是使用的这个查询语言,而且可以跨越ORMapping平台。而且EJBQL是导航性质的。

第四:QL应该与导航关系相结合,共同为查询提供服务。

第五:关于分页的实现:Oracle中使用三层嵌套实现,SQL使用Limit,而在HQL中使用的setMaxResult()和setFirstResult()两个方法来实现。

第六:一个面试题:JAVA中有没有内存泄露?其实,java在语法级别是没有内存泄露的,但是在实际运用中,会存在内存泄露的情况,比如这样一个场景,在一个有上千万条数据的表中,不断分页取出数据,试想一下,每次取出一百条,如果处理完成之后,不手动的执行session.clear()清理内存,这个时候由于内存中有数据的引用,这个时候,垃圾收集器是不会主动去回收内存,这样,在不断的分页取出数据的时候,一定时间以后,内存就会被占满。还有一个问题需要说明是:为什么java打开的文件一定要手动关闭?原因是JAVA打开一个文件操作实际是调用了底层的C来完成的,然后C再去调用windows API执行相关的操作,但是虽然JAVA有内存垃圾回收机制,但是C却没有这种机制。所以,JAVA打开的文件一定要手动的去关闭。

下面就常用的QL用法做一个总结说明:

1:HQL采用面向对象的思维,直接通过类取对象:比如  Query query = session.createQuery("from Category");

2:从面向对象的角度,在1的基础上添加各种过滤条件:比如 Query q = session.createQuery("from Category c where c.name > 'c5'");

3:从面向对象的角度,在1的基础上添加排序:Query q = session.createQuery("from Category c order by c.name desc");

4:过滤重复值:Query q = session.createQuery("select distinct c from Category c order by c.name desc");

5:设定过滤条件参数(两种方式可选 ? 和 :xxx):

5.1:Query q = session.createQuery("from Category c  where c.id > :min and c.id < :max order by c.name desc").setParameter("min", 3).setParameter("max", 6);

5.2:Query q = session.createQuery("from Category c  where c.id > ? and c.id < ? order by c.name desc").setParameter(0, 3).setParameter(1, 6);

6:只选取对象中的特定列组成对象数组:

		Query q = session.createQuery("select c.id , c.name from Category c");
		List<Object[]> categories = (List<Object[]>)q.list();
7:通过对象导航实现查询:Query q = session.createQuery("from Topic t where t.category.id = 1");
8:将查询出来的值组装成VO对象:比如:Query q = session.createQuery("select new com.zxb.model.MsgInfo(m.id, m.cont, m.topic.title, m.topic.category.name) from Msg m");注意,这里的MsgInfo对象在数据库中是不存在对应表的,只是程序中用来完成特定功能的一个辅助工具类,比如VO ,DTO一般都属于这类对象。

9:表之间的链接查询:比如:Query q = session.createQuery("select t.title, c.name from Topic t join t.category c");注意,这里的t.category c不可以是Category c,因为在Topic 可能存在多个类型为Category的属性,这样写的话就不知道到底是以那个属性作为链接条件使用了。必须通过t.属性名的形式指定具体是那个属性作为链接条件。

10:UniqueResult的使用:使用的过滤条件可以是传入的一个对象。示例代码如下:

Query q = session.createQuery("from Msg m where m = :MsgToSearch "); //不重要
		Msg m = new Msg();
		m.setId(1);
		q.setParameter("MsgToSearch", m);
		Msg mResult = (Msg)q.uniqueResult();
11:在HQL中,虽然从面向对象的角度考虑,但是sql中很多特性依旧可用,比如,聚合函数,between , in 等,例如:

Query q = session.createQuery("select count(*) from Msg m");

Query q = session.createQuery("select max(m.id), min(m.id), avg(m.id), sum(m.id) from Msg m");

Query q = session.createQuery("from Msg m where m.id between 3 and 5");

Query q = session.createQuery("from Msg m where m.id in (3,4, 5)");

Query q = session.createQuery("from Topic t where t.title like '_5'");

Query q = session.createQuery("select lower(t.title)," + "upper(t.title)," +"trim(t.title)," +"concat(t.title, '***')," + "length(t.title)" + " from Topic t ");

Query q = session.createQuery("select t.title ,count(*) from Topic t group by t.title");

Query q = session.createQuery("from Topic t where exists (select m.id from Msg m where m.topic.id=t.id)") ;

12:null 、not null、 empty 、 not empty的说明,在HQL中,null 和 not null 是判断对象的非集合属性是否为空,而empty 和 not empty使用来判断对象的集合属性是否有值,即集合的长度是否是0,而不是说空与非空,概念完全不一样。

Query q = session.createQuery("from Msg m where m.cont is not null"); 判断m的cont属性是否是空值。

Query q = session.createQuery("from Topic t where t.msgs is empty");判断t这个对象的集合属性msgs的大小是否是0。

13:特别说明一个HQL语句:

Query q = session.createQuery("select current_date,current_time,current_timestamp ,t.id from Topic t");

这个hql语句中,取得的是数据库的当前日期,时间以及时间戳信息,一般我们会认为,服务器在数据库服务器中取得这些当前信息有意义吗?服务器去取得自己的这些信息不就ok了吗?但是如果说在集群环境下,这个时候,多个服务器需要通过时间信息相互协作,这个时候,有可能各个服务器的时间信息并不是一致的,这个时候就会出问题,但是如果都以数据库服务器中的时间信息为准的话,就不会存在问题。

14:命名sql: 这种方式,类似于配置文件的配置方式,先配好语句,用到的时候填充条件。比如。我们在要查询的类上加上如下配置:(目前为止:JAP还不支持@NameNativeQuery.)

@Entity
@NamedQueries({
@NamedQuery(name="topicQuery",query="from Topic t where t.id = :id")
})
/*@NamedNativeQueries({
	@NamedNativeQuery(name="topicNativeQuery", query="select * from topic limit 2, 5")
})*/
public class Topic {
	private int id;
	private String title;
	@Id
	@GeneratedValue
	public int getId() {
		return id;
	}
	public String getTitle() {
		return title;
	}
	public void setId(int id) {
		this.id = id;
	}
	public void setTitle(String title) {
		this.title = title;
	}
}
由于我们配置了一条根据ID来查询Topic类实例的命名语句,所以程序中每次我们要根据id取得topic实例的时候,我们就不需要每次都写HQL语句了。只需要取得这个命名QL语句,然后填充条件即可。如下代码所示:

@Test
	public void testNameQuery() {
		Session session = this.sessionFactory.openSession();
		session.beginTransaction();
		Query q = session.getNamedQuery("topicQuery");
		q.setParameter("id", 5);
		Topic t = (Topic)q.uniqueResult();
		System.out.println(t.getTitle());
		session.getTransaction().commit();
		session.close();
	}
15:QBE查询方式示例代码:

public void testQBE(){
		Session session = this.sessionFactory.openSession();
		session.beginTransaction();
		Topic topic = new Topic();
		topic.setTitle("T_");
		Example example = Example.create(topic).enableLike().ignoreCase();
		Criteria criteria = session.createCriteria(Topic.class)
				.add(Restrictions.ge("id", 2))
				.add(Restrictions.le("id", 9))
				.add(example);
		List<Topic> topics = (List<Topic>)criteria.list();
		for(Topic t :topics ){
			System.out.println(t.getTitle());
		}
		session.getTransaction().commit();
		session.close();
	}
16:QBC查询方式示例代码:

public void testQBC(){
		Session session = this.sessionFactory.openSession();
		session.beginTransaction();
		Criteria criteria = session.createCriteria(Topic.class)
				.add(Restrictions.gt("id", 2))
				.add(Restrictions.lt("id", 8))
				.add(Restrictions.like("title", "t_"))
				.createCriteria("category")
				.add(Restrictions.between("id",1,5));
		List<Topic> topics = (List<Topic>)criteria.list();
		for(Topic t :topics ){
			System.out.println(t.getTitle());
		}
		session.getTransaction().commit();
		session.close();
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章