- 浏览: 2667741 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
我素熊猫:
66666666666666
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderL -
jonyzhou94:
1987_ming 写道1987_ming 写道System. ...
CXF框架入门实例 -
davidforit:
你那个“2004年Nutch创始人Doug Cutting基于 ...
《Hadoop基础教程》之初识Hadoop -
masuweng:
我的就是这么弄得,到了页面还是那个格式的 。
JSONObject转换JSON--将Date转换为指定格式 -
masuweng:
∑
JSONObject转换JSON--将Date转换为指定格式
根据个人使用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的类名和属性名!
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:
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循环的代码,查询FK的name,结果与前面使用HQL查询一样:一句SQL查询Member表,随后每一次for循环又发一句SQL查询Userinfo表
1-3Hibernate条件查询(Criteria)
HQL极为强大,但是有些人希望能够动态的使用一种面向对象API创建查询,而非在他们的Java代码中嵌入字符串。对于那部分人来说,Hibernate提供了直观的Criteria查询API。
获取Hibernate的Criteria对象方法: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()); }
其实上面这种方式就是发了一句SQL:SELECT * FROM member
结果:一句SQL将所有结果查询出来
如果修改一下for循环的代码,查询FK的name,结果与前面情况一样
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;这里面有like、in和=三种查询
特别注意:绝对不推荐直接在SQL语句后面拼接参数值:“*** WHERE id=”+id+” AND name like ”+name+”%”;这种方式可能会造成很严重的后果:每一个不同的id值都会在内存中创建一个SQL请求对象,如果id多并且多次执行该句SQL很可能出现宕机状况!推荐使用下面这些赋值方式,下面的方式都只会在内存中创建一个SQL请求对象。
3-1-1使用HQL“WHERE 字段=?”的形式给条件赋值
这种打?号传值的方式在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使用SQL“WHERE 字段=?”的形式给参数赋值
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才能用,下面这段代码是能查询出结果的
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提供了各种各样的查询条件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构造函数
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>中了
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表的部分字段就不能这样写了,先看下面这段可正确运行的代码:
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语句。
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语句。
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语句查询,如下代码
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提供了一种持久化状态的更新机制,这种更新方法非常奇妙:
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之后再深入了解。
发表评论
-
关于HQL和JDBC SQL中字段相除的一点小经验
2016-02-25 11:42 3283最近在做一个功能,产 ... -
org.hibernate.hql.ast.QuerySyntaxException: unexpected token: on near line 1解决方案
2012-09-12 16:03 28072文章摘自:http://blog.csdn.net/yangw ... -
JDBC常用API之外的总结
2012-04-20 15:43 6421做JAVA的人玩JDBC肯定已经很熟练了,像DriverMa ... -
spring/hibernate/struts2常见异常总结
2011-10-21 15:52 3538Spring ①ClassNotFoundExcep ... -
eclipse插件hibernate tools安装
2011-09-09 17:34 7525eclipse helios(3.6)版 1.启动 ... -
[Hibernate框架]Hql语句in中带参数的写法
2011-05-20 11:29 67646最近遇到两次在hql的in中传递参数的问题,最初让我纠结万千。 ... -
使用代理实现Hibernate Dao层自动事务
2010-11-06 10:24 4913都说spring利用AOP实现自动事务处理机制非常好,但在 ...
相关推荐
根据个人使用Hibernate的经验,介绍一下Hibernate的多种不同的查询和CUD操作,这些东西在日常开发中非常常用,希望对大家有所帮助。
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的...
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的...
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的...
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的开发顺序,首先讲解了页面的布局设定,接着详细讲解了各种常用组件的使用方法,并对实际开发中常用的画面场景进行了总结,最后通过完整的示例演示了Ext JS+REST+Spring+Hibernate的整合方案。...
然后按照Ext JS的开发顺序,首先讲解了页面的布局设定,接着详细讲解了各种常用组件的使用方法,并对实际开发中常用的画面场景进行了总结,最后通过完整的示例演示了Ext JS+REST+Spring+Hibernate的整合方案。...
然后按照Ext JS的开发顺序,首先讲解了页面的布局设定,接着详细讲解了各种常用组件的使用方法,并对实际开发中常用的画面场景进行了总结,最后通过完整的示例演示了Ext JS+REST+Spring+Hibernate的整合方案。...
然后按照Ext JS的开发顺序,首先讲解了页面的布局设定,接着详细讲解了各种常用组件的使用方法,并对实际开发中常用的画面场景进行了总结,最后通过完整的示例演示了Ext JS+REST+Spring+Hibernate的整合方案。...
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模式
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 ...
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上下文...
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. ...
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
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. ...