根据个人使用Hibernate的经验,介绍一下Hibernate的多种不同的查询和CUD操作,这些东西在日常开发中非常常用,希望对大家有所帮助。

以下示例均以两张表为例:member和userinfo,member帐号信息表外键关联userinfo用户基本信息表,主键自动生成即可

然后映射出的POJO如下:

public class Userinfo  implements Serializable{

  // primary key

private java.lang.Integer id;

// fields

private java.lang.String name;

private java.lang.String code;

private java.lang.String birthday;

private java.lang.String address;

private java.util.Date createTime;

private java.lang.Integer deleteFlag;

// collections

private java.util.Set<com.bless.model.Member> members;

//省略 getter setter

}

public class Member implements Serializable{

  // primary key

private java.lang.Integer id;

// fields

private java.lang.String loginCode;

private java.lang.String password;

private java.lang.Integer deleteFlag;

// many to one

private com.bless.model.Userinfo fkUserinfo;

//省略getter setter

}

1、Hibernate提供多种方法查询数据库数据

下面以一个最简单的查询为例:SELECT * FROM TABLE为例

1-1简单HQL语句查询

Hibernate提供了HQL查询,HQL是Hibernate推荐语句,它屏蔽了不同数据库SQL不兼容的问题,使用HQL写的查询语句在主流数据库上都能执行。

执行HQL需要创建Query对象:getSession().createQuery(hql语句);

简单HQL格式:FROM POJO 对应SQL语句:SELECT * FROM POJO对应的表名

千万注意:HQL语句中的表名和字段名不是数据库的表名和字段名,而是对应ORM映射POJO的类名和属性名!

Java代码

Query query = baseDao.getQuery("FROM Member");

List<Member> lstM = query.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

结果:一句SQL将所有结果查询出来

如果修改一下for循环的代码,查询FK的name:

Java代码

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getName());

}

结果:一句SQL查询Member表,每一次for循环又发一句SQL查询Userinfo表

总结:被查询表中如果有外键关联,在执行查询时能将外键关联字段的值查询出来,但如果想查询关联表的其它字段会另外发SQL,这个特别要注意!

1-2简单SQL语句查询

Hibernate同样支持写SQL,对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口

Java代码

SQLQuery sql = baseDao.getSQLQuery("SELECT * FROM member");

//查询出的结果放到指定POJO中

sql.addEntity(Member.class);

List<Member> lstM = sql.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

结果:一句SQL将所有结果查询出来

如果修改一下for循环的代码,查询FK的name,结果与前面使用HQL查询一样:一句SQL查询Member表,随后每一次for循环又发一句SQL查询Userinfo表

1-3Hibernate条件查询(Criteria)

HQL极为强大,但是有些人希望能够动态的使用一种面向对象API创建查询,而非在他们的Java代码中嵌入字符串。对于那部分人来说,Hibernate提供了直观的Criteria查询API。

获取Hibernate的Criteria对象方法:getSession().createCriteria(Class对象);

Java代码

Criteria crit = baseDao.getCriteria(Member.class);

List<Member> lstM = crit.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

其实上面这种方式就是发了一句SQL:SELECT * FROM member

结果:一句SQL将所有结果查询出来

如果修改一下for循环的代码,查询FK的name,结果与前面情况一样

2、在简单的select from table基础上,加上分页和排序

以此为例:查询第11条~20条数据,按照ID降序排列

2-1使用HQL

Java代码

Query query = baseDao.getQuery("FROM Member m ORDER BY m.id DESC");

query.setFirstResult(10);

query.setMaxResults(10);

List<Member> lstM = query.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

2-2使用SQL

Java代码

SQLQuery sql = baseDao.getSQLQuery("SELECT * FROM member m ORDER BY m.id DESC");

sql.setFirstResult(10);

sql.setMaxResults(10);

//查询出的结果放到指定POJO中

sql.addEntity(Member.class);

List<Member> lstM = sql.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

2-3使用Criteria

Java代码

Criteria crit = baseDao.getCriteria(Member.class);

crit.setFirstResult(10);

crit.setMaxResults(10);

crit.addOrder(Order.desc("id"));

List<Member> lstM = crit.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

3、数据库查询核心是条件,绝大多数SQL都会带有WHERE子句,下面介绍简单的WHERE查询

以此为例:SELECT * FROM member m WHERE m.login_code like ‘kaka%’ AND m.password in (‘12345’, ‘123451’,’123452’) AND m.delete_flag=0;这里面有like、in和=三种查询

特别注意:绝对不推荐直接在SQL语句后面拼接参数值:“*** WHERE id=”+id+” AND name like ”+name+”%”;这种方式可能会造成很严重的后果:每一个不同的id值都会在内存中创建一个SQL请求对象,如果id多并且多次执行该句SQL很可能出现宕机状况!推荐使用下面这些赋值方式,下面的方式都只会在内存中创建一个SQL请求对象。

3-1-1使用HQL“WHERE 字段=?”的形式给条件赋值

这种打?号传值的方式在JDBC是非常常见的了,使用HQL语句也可以通过这种方式赋值:

Java代码

Query query = baseDao.getQuery("FROM Member m WHERE m.loginCode LIKE ? AND m.password in (?,?,?) AND m.deleteFlag=?");

query.setParameter(0, "kaka%");

query.setParameter(1, "12345");

query.setParameter(2, "123451");

query.setParameter(3, "123452");

query.setParameter(4, 0);

List<Member> lstM = query.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

通过query.setParameter(int,Obejct)方法即可给每个?赋值,注意第一个参数是从下标0开始!

3-1-2使用HQL “WHERE 字段=:key”的形式给条件赋值

这种赋值方式是HQL特有的,什么意思呢,直接看例子分析:

Java代码

Query query = baseDao.getQuery("FROM Member m WHERE m.loginCode LIKE :code AND m.password in (:pwd) AND m.deleteFlag=:flag");

query.setParameter("code", "kaka%");

query.setParameterList("pwd", new String[]{"12345","123451","123452"});

query.setParameter("flag", 0);

List<Member> lstM = query.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

上面例子关键代码是Query调用setParameter(String,Object)和setParameterList两个方法,前者是赋单一值,后者是赋多个值(特别适合in查询赋值)。这两种赋值方法都需要传两参数:第一个参数是key值,对应HQL语句中的“:xxx”;第二个参数是value值,就对应key的实际值。这种传值比3-1-1更准确方便:一来不用担心下标错位的问题,二来如果存在”xx,xx,xx”这种格式的参数可以使用setParameterList方法,屡试不爽!

3-2-1使用SQL“WHERE 字段=?”的形式给参数赋值

Java代码

SQLQuery sql = baseDao.getSQLQuery("SELECT * FROM Member m WHERE m.login_code LIKE ? AND m.password in (?,?,?) AND m.delete_flag=?");

sql.setParameter(0, "kaka%");

sql.setParameter(1, "12345");

sql.setParameter(2, "123451");

sql.setParameter(3, "123452");

sql.setParameter(4, 0);

sql.addEntity(Member.class);

List<Member> lstM = sql.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

上面这段代码与3-1-2的代码极其相似,但是有以下几点区别:①使用SQLQuery的形式查询;②SQL语句m.login_code和m.delete_flag与前面的HQL里面不对应,前面说了HQL里面对应的是POJO(也就是Member类)的属性,而SQL语句是直接对应数据库的字段名!

3-2-2使用SQL “WHERE 字段=:key”的形式给条件赋值

注意这种key/value赋值的形式是通过SQLQuery对象创建的SQL才能用,下面这段代码是能查询出结果的

Java代码

SQLQuery sql = baseDao.getSQLQuery("SELECT * FROM Member m WHERE m.login_code LIKE :code AND m.password in (:pwd) AND m.delete_flag=:flag");

sql.setParameter("code", "kaka%");

sql.setParameterList("pwd", new String[]{"12345","123451","123452"});

sql.setParameter("flag", 0);

sql.addEntity(Member.class);

List<Member> lstM = sql.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

3-3使用Criteria来实现查询

其实Criteria出现的主要原因就是为了处理复杂的条件查询,开发人员在使用SQL编写复杂查询条件时很容易出错,Hibernate就提供了Criteria这样一个方便的API,开发人员用Java来写查询条件,最后由Hibernate转换成SQL去执行。

Java代码

Criteria crit = baseDao.getCriteria(Member.class);

crit.add(Restrictions.like("loginCode", "kaka%"));

crit.add(Restrictions.in("password", new String[]{"12345","123451","123452"}));

crit.add(Restrictions.eq("deleteFlag", 0));

List<Member> lstM = crit.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

Criteria对象通过add方法添加查询条件,Restrictions提供了各种各样的查询条件API:like、in、eq、between、or等等。这里要注意一点:像Restrictions.like(key,value)这些方法的key就是POJO中的属性,而不是数据库中的字段!

4、有时候我们调用SQL时不希望查询出表的所有字段(特别是大数据量项目更要考虑),使用纯JDBC写这样的SQL就能实现,但是如果用JDBC,得到值后还要通过ResultSet.getXXX来获取对应数据,这种方式非常麻烦。Hibernate提供了很多解决方案,使我们摆脱频繁的getXX操作。

以此为例:我希望查询Member表的id和fk_userinfo这两个字段

4-1HQL获取指定字段推荐采用面向对象的形式来实现

什么意思呢,假设Member类有一个构造函数Member(int id,int fkId),我们通过new Member(xx,xx)赋值这样就把值放入Member中了,使用HQL也是这样的:

第一步编写Member构造函数

Java代码

public BaseMember(Integer id, Integer fkId) {

this.id = id;

Userinfo fkUserinfo = new Userinfo(fkId);

this.fkUserinfo = fkUserinfo;

}

第二步编写HQL,注意看SELECT后面的写法,这种写法看起来非常像Java的new Member是吧,只要这样写,通过Query.list()返回的结果就直接存放在List<Member>中了

Java代码

Query query = baseDao.getQuery("SELECT NEW com.bless.model. Member(m.id,m.fkUserinfo.id) FROM Member m");

List<Member> lstM = query.list();

for (Member member : lstM) {

System.out.println("id:"+member.getId()+"   fk_id:"+member.getFkUserinfo().getId());

}

两点说明:

①理论上在编写上面那句HQL时可以这样写的:SELECT NEW Member(m.id,m.fkUserinfo.id) FROM Member m(就是把Member的包名去掉),因为Member类是在Hibernate映射文件Member.hbm.xml中指定了路径的。但是Member在HQL里面是关键字,如果不加包名执行查询的话会报如下错误:java.lang.ClassCastException: org.hibernate.hql.ast.tree.SqlNode cannot be cast to org.hibernate.hql.ast.tree.PathNode。那么如果POJO对象不是*.hbm.xml中映射的类,则注意一定要加上POJO的全路径!

②上面HQL语句有这样一段代码“m.fkUserinfo.id”,这是一种面向对象的写法,表示m对象(Member)下的fkUserinfo属性(Userinfo)下的id,之所以这样写是因为Member表里的fk_userinfo外键关联Userinfo表的id,在编写hbm.xml时通常是将字段fk_userinfo设置成Userinfo对象方便关联自动查询,这也就是为什么在1-1例子中调用.getName()时会自动发送SQL的原因。

4-2使用SQL查询字段

在1-2中我使用setEntity将SELECt *查询出的数据直接映射到Member集合中,但是如果只查询Member表的部分字段就不能这样写了,先看下面这段可正确运行的代码:

Java代码

SQLQuery sql = baseDao.getSQLQuery("SELECT m.id,m.login_code,m.fk_userinfo FROM Member m");

sql.addScalar("login_code", Hibernate.STRING);

sql.addScalar("id", Hibernate.INTEGER);

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

for (Object[] objects : lstM) {

System.out.println("login_code:"+objects[0]+"  id:"+objects[1]);

}

上面这段代码有几个功能点:

①通过SELECT x.xx,x.xxx FROM xx x格式查询出的数据是返回一个List<Object[]>集合,也就是List每一条数据是一个Object数组,代表一行字段,在迭代List集合后通过object[下标]取每个字段数据即可;

②addScalar(字段名,类型名)用于设置返回字段的类型,Hibernate有默认设置字段类型功能,但是如果你希望明确指定每个字段的类型则必须这么写;

③上面的SQL语句是查询三个字段“m.id,m.login_code,m.fk_userinfo”,但是结果只返回了两个字段的数据,如果在lstM循环体内写objects[2]会报下标越界错误,这是因为addScalar时只设置了login_code和id两个字段,所以要注意如果你希望查询多个字段,而且又希望通过addScalar方法设置返回类型则所有查询的字段都要调用addScalar方法!

④返回的Object数组的值顺序与SQL语句中不同,SQL语句是依照id、login_code的顺序查询,而结果却是login_code、id的顺序返回,这还是因为addScalar方法,返回值是根据addScalar方法顺序来设置值的!

⑤如果只查询Members表的几个字段不能使用addEntity直接将映射到实体中,会报找不到字段值的错误,因为有几个字段是没查询的。

4-3Criteria没有找到返回特定字段的方法,如果谁有解决方案麻烦告知我一声。

5、前面介绍了查询的各种方法,这里再介绍一下通过HQL/SQL执行增删改操作。

增删改都是能改动表结构,所以调用的方法都是相同的,只是语句不同而已,同时需要考虑事务(在执行语句前开启事务,执行语句后提交事务)这样才能保证数据完整性。

5-1 使用HQL实现删除操作

HQL删除是非常简单的,同样创建Query对象,然后调用executeUpdate方法即可,该方法能处理INSERT、UPDATE和DELETE语句。

Java代码

Query q = baseDao.getQuery("DELETE FROM Member m WHERE m BETWEEN 1 AND 10");

System.out.println("删除影响行数:"+q.executeUpdate());

5-2使用SQL实现删除操作

SQL删除也是非常简单的,同样创建SQLQuery对象,然后调用executeUpdate方法即可,该方法能处理INSERT、UPDATE和DELETE语句。

Java代码

SQLQuery q = baseDao.getSQLQuery("DELETE FROM Member WHERE login_code in (:login_code)");

q.setParameterList("login_code", new String[]{"kaka10","kaka11","kaka12"});

System.out.println("删除影响行数:"+q.executeUpdate());

6、介绍Hibernate内置的几个经典API

6-1使用几个常用的

新增一个POJO到数据库:this.getSession().save(arg0)传入参数是一个POJO对象,一定要有hbm.xml映射,Hibernate会根据对象类型发送新增SQL到数据库

更新一条表数据,:this.getSession().update(arg0)传入参数是一个POJO对象,必须有ID,Hibernate会根据id更新数据,而且此方法会将POJO对象所有属性进行更新,也就是说假设Member表login_code为”kaka”,而执行update时Member对象中的logincode未设值,则最终表的login_code值会为null

删除一条表数据:this.getSession().delete(arg0)传入参数是一个POJO对象,必须有ID,其它属性值可以不要

查询操作this.getSession().get(arg0, arg1)传入参数arg0:POJO的Class,参数arg1:POJO的id,根据主键id查询一条字段数据

延迟查询 this.getSession().load(arg0, arg1)传入参数与上面的get方法相同,功能也是根据id查询一条字段,唯一不同的是:get是调用该方法就发送SQL语句并返回数据;load是当使用返回对象时才发送SQL语句查询,如下代码

Java代码

Member m = …load(Member.class,id);

Thread.sleep(1000);

m.getId();

上面的代码肯定要发一条SQL语句查询Member表,如果用的是load方法,则是在睡眠完成运行m.getId()才发送SQL语句;而如果用的是get方法,则是在调用get方法就发送SQL语句了。

6-2经典的更新操作

从6-1的update语句中我们能看到一个弊端:不能定制更新个别字段,只能更新全部字段。Hibernate提供了一种持久化状态的更新机制,这种更新方法非常奇妙:

Java代码

Member member = (Member) getSession().get(Member.class, id);

member.setLoginCode("akaka");

member.setPassword("654321");

猜想上面这段代码会发几句SQL?根据控制台调试发现总共发了两句SQL:一句是SELECT语句查询Member表,另一句是UPDATE语句更新Member表字段,最终查询数据库时发现logincode和password的值都变成了上面设置的值。

这是一种非常好使的UPDATE方法,不用写SQL语句,直接先get后set即可自动发送SQL。

以上介绍的是非常通用的Hibernate API,当然Hibernate还提供了很多其它优秀的功能,比如缓存、复杂映射等等,这些技术需要大家在学会通用API之后再深入了解。

hibernate常用API详解的更多相关文章

  1. Java程序员从笨鸟到菜鸟之(五十二)细谈Hibernate(三)Hibernate常用API详解及源码分析--csdn 曹胜欢

    新接触一个框架的目的就是想利用这个框架来为我们做一些工作,或者是让他来简化我们的工作,利用这个框架无非就是要利用这个框架所给我们提供的API去操作我们的数据,所以利用一个框架的好坏很大一部分取决于你对 ...

  2. 分享知识-快乐自己:Hibernate框架常用API详解

    1):Configuration配置对象 Configuration用于加载配置文件. 1): 调用configure()方法,加载src下的hibernate.cfg.xml文件 Configura ...

  3. Hibernate常用配置文件详解

    本文转载自:http://blog.csdn.net/csh624366188/article/details/7578939 初学hibernate的童鞋,刚开应该都有这种感觉,hibernate的 ...

  4. Selenium常用API详解介绍

    转至元数据结尾   由 黄从建创建, 最后修改于一月 21, 2019 转至元数据起始   一.selenium元素定位 1.selenium定位方法 2.定位方法的用法 二.控制浏览器操作 1.控制 ...

  5. [总结]JS操作DOM常用API详解

    文本整理了javascript操作DOM的一些常用的api,根据其作用整理成为创建,修改,查询等多种类型的api,主要用于复习基础知识,加深对原生js的认识. 基本概念 在讲解操作DOM的api之前, ...

  6. hibernate学习(2)——api详解对象

    1   Configuration 配置对象 /详解Configuration对象 public class Configuration_test { @Test //Configuration 用户 ...

  7. ( 转)Hibernate常用API

    http://blog.csdn.net/yerenyuan_pku/article/details/65103203 可在度娘上摘抄如下文字: Hibernate的核心类和接口一共有6个,分别为:S ...

  8. jqGrid APi 详解

    jqGrid APi 详解 jqGrid皮肤 从3.5版本开始,jqGrid完全支持jquery UI的theme.我们可以从http://jqueryui.com/themeroller/下载我们所 ...

  9. JDBC常用接口详解

    JDBC中常用接口详解 ***DriverManager 第一.注册驱动 第一种方式:DriverManager.registerDriver(new com.mysql.jdbc.Driver()) ...

随机推荐

  1. 移动开发tip

    input点击出现背景色和边框,加入样式 -webkit-tap-highlight-color: rgba(255,255,255,0); ios下按钮糊掉,样式表不怎么起作用,使用-webkit- ...

  2. 6. Adapter Class/Object(适配器)

    意图: 将一个类的接口转换成客户希望的另外一个接口.Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适用性: 你想使用一个已经存在的类,而它的接口不符合你的需求. 你想 ...

  3. Java中super的几种用法并与this的区别

    1. 子类的构造函数如果要引用super的话,必须把super放在函数的首位. class Base { Base() { System.out.println("Base"); ...

  4. which type of VS files should be committed into a version control system

    which type of VS files should be committed into a version control system? aps, no: last resource edi ...

  5. css之滚动条

    overflow:auto; overflow-x:auto; overflow-y:auto;

  6. sql操作

    SQL Server 存储过程 Transact-SQL中的存储过程,非常类似于Java语言中的方法,它可以重复调用.当存储过程执行一次后,可以将语句缓存中,这样下次执行的时候直接使用缓存中的语句.这 ...

  7. c#利用WebClient和WebRequest获取网页源代码的比较

    前几天举例分析了用asp+xmlhttp获取网页源代码的方法,但c#中一般是可以利用WebClient类和WebRequest类获取网页源代码.下面分别说明这两种方法的实现. WebClient类获取 ...

  8. jQuery学习-css、class操作、动画方法的运用、jQ操作Dom节点

    css操作(设置单个/多个样式.获取样式) //修改单个属性:括号之中直接是需要修改的样式名,值 css(name,value) //例:$("#one").css("b ...

  9. C.C++把整个文件内容读进一个buffer中

    原创文章,未经本人允许禁止转载. //C方式, 调用的函数繁多 //fopen,fseek,ftell,fseek,malloc,fread,fclose,free. void foo() { FIL ...

  10. Java学习笔记 01 基本数据类型、标识符、关键字和运算符

    一.基本数据类型 基本数据类型 数据类型 内存空间(8位等于1字节) 取值范围 备注 byte 8位 -128~127   short 16位 -32768~32767   int 32位 -2147 ...