《企业级开发QL语言PPT课件》由会员分享,可在线阅读,更多相关《企业级开发QL语言PPT课件(44页珍藏版)》请在金锄头文库上搜索。
1、第四章第四章EJB3.0 QL语言语言 课程内容课程内容查询Query的API 两种参数查询:命名参数查询和位置参数查询 EJB3.0 QL语言 排序 批量更新和删除 连接操作 投影 使用操作符:NOT、BETWEEN、IN、LIKE、NULL、EXISTS等字符串函数 查询(查询(QUERY)API 一个查询API是Java持久化的一个开放接口,我们可以在运行期间通过实体管理器来获取它。Queue接口的定义如下:Package ;public interface Querypublic ListgetResultList();public object getSingleResult();p
2、ublic int executedate();pubiic Query setMaxResults(int maxResult);pubiic Query setFirstResult(int startPosition);pubiic Query setHit(String hintName,Object value);pubiic Query setParameter (String name,Object value);public Query setParameter(String name,Date value,TemporalType temporalType);public Q
3、uery setParameter(int position,Object value);/等等等等查询Query的创建我们可以使用EntityManager中的以下方法:package ;public interface EntityManagerpublic Query createQuery(String ejbqlString);public Query createNamedQuery(String name);public Query createNativeQuery(String sqlString);public Query createNativeQuery(String
4、sqlString,Class resultClass);public Query createNativeQuery(String sqlString,String resultSetMapping); 参数查询参数查询 像在JDBC中EJB-QL允许你指定参数在查询定义中所以我们可以重用和执行多次参数查询,参数查询也和SQL中的参数查询类似 QL支持两种方式的参数定义方式:命名参数和位置参数。 命名参数查询命名参数查询我们可以在EJB3 QL语句中使用参数来动态的执行我们需要查询的命令,命名参数查询的格式为:“:+参数名字”,如以下语句:Query query = entityManage
5、r.createQuery(from Order o where = :myId);/设置查询中的参数( “myId”, 2 ); 同样的,我们也可以使用多个参数在查询语句中 注意:不允许在同一个查询中使用两个相同名字的命名参数。 位置参数查询位置参数查询 位置参数: Query query = entityManager.createQuery(select o from Order o where = ?1);/ 设置查询中的参数query.setParameter(1, 2 );/ 1表示第一个参数,2是参数的值如果考虑到以后的应用需要在不同的EJB3.0 运行环境中运行,建议最好使用位
6、置参数,这样可以保证应用的可移植性。 语言语言 EJB3.0 QL主要对以下做了改进:主要对以下做了改进: 批量更新和删除批量更新和删除 连接操作连接操作 Group By从句从句 Having从句从句 投影投影 子查询子查询 动态查询动态查询 命名参数命名参数 在在SELECT从句中构造新的对象从句中构造新的对象排序排序在EJB3.0 QL语言中,排序同SQL的使用方法是很类似的,它使用ORDER BY子句。ORDER BY子句的语义同SQL中的类似。例如,我们可以构造一个简单的查询,使用ORDER BY子句来返回一个以用户姓名的字母为顺序的排列表:select pfrom Person p
7、order by ORDER BY子句中默认的列表排序方式是升序的。升序和降序分别用ASC和DESC表示。 批量更新和删除批量更新和删除 操作应用于指定的实体及其所有的子类。操作应用于指定的实体及其所有的子类。 操作不会级联到关联的实体。操作不会级联到关联的实体。 在批量更新中指定的值的类型必须同数据库在批量更新中指定的值的类型必须同数据库中的目标字段相匹配。中的目标字段相匹配。 批量更新直接在关系型数据库中进行。批量更新直接在关系型数据库中进行。 持久化上下文并不会同操作结果进行同步。持久化上下文并不会同操作结果进行同步。 批量更新就是一次性的完成多条记录的更新;批量删除就批量更新就是一次性
8、的完成多条记录的更新;批量删除就是一次性的完成从数据库中删除多条记录的操作。我们应该是一次性的完成从数据库中删除多条记录的操作。我们应该能很容易的猜到它们的含义。这些操作必须遵循以下规则:能很容易的猜到它们的含义。这些操作必须遵循以下规则:批量更新批量更新/删除删除如以下查询将所有的定单的金额加如以下查询将所有的定单的金额加10,查询如下:,查询如下:Query query = em.createQuery(update Order as o set =o.amount+10);/update的记录数的记录数int result = ();批量删除:批量删除:如以下查询语句把金额小于100 的
9、订单删除,代码如下:Query query = em.createQuery(delete from Order as o where 100);/delete的记录数int result = (); 连接操作连接操作 连接操作也是关系型数据库中常见的操作。通常,表中的外键会对应另一表中的主键。为了设计出符合范式的数据库设计,尽量不要在不同表间存储重复的数据。 连接操作能够限定关系型数据库返回符合条件的不同记录。默认的时候,EJB-QL采用内部连接(inner join)完成记录的获取工作。比如,下面给出的查询只会选择出至少存在一个雇员的所有公司集合。 select c from Compan
10、y c join c.employees eGroup By和和Having从句从句 在关系型数据库操作中,在关系型数据库操作中,Group By和和Having从句也是常见的。但是,从句也是常见的。但是,这对于这对于EJB-QL语言却是新增的。语言却是新增的。Group By会根据属性集合对结果进会根据属性集合对结果进行分组(聚合)。比如,我们需要从数据库中了解到男女职员各自的行分组(聚合)。比如,我们需要从数据库中了解到男女职员各自的数量,则可以使用如下的数量,则可以使用如下的EJB-QL: select e.sex,count(e) from Employee e Group By 注意
11、这些从句必须遵循如下若干原则:注意这些从句必须遵循如下若干原则: 处理聚合函数(比如,SUM、AVG等)外,出现在select从句的任何参数必须出现在Group By从句中。 Having从句必须针对Group By中的参数或其他聚合函数给定限制条件。 对于那些使用了Having从句,但并未使用Group By从句的EJB-QL不作要求。 投影投影 投影允许投影允许EJB-QL针对实体集合进行查询,而仅仅从实体针对实体集合进行查询,而仅仅从实体返回特定的属性。如果不要求整个实体或整个实体集合都返返回特定的属性。如果不要求整个实体或整个实体集合都返回一个调用者,则使用投影能够提高查询效率。回一个
12、调用者,则使用投影能够提高查询效率。 下面是下面是EJB-QL的示例代码:的示例代码:/直接查询我们感兴趣的属性直接查询我们感兴趣的属性(列列)Query query = em.createQuery(select , from +Person p order by desc );/集合中的元素不再是集合中的元素不再是Person,而是一个而是一个Object对象数组对象数组List result = ();在在Select从句中构造对象从句中构造对象 新的新的EJB-QL引入了一个最令人兴奋、功能方便的对象构造特性。那就引入了一个最令人兴奋、功能方便的对象构造特性。那就意味着我们可以在意味着
13、我们可以在SELECT从句中实例化对象,并作为查询结果返回给调用从句中实例化对象,并作为查询结果返回给调用者,通常在使用投影的时候,开发者经常会使用这一特性。者,通常在使用投影的时候,开发者经常会使用这一特性。 以下的代码片段使用了含有对象构造语句的查询语句:以下的代码片段使用了含有对象构造语句的查询语句: public List getSomeInfor()String ejbSql=select new com.ejb3.query.CompanyEmploueeInfo(c.name,e.name)+from Employee e join c;Query query=Em.create
14、Query(ejbSql);return ();使用操作符使用操作符BETWEEN: 比如,我们使用操作符比如,我们使用操作符BETWEEN来查询金额在来查询金额在300到到1000之之间的订单,代码如下所示:间的订单,代码如下所示: Query query = ( select o from Order as o where between 300 and 1000); List result = ();IN: 我们使用操作符我们使用操作符IN来查询所有年龄为来查询所有年龄为18,25 的的Person。如以下语。如以下语句所示:句所示: Query query = em.createQue
15、ry(select p from Person as p where in(18,25); List result = ();LIKE : 和使用和使用SQL语句查询类似,使用操作符语句查询类似,使用操作符LIKE同样也可以实现同样也可以实现模糊查询。如以下语句就可以实现查找以字符串模糊查询。如以下语句就可以实现查找以字符串li开头的开头的Person: Query query = em.createQuery(select p from Person as p where like li%); List result = (); NULL和和IS NULL: 如以下语句使用了操作符如以下语句
16、使用了操作符NULL查询了所有没有地址的查询了所有没有地址的Order: Query query = managerNew.createQuery(select o FROM Order as o where is null); 以下语句使用了操作符以下语句使用了操作符IS NULL查询了所有地址非空的查询了所有地址非空的Order: Query query = managerNew.createQuery(select o FROM Order as o where is not null); IS EMPTY和和IS NOT EMPTY 操作符操作符IS EMPTY是针对集合属性是针对集合
17、属性(Collection)的操作符。可以和的操作符。可以和NOT一起使用。如以下语句查询了一起使用。如以下语句查询了orderItems集合为空的集合为空的Order: Query query = managerNew.createQuery(select o FROM Order o where is empty by desc); List result = (); 如以下语句使用了如以下语句使用了NOT查询了查询了orderItems集合非空的集合非空的Order: Query query = managerNew.createQuery(select o FROM Order o +
18、where is not empty by desc); List result = (); EXISTS 操作符号操作符号NOTEXISTS需要和子查询语句(如需要和子查询语句(如SELECT子查询语句等)子查询语句等)配合使用。如以下语句:配合使用。如以下语句: /如果存在订单号为如果存在订单号为2 的订单,就获取所有的订单,就获取所有OrderItem Query query = em.createQuery(select oi from OrderItem as oi +where exists (select o from Order o where =2); List result
19、 = (); /如果不存在订单号为如果不存在订单号为10 的订单,就获取的订单,就获取id为为1 的的OrderItem query = em.createQuery(select oi from OrderItem as oi where +=1 and not exists (select o from Order o where =10); result = ();字符串函数字符串函数 EJB3.0 QL中定义的字符串函数包括:中定义的字符串函数包括: CONCAT字符串拼接。字符串拼接。SUBSTRING字符串截取。字符串截取。TRIM 去掉空格。去掉空格。 LOWER转换成小写。转换
20、成小写。 UPPER转换成大写。转换成大写。 LENGTH 获取字符串长度。获取字符串长度。 LOCATE 字符串定位。字符串定位。 如以下语句,查询所有人员,只取姓名的前三个字符:如以下语句,查询所有人员,只取姓名的前三个字符: Query query = em.createQuery(select , substring(p.name,1,3) from Person as p);计算函数计算函数 EJB3.0 QL中定义的计算函数包括中定义的计算函数包括 : ABS绝对值绝对值 SQRT平方根平方根 MOD取余数取余数 SIZE取集合的数量取集合的数量 如以下语句,查询所有如以下语句,查
21、询所有Order的订单号及其订单项的数量:的订单号及其订单项的数量: Query query = em.createQuery(select , ) from Order as o group by ); 又如以下语句,查询所有又如以下语句,查询所有Order 的订单号及其总金额的订单号及其总金额/10的余数:的余数: query = em.createQuery(select , , 10) from Order as o);子查询子查询 子查询可以用于子查询可以用于WHERE和和HAVING条件语句中。如以下语句查询条件语句中。如以下语句查询了年龄为了年龄为26岁的购买者的所有岁的购买者的
22、所有Order: Query query = em.createQuery(select o from Order as o where in(select p from Person as p where =26) order by ); List result = ();本章总结本章总结查询Query的API 两种参数查询:命名参数查询和位置参数查询 EJB3.0 QL语言 排序 批量更新和删除 连接操作 投影 使用操作符:NOT、BETWEEN、IN、LIKE、NULL、EXISTS等字符串函数 动手实践:动手实践:应用示例应用示例 将本章体验项目中开发的实体Bean打包部署到服务器中,
23、并把客户端的测试Web工程打包发布到JBoss服务器中,启动服务器,在浏览器中输入以下地址: 如果成功运行,将会看到页面中输出结果如图4-1所示: 图4-1 EQL查询结果图用普通的查询语句进行操作。用Order By语句来对查询结果进行排序。用Group By语句对查询结果进行分组。用批量更新和删除对数据库进行操作。根据本章所学的知识,以实体Bean:Person、Order、OrderItem为例,练习所学的查询语句。(1)实现功能一:能够获取指定persinid的人员。(2)实现功能二:使用ORDER BY语句查询符合条件的人员或者是订单。(3)实现功能三:使用GROUP BY语句查询符
24、合条件的人员或者是订单。(4)实现功能四:实现批量更新或者是批量删除的功能。二、实现步骤二、实现步骤 (1)开发实体)开发实体Bean:Person,Order,OrderItem (2)编写查询业务操作的接口:)编写查询业务操作的接口:QueryDao (3)实现类的设计:)实现类的设计: (4)实现其它的查询方法)实现其它的查询方法 (5)在)在Web工程中编写工程中编写Jsp代码测试以上的查询结果代码测试以上的查询结果 (1)开发实体Bean:Person、Order、OrderItem,我们在此处就不再次开发了,还是以本章教材中的为例,在本实践项目中我们主要是讲述如何综合运用中的查询语
25、言。(2)编写查询业务操作的接口:QueryDao,代码如下所示:package com.ejb3query.dao;public interface QueryDAO public void initdate();public String ExecuteQuery(int index);public String NameQuery(Integer id);public String PositionQuery();public String QueryOrderBy();public String QueryGroupBy();public String QueryBatchUpdate
26、();public String QueryBatchRemove();我们来简单的分析一下接口的设计,业务操作方法中除了有6个查询操作外,另外我们还定义了两个方法:initdate()和ExecuteQuery()。 initdate()方法是用于初始化数据的,为了避免程序的首次运行而导致数据库中无数据可查询而设计的。 ExecuteQuery(int index)方法是用于执行查询方法的,int index参数代表在第index处的方法被执行。设计该方法的目的是:如果我们在接口中的操作过多(可能以后还会添加其他查询操作),那么可以借助于该方法直接在实现类中调用设计的查询方法,而不必再在接口
27、中重新定义了。要理解这一点。(3)下面我们来看实现类的设计:,我们首先来看一下程序的大体框架,如以下代码所示:package com.ejb3query.imp;import java.text.SimpleDateFormat;import java.util.*;import javax.ejb.Remote;import javax.ejb.Stateless;import javax.persistence.*;import com.ejb3query.dao.QueryDAO;import com.ejb3query.bean.*;StatelessRemote (QueryDAO.
28、class)public class QueryDAOBean implements QueryDAO PersistenceContextprotected EntityManager em;/*初始化数据*/public void initdate() /public String ExecuteQuery(int index) /public String NameQuery(Integer id) /public String PositionQuery()/public String QueryOrderBy()/public String QueryGroupBy()/public
29、 String QueryBatchUpdate()/public String QueryBatchRemove()/首先,我们在initdate()方法中往数据库中添加几条数据。该方法的简单实现如下所示:public void initdate() try Query query = em.createQuery(select count(p) from Person p);Object result = query.getSingleResult();if (result = = null | Integer.parseInt(result.toString() = = 0) /没有数据
30、时,插入几条数据用作测试SimpleDateFormat formatter = new SimpleDateFormat(yyyy-MM-dd);Person person = new Person(Toikd, true, new Short(26), formatter.parse(1986-4-23);Set orders = new HashSet();Order order1 = new Order(new Float(105.5), person, new Date();order1.addOrderItem(new OrderItem(U盘, new Float(105.5);
31、Order order2 = new Order(new Float(780), person, new Date();order2.addOrderItem(new OrderItem(MP4, new Float(778); order2.addOrderItem(new OrderItem(矿泉水, new Float(2);orders.add(order1);orders.add(order2);person.setOrders(orders);Person person1 = new Person(yunxiaoyi, false,new Short(23), formatter.
32、parse(1983-10-20);orders = new HashSet();order1 = new Order(new Float(360), person1, new Date();order1.addOrderItem(new OrderItem(香水, new Float(360);order2 = new Order(new Float(1806), person1, new Date();order2.addOrderItem(new OrderItem(照相机, new Float(1800);order2.addOrderItem(new OrderItem(5号电池,
33、new Float(6);orders.add(order1);orders.add(order2);person1.setOrders(orders);Person person2 = new Person(zhangming, false,new Short(21), formatter.parse(1985-11-25);orders = new HashSet();order1 = new Order(new Float(620), person2, new Date(); order1.addOrderItem(new OrderItem(棉被, new Float(620);ord
34、er2 = new Order(new Float(3), person2, new Date();order2.addOrderItem(new OrderItem(可乐, new Float(3);orders.add(order1);orders.add(order2);person2.setOrders(orders);em.persist(person2);em.persist(person1);em.persist(person); catch (Exception e) e.printStackTrace();(4)接下来我们来实现其它的查询方法,分别如下: NameQuery(
35、)方法:获取指定personid的人员。public String NameQuery(Integer id)/获取指定personid的人员Query query = em.createQuery(select p from Person p where p.personid=:Id);query.setParameter(Id,id);List result = query.getResultList();StringBuffer out = new StringBuffer(*+ NameQuery结果打印*);if (result!=null)Iterator iterator = r
36、esult.iterator();while( iterator.hasNext() )Person person= (Person)iterator.next();out.append(person.getName()+ );return out.toString(); QueryOrderBy()方法:先按年龄降序排序,然后按出生日期升序排序。public String QueryOrderBy()/先按年龄降序排序,然后按出生日期升序排序Query query = em.createQuery(select p from Person p order by p.age desc, p.b
37、irthday asc);List result = query.getResultList();StringBuffer out = new StringBuffer(*+QueryOrderBy结果打印*);if (result!=null)Iterator iterator = result.iterator();while( iterator.hasNext() )Person person= (Person)iterator.next();out.append(person.getName()+ );return out.toString(); QueryBatchUpdate()方
38、法:批量更新。public String QueryBatchUpdate()/把所有订单的金额加10Query query = em.createQuery(update Order as o set o.amount=o.amount+10);/update的记录数int result = query.executeUpdate();StringBuffer out = new StringBuffer(*+QueryBatchUpdate 结果打印*);out.append(更新操作影响的记录数:+ result+ 条);return out.toString(); 此处我们只列出了三个
39、方法的实现,其余的三个方法的实现同以上是类似的,我们就不再一一列举了。下面我们来看ExecuteQuery()方法的实现。 ExecuteQuery()方法实现是最为简单的了,如以下代码所示:public String ExecuteQuery(int index) String result = ;switch(index)case 1:result = this.NameQuery(new Integer(1);break;case 2:result = this.PositionQuery();break;case 3:result = this.QueryOrderBy();break;/.4、5、6调用其他的方法。return result;(5)在Web工程中编写JSP代码测试上面的查询方法,JSP中的代码如下所示: