`

hibernate常用API详解

 
阅读更多

 

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

 

 

以下示例均以两张表为例:memberuserinfomember帐号信息表外键关联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

}

 

 

 

 

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

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

1-1简单HQL语句查询

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

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

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

 

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

 

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循环的代码,查询FKname

 

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()获取这个接口

 

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循环的代码,查询FKname,结果与前面使用HQL查询一样:一句SQL查询Member表,随后每一次for循环又发一句SQL查询Userinfo

 

1-3Hibernate条件查询(Criteria

 

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

 

获取HibernateCriteria对象方法:getSession().createCriteria(Class对象);

 

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());
}

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

 

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

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

 

 

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

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

 

2-1使用HQL

 

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

 

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

 

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;这里面有likein=三种查询

 

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

 

 

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

 

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

 

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特有的,什么意思呢,直接看例子分析:

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使用SQLWHERE 字段=?”的形式给参数赋值

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_codem.delete_flag与前面的HQL里面不对应,前面说了HQL里面对应的是POJO(也就是Member类)的属性,而SQL语句是直接对应数据库的字段名!

 

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

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

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去执行。

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提供了各种各样的查询条件APIlikeineqbetweenor等等。这里要注意一点:像Restrictions.like(key,value)这些方法的key就是POJO中的属性,而不是数据库中的字段!

 

 

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

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

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

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

第一步编写Member构造函数

public BaseMember(Integer id, Integer fkId) {
	this.id = id;
	Userinfo fkUserinfo = new Userinfo(fkId);
	this.fkUserinfo = fkUserinfo;
}

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

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中指定了路径的。但是MemberHQL里面是关键字,如果不加包名执行查询的话会报如下错误: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中我使用setEntitySELECt *查询出的数据直接映射到Member集合中,但是如果只查询Member表的部分字段就不能这样写了,先看下面这段可正确运行的代码:

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_codeid两个字段,所以要注意如果你希望查询多个字段,而且又希望通过addScalar方法设置返回类型则所有查询的字段都要调用addScalar方法!

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

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

 

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

 

 

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

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

 

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

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

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方法即可,该方法能处理INSERTUPDATEDELETE语句。

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对象,必须有IDHibernate会根据id更新数据,而且此方法会将POJO对象所有属性进行更新,也就是说假设Memberlogin_code”kaka”,而执行updateMember对象中的logincode未设值,则最终表的login_code值会为null

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

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

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

Member m = …load(Member.class,id);
Thread.sleep(1000);
m.getId();

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

 

6-2经典的更新操作

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

Member member = (Member) getSession().get(Member.class, id);
member.setLoginCode("akaka");
member.setPassword("654321");
 猜想上面这段代码会发几句SQL?根据控制台调试发现总共发了两句SQL:一句是SELECT语句查询Member表,另一句是UPDATE语句更新Member表字段,最终查询数据库时发现logincodepassword的值都变成了上面设置的值。

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

 

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

  • 大小: 21.5 KB
1
0
分享到:
评论
2 楼 白糖_ 2011-12-28  
yanshien 写道
总结的不错,受益

总结地不详细,欢迎指正、补充,共同提高
1 楼 yanshien 2011-12-28  
总结的不错,受益

相关推荐

    hibernate常用API详解(原创).doc

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

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     2.4 Hibernate API简介  2.4.1 Hibernate的核心接口  2.4.2 事件处理接口  2.4.3 Hibernate映射类型接口  2.4.4 可供扩展的接口  2.5 小结  2.6 思考题 第3章 第一个Hibernate应用  3.1 创建Hibernate的...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part4

     2.4 Hibernate API简介  2.4.1 Hibernate的核心接口  2.4.2 事件处理接口  2.4.3 Hibernate映射类型接口  2.4.4 可供扩展的接口  2.5 小结  2.6 思考题 第3章 第一个Hibernate应用  3.1 创建Hibernate的...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part3

     2.4 Hibernate API简介  2.4.1 Hibernate的核心接口  2.4.2 事件处理接口  2.4.3 Hibernate映射类型接口  2.4.4 可供扩展的接口  2.5 小结  2.6 思考题 第3章 第一个Hibernate应用  3.1 创建Hibernate的...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part1.rar

     2.4 Hibernate API简介  2.4.1 Hibernate的核心接口  2.4.2 事件处理接口  2.4.3 Hibernate映射类型接口  2.4.4 可供扩展的接口  2.5 小结  2.6 思考题 第3章 第一个Hibernate应用  3.1 创建Hibernate的...

    快意编程 EXT JS Web开发技术详解.pdf

    然后按照Ext JS的开发顺序,首先讲解了页面的布局设定,接着详细讲解了各种常用组件的使用方法,并对实际开发中常用的画面场景进行了总结,最后通过完整的示例演示了Ext JS+REST+Spring+Hibernate的整合方案。...

    快意编程EXT JS Web开发技术详解.part2

    然后按照Ext JS的开发顺序,首先讲解了页面的布局设定,接着详细讲解了各种常用组件的使用方法,并对实际开发中常用的画面场景进行了总结,最后通过完整的示例演示了Ext JS+REST+Spring+Hibernate的整合方案。...

    快意编程EXT JS Web开发技术详解.part1

    然后按照Ext JS的开发顺序,首先讲解了页面的布局设定,接着详细讲解了各种常用组件的使用方法,并对实际开发中常用的画面场景进行了总结,最后通过完整的示例演示了Ext JS+REST+Spring+Hibernate的整合方案。...

    快意编程EXT JS Web开发技术详解.part3

    然后按照Ext JS的开发顺序,首先讲解了页面的布局设定,接着详细讲解了各种常用组件的使用方法,并对实际开发中常用的画面场景进行了总结,最后通过完整的示例演示了Ext JS+REST+Spring+Hibernate的整合方案。...

    (超赞)JAVA精华之--深入JAVA API

    1 JAVA SE ...3.5 JavaMail(JAVA邮件服务)API详解 3.6 jxl.jar 包简介 3.7 Java与XML联合编程之SAX篇 3.8 Java与XML联合编程之DOM篇 4 其他 4.1 代码复用的规则 4.2 Java IO 包中的Decorator模式

    低清版 大型门户网站是这样炼成的.pdf

    4.2.2 hibernate api简介 197 4.2.3 配置hibernate 198 4.2.4 hibernate的映射配置文件 201 4.2.5 体验hibernate(会员管理) 203 4.3 hibernate的映射机制 212 4.3.1 hibernate的基本映射数据类型 212 4.3.2 ...

    J2EE应用开发详解

    50 4.2 开发和部署一个简单的Servlet 51 4.3 Servlet常用API介绍 53 4.3.1 Servlet实现相关 54 4.3.2 Servlet配置相关 54 4.3.3 Servlet异常相关 55 4.3.4 请求和响应相关 55 4.3.5 会话跟踪 56 4.3.6 Servlet上下文...

    Spring API

    12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器中使用Hibernate的注意事项 12.3. ...

    JAVA SE学习精华集锦

    3.5 JavaMail(JAVA邮件服务)API详解 145 3.6 jxl.jar 包简介 150 3.7 Java与XML联合编程之SAX篇 154 3.8 Java与XML联合编程之DOM篇 159 4 其他 165 4.1 代码复用的规则 165 4.2 Java IO 包中的Decorator模式 168

    Spring中文帮助文档

    12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器中使用Hibernate的注意事项 12.3. ...

Global site tag (gtag.js) - Google Analytics