数据库:Criteria与原生SQL查询

1 Criteria查询

       

Hibernate除了提供强大的HQL查询之外,还提供了一种称为Criteria的查询方法。HQL和SQL很相似,其特点是灵活和功能丰富,但缺点是使用者必须熟悉SQL的语法,而且在组合条件查询时,常常需要拼装Where条件,还得为条件提供参数。而Criteria查询更加面向对象,和Java代码结合得更好,在组合条件查询时往往更加方便。当然,Criteria也有其缺点,其可读性不如HQL高,功能也不如HQL多。

        Hibernate官方往往更推荐使用HQL去解决问题。

1.1Criteria的使用方法。

Criteria criteria = sess.createCriteria(Category.class);     //创建持久化类的查询对象Criteria

        criteria.add(规则);                                                             //设置查询规则criterion

        List list = query.list();                                                          //获取查询结果

 1.2规则-Criterion

Criterion 是Criteria的查询条件。Criteria 提供了add(Criterion criterion)方法来添加查询条件。Criterion 接口的主要实现包括:Example 、Junction和SimpleExpression。Junction 的实际使用是它的两个子类 conjunction 和 disjunction ,分别是使用 AND 和 OR 操作符进行来联结查询条件集合。

Criterion的实例可以通过Restrictions工厂类来提供,Restrictions 提供了大量的静态方法,如 eq(等于)、 ge(大于等于)、between等来方法的创建Criterion查询条件

(SimpleExpression实例)。除此之外,Restrictions还提供了方法来创建conjunction和

disjunction实例,通过往该实例的 add(Criteria) 方法来增加查询条件形成一个查询条件集合。

Restrictions中的静态方法条件

含义

Criteria

HQL

等于

Restrictions.eq()

=

不等于

Restrictions.not(Exprission.eq())

<>

大于

Restrictions.gt()

>

大于等于

Restrictions.ge()

>=

小于

Restrictions.lt()

<

小于等于

Restrictions.le()

<=

等于空

Restrictions.isnull()

is null

非空

Restrictions.isNotNull()

is not null

模糊查询

Restrictions.like()

like

逻辑与

Restrictions.and()

and

逻辑与

Restrictions.conjunction()

and

逻辑或

Restrictions.or()

or

逻辑或

Restrictions.disjunction()

or

逻辑非

Restrictions.not()

not

等于某一个值

Restrictions.in()

in( )

不等于任一个值

Restrictions.not(Restrictions.in())

not in()

区间

Restrictions.between()

between x and y

不在区间内

Restrictions.not(Restrictions..between())

not between x and y

(1)为Criteria添加简单类型属性限制(查询条件)。

        Criteria criteria = sess.createCriteria(Movie.class);

        criteria.add(Restrictions.like("title", "%%"));

        List<Movie> list = criteria.list();

(2)为Criteria添加关联类属性限制。

        直接使用criteria的add()方法,仅能添加简单类型属性限制和对于关联类的Id属性限制。若要添加关联类的其它属性限制(如为Movie实体添加关联类Category的name属性限制,必须重新createCriteria()并把关联属性名作为参数传入,然后就可以使用关联类Category的属性作为限制条件。

        Criteria criteria = sess.createCriteria(Movie.class);

        criteria = criteria.createCriteria("category");                   //重新执行createCriteria()

        criteria.add(Restrictions.eq("name","动漫"));

        List<Movie> list = criteria.list();

        上述的效果还可以通过criteria的createAlias()方法实现,与createCriteria不同,它只是给关联实体起一个别名,使用createAlias后依然可以使用被查询对象的其它属性作为限制。

        List<Movie> list = sess.createCriteria(Movie.class)

                                                  .createAlias("category", "c")

                                                  .add(Restrictions.eq("c.name", "战争"))

                                                  .add(Restrictions.like("title", "%"))

                                                  .list();

 1.3用实体一次声明多个等于或者like规则的限制条件-Example

Example也是一种添加Criteria规则的方式,这种方式使用一个查询实体类的对象,一口气声明多个规则。Example 的创建有所不同,Example 本身提供了一个静态方法 create(Object entity),参数是一个实体对象(实际使用中一般是映射好的实体对象)来创建。然后可以设置一些过滤条件:

        Example example = Example.create(entity)

                                                           .ignoreCase()   // 忽略大小写

                                                           .enableLike(MatchMode.ANYWHERE);  //使用like

        criteria.add(example);

        List list = criteria.list()

1.4实现排序 

你可以使用Criteria的addOrder(Order order) 控制查询结果的顺序。Order对象实例可以通过Order.asc("属性名") 和Order.desc("属性名")获取。

        List cats = sess.createCriteria(Cat.class)

                                  .add( Restrictions.like("name", "F%")

                                  .addOrder( Order.asc("name") )

                                  .addOrder( Order.desc("age") )

                                  .list() ;

1.5 实现分页

Criteria对象与Query对象一样可以通过setFirstResult() 和setMaxResults()方法实现分页

1.6 投影Projection—实现聚合函数和分组

Criteria可以通过setProjection(Projection projection)方法实现聚合统计和分组。

Projection主要是让Criteria能够进行统计查询,并可以实现分组。Projection主要有   SimpleProjection和ProjectionList实现。其中 SimpleProjection 和 ProjectionList 的创建是通过内建的 Projections静态方法来完成的,如提供的avg()、count()、max()、min()、sum()可以让开发者很容易对某个字段进行统计查询。Projections的groupProperty()方法还可以对结果进行分组。

        ProjectionList projectionList = Projections.projectionList();

        Projection prjCount = Projections.count("id");

        projectionList.add(prjCount);

        projectionList.add(Projections.groupProperty("category"));

        criteria.setProjection(projectionList);

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

1.7 DetachedCriteria 

DetachedCriteria类和Criteria接口功能很类似,可以使用上述提到的方式(Criterion与Projection)设置查询条件,但两者的创建方式不同:Criteria必须由Session对象创建,而DetachedCriteria创建时不需要Session对象。因此DetachedCriteria可以在Session作用域之外构建,并添加一系列复杂条件,然后传递到具有Session环境的Dao方法中执行。DetachedCriteria的出现实现了“条件构建”和“查询执行”的分离。

public static void main(String[] args) {
		DetachedCriteria cri = DetachedCriteria.forClass(Movie.class);
		cri.add(Restrictions.eq("category.id", 1));
		List<Movie> list = get(cri);
		for(Movie m: list){
			System.out.println(m.getTitle()+","+m.getCategory().getName());
		}
	}
	static List get(DetachedCriteria cri){
		Session sess = null;
		try {
			sess = HibernateUtil.getSession();	
			return cri.getExecutableCriteria(sess).list();
		} finally {
			if(sess!=null)
				sess.close();
		}
	}

2 原生SQL操作 

2.1 原生SQL查询

虽然HQL已经足够强大,但由于不同的数据库系统对标准SQL有不同的扩展(如SQL Server的T-SQL、Oracle的PL/SQL,Hibernate中称作方言“Dialect”),因此HQL无法100%完成我们在本地SQL中可以实现的功能。而且HQL最终还是要转换到SQL执行的,这种自动转换总有不如人意的地方,过于复杂的HQL转换成SQL后,执行效率可能会较低。为此,Hibernate还保留了我们直接使用数据库本地SQL的权利,我们可以直接编写SQL语句,控制查询结果。值得注意的是,一旦使用了本地SQL,若将来为数据访问层切换另一种数据库系统时,就需要修改这些本地SQL,使之符合新的数据库方言。

(1)返回基本类型Object数组的本地SQL查询。

本地SQL查询与HQL查询的用法基本相似,不同的是SQL查询需要使用Session的createSQLQuery(String sql)方法,返回的查询对象为SQLQuery类型。

String sql = "select m.Title, c.name from Movie m inner join Category c on m.CategoryId=c.Id where c.name=:cname";

SQLQuery query = sess.createSQLQuery(sql);

query.setString("cname", "战争");

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

(2)直接返回映射实体的本地SQL查询。

我们常常希望通过本地SQL查询返回持久化实体对象,若用上述的方式,Hibernate的返回结果是基本类型的Object数组,要获取实体,还需要重新构建实体对象和设置属性。为了简化我们的工作,SQLQuery接口对象直接提供了addEntity(String alias, Class entityClass)方法,可以帮助我们直接把SQL结果填充到实体对象,返回实体对象数组和列表。

String sql = "select m.*, c.* from Movie m inner join Category c on m.CategoryId=c.Id where c.name=:cname";
SQLQuery query = sess.createSQLQuery(sql);
query.addEntity("m",Movie.class);
query.addEntity("c",Category.class);
query.setString("cname", "战争");
List<Object[]> list = query.list();
for(Object[] arr : list){
        Category c = (Category)arr[1];
        Movie m = (Movie)arr[0];
        System.out.println( c.getName() + "," + m.getTitle());
}

2.2 原生JDBC操作 

如果想更灵活的使用原生JDBC操作增删改,则可以使用Session对象提供的doWork方法,通过Work接口编写内部匿名类,我们可以调用JDBC的底层API来实现批量操作。

Session.doWork() 方法的执行方式如下所示。

Session session=HibernateUtil.openSession();
	Transaction transaction=session.beginTransaction();
	session.doWork(new Work() {
			public void execute(Connection conn) throws SQLException {
				//这里是SQL非HQL
				String sql = "delete from Movie where categoryId=?"; 
				PreparedStatement stmt = conn.prepareStatement(sql);
				stmt.setInt(1, 2);
				stmt.executeUpdate();
			}
	});
	transaction.commit();

猜你喜欢

转载自blog.csdn.net/qq_55917018/article/details/128237954
今日推荐