Hibernate使用原生SQL查询

Hibernate使用原生SQL查询

  Hibernate提供了原生的SQL语句的查询,通过createSQLQuery(String)和createNativeQuery(String),createSQLQuery(String)是Hibernate5.x之前的版本的,在Hibernate5.x和之后,都采用的是createNativeQuery(String),使用原生SQL虽然麻烦,但是一些复杂的查询明显可以使用原生SQL更加方便实现各种复杂的关联查询,这里主要记录一下原生SQL查询在开发中经常使用到的一些用法。主要参考了官方的文档:https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#sql

准备

  使用的Hibenate版本为5.4的;这里使用的数据库是MySQL,测试的数据库时sakila数据库,数据库初始化脚本: https://download.csdn.net/download/strive_or_die/11928949 ,如果需要但是没有积分,也可以在评论区留下邮箱号,看到了会直接发送到邮箱。。

普通的查询

  Hibernate会通过ResultSetMetadata来判断每个字段值的存放位置以及类型,返回一个Object[]类型的数组,其实这种结果集应用场景并不广,所以实际开发中使用起来也不方便。

//查询所有的列
List<Object[]> objList = session.createNativeQuery("select * from actor").list()
//查询指定的列
List<Object[]> list = session.createNativeQuery("select actor_id as actorId,first_name as firstName  from actor")
                    .setFirstResult(0)
                    .setMaxResults(5)
                    .list();
查询结果转为Map

  使用setResultTransformer转为Map,一般转为了Map比上面的方式要好很多了,可以通过一些反射进行转为对象。如下所示:

List<Map> mapList = session.createNativeQuery("select actor_id as actorId,first_name as firstName from actor")
                    .unwrap(NativeQueryImpl.class)
                    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP)
                    .setFirstResult(0)
                    .setMaxResults(5)
                    .list();
查询结果转为Bean对象

  使用setResultTransformer转为指定对象,如果会报Hibernate的类型和实体类的类型不匹配的错误,则需要使用addScalar指定结果列的Hibernate类型,使得两者类型匹配;例如下例中,Hibernate查出来的actorId是Short,而Entity中定义了为Integer,执行则会报错,所以添加了addScalar("actorId",IntegerType.INSTANCE)将Hibernate的类型修改为Integer

List<Actor> actors = session.createNativeQuery("select actor_id as actorId,first_name as firstName from actor")
                    .addScalar("actorId",IntegerType.INSTANCE)
                    .unwrap(NativeQueryImpl.class)
                     //将查询结果列转为指定的对象,可以是实体类,也可以是非实体类例如VO和DTO
                    .setResultTransformer(Transformers.aliasToBean(Actor.class))
                    .setFirstResult(0)
                    .setMaxResults(5)
                    .list();
标量查询

  标量查询主要用于指定查询语句返回哪些字段的值,例如下列的select * from actor通过标量查询,进行指定结果列,这样就不会将所有结果列都查询出来,只查询我们需要的结果列。

 List<Object[]> listB = session.createNativeQuery("select *  from actor")
                    .addScalar("actor_id")
                    .addScalar("first_name")
                    .setFirstResult(0)
                    .setMaxResults(5)
                    .list();
转为实体对象

a.返回一个实体对象

  这种通过addEntity的查询方式,可以将结果查询转为指定的实体类,但是有个点需要特别注意,**如果使用了实体对象,那么在查询时要将实体对象中有的属性全部在SQL语句中查询出来,否则就会报错。**报的错误如:SQLException: Column 'actor_id' not found

 List<Actor> actorList  = session.createNativeQuery("select actor_id,first_name ,last_name,last_update from actor")
                    .addEntity("com.hibernate.learn.po.Actor")
                    .setFirstResult(0)
                    .setMaxResults(5)
                    .list();

b.返回多个实体对象

  通过addEntity指定别名和实体类,添加多个Entity,查询多个实体类结果。例如下列所示:

String multiEntitySQL = "select ac.*,fi.* from actor ac " +
                    "inner join film_actor fa on ac.actor_id = fa.actor_id " +
                    "inner join  film fi on fi.film_id = fa.actor_id";
List<Object[]> multiList =  session.createSQLQuery(multiEntitySQL)
    .addEntity("ac",Actor.class)
    .addEntity("fi", Film.class)
    .setFirstResult(0)
    .setMaxResults(5)
    .list();
//多个实体,按照addEntity的顺序排列
for (Object[] multiEntity : multiList){
    System.out.println("actor :"+ ((Actor)multiEntity[0]));
    System.out.println("film :"+ ((Film)multiEntity[1]));
}

  当使用连接查询查询多个对象时,可以通过addEntity("xxx", XXX.class)方法来根据数据库表的别名来引入多个实体类,这时如果需要将查询出来的所有的对象分别存入实体类中,只需要在查询出来的对象上添加{}号即可,此时就会自动分类,{}这种方式主要用于返回多个实体对象,而且实体对象的列名可能存在相同的,那么就需要使用{},这样Hibernate就可以区分了。例如上面语句可以改为如下所示:

String multiEntitySQL = "select {ac.*},{fi.*} from actor ac " +
                    "inner join film_actor fa on ac.actor_id = fa.actor_id " +
                    "inner join  film fi on fi.film_id = fa.actor_id";
List<Object[]> multiList =  session.createSQLQuery(multiEntitySQL)
    .addEntity("ac",Actor.class)
    .addEntity("fi", Film.class)
    .setFirstResult(0)
    .setMaxResults(5)
    .list();
//多个实体,按照addEntity的顺序排列
for (Object[] multiEntity : multiList){
    System.out.println("actor :"+ ((Actor)multiEntity[0]));
    System.out.println("film :"+ ((Film)multiEntity[1]));
}
总结

  一般来说,Hibernate提供的原生SQL查询的方式,常用的就是这些了,很多使用我们使用的都是将查询结果转为实体对象,这个可以通过addEntity方式实现,还有将连接查询的结果列转为VO或者DTO,这个可以通过setResultTransformer(Transformers.aliasToBean(XXX.class))实现,对于查询结果为Object[]数组的是在是不方便处理。更多的实现可以参考Hibernate的官方文档:https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#sql

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值