Java数据对象JDO 2.0查询语言的特点

查询语言的改进是JDO2.0规范中的重要环节,本文从较高的层面阐述JDO2.0所提供的一些新功能。由于JDO2.0规范还未进入公开草案状态,目前还没有任何内容敲定下来,一切都还可能面临变化。不过,JDO2.0将会很快进入最后阶段,而这里提到的查询特性是JDO2.0专家组(译者注:David Jordan就是专家组重要成员)花费时间最多,并且相对来说最为稳定。因此,我有足够理由相信,最终规范与这里的描述将会基本一致。

  如果各位读者觉得本文遗漏了某些重要的特性,建议立即到JDO论坛(http://www.jdocentral.com/forums/index.php?showforum=10 )去提出并讨论。这里我们需要感谢JDO2.0规范领导人Craig Russell授权给我公开这些JDO2.0查询语言的新特性。

  查询结果

  我们首先从最深入的改进开始介绍。在JDO1.0中,查询结果总是你所指定的类的实例集合。考虑下面的UML类图,它表达了A、B、C、D四个类及之间的关系:


  你可以创建一个对A类的查询,通过contains()引用到B类,再通过又一层contains()引用到C类,最后再使用一个“.”操作符引用到D类。但最终返回的集合中只会包含A类的对象实例,如果要从结果中获得其它类,就必须通过A类的引用来逐个获取相关的其它类对象。如果你的查询条件里面包含了B、C或D类的约束,那么在结果集中通过A类对象引用其它类对象时,必须重新将这些约束在Java代码中重复一遍,也就是说,你不得不在Java和JDOQL中重复声明限制条件。再者,你可能只关心满足查询条件的D类对象,而不希望中间的B、C类对象被JDO底层创建从而节省内存或相关资源。

  在JDO2.0中,你再也不受缚于这些限制了。你可以返回:

  数据类(PersistentCapable)的一个或多个字段
  候选类以外的其它类对象
  统计数据

  这意味着你可以返回A、B、C、D类对象,或者它们的某些字段,或者二者的混和结果。你还可以计算类似min或max之类的统计结果。基本上,你想返回什么结果都可以。

  当你创建一个查询时,你可以指定一个“结果定义(Result Specification)”来指定返回什么样的内容。它是一个包含一个或多个以逗号分隔的“结果表达式(Result Expression)”。结果表达式可以是:

  this关键字,表示返回候选类的对象实例。这与JDO1.0是一样的字段,标明候选类或引用类的某个字段的值,如 address.street.name 字段表达式,代表对多个字段进行JDO预定义的几种算术运算而获得的结果变量,代表查询条件中出现的某个中间变量引用表达式,也就是JDO1.0中的通过“.”操作符进行的对象之间的引用 统计表达式通过对以上这几种结果表达式的组合运用,你可以获得任何你想要的结果。

  JDO2.0支持下面的统计函数:

  count(表达式),表达式可以是this
  sum(数字型字段表达式),“数字型字段表达式”可以是通过字段或字段的运算得到的数字型的结果
  min(数字型字段表达式)
  max(数字型字段表达式)
  avg(数字型字段表达式)

  对查询结果的指定是通过下面的API:

void javax.jdo.Query.setResult(String result)

  如果你不调用这个方法,或者参数是null,则返回候选类的对象实例(相当于设置为“this”),即JDO1.0的返回结果。如果你只指定了唯一结果表达式,则返回集合的元素类型与该结果的类型一致。另外,在默认方式下,如果指定了多个结果表达式,则返回的集合元素类型将是 Object[]。

  你可以在结果定义字符串的开头标上distinct来保证结果不会重复。而如果结果定义串中包含好几个表达式,那么distinct可以保证结果集中不会有重复的数据组。

  每个结果表达式可以指定一个名称,对于简单的字段,系统会默认以该字段的名称作为结果中该项的名称。对复杂的表达式,你可以使用下面的语法指定名称:

result_expression as name

  
  名称的使用可以让结果中的该项作为结果类中的一个属性来进行设置和使用。你可以指定一个结果类(result class),用来返回查询结果。如果查询结果是一个单值,结果类可以是任何JDO支持的类(Integer, Double, String, BigInteger, BigDecimal, java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp)。Query中设置结果类的方法是:

void setResultClass(Class resultClass)

  如果查询结果包含多个结果表达式,你可以定义一个结果类来保留结果中的各项数据,这个类必须有一个无参数的构造器。此外,每个结果表达式必须对应此类中的一个属性,不论是一个public的字段,还是一个public的setXxx()方法,并且这种直接的或bean风格的属性名称与查询结果中各项结果表达式的名称保持一致。

    组操作(Grouping)

  统计功能可用于一个分组操作中。JDO2.0提供类似SQL中的GROUP BY和HAVING子句。Query方法:

void setGrouping(String groupSpec)

  用于指定分组的原则。groupSpec参数包含一个或多个以逗号分隔的分组表达式,还可以跟上一个以“having ”开头的过滤条件。调用此方法后,setResult()参数的每个结果表达式项必须是groupSpec中的一项,或者是groupSpec中的一项或多项的运算结果。所有groupSpec项的值均相同的结果被归在同一组中(同一条结果记录)。having子句的过滤条件可以包含boolean结果的判断语句或者是对分组表达式的统计运算。与SQL一样,having子句用于对分组后的结果集进行条件过滤。

  唯一性(Uniqueness)

  很多人一直奇怪为什么Query的执行(execute)结果是一个Object类型的对象,因为这样给开发人员造成必须手工强制将结果转换成Collection的不便。JDO1.0中查询结果一般有多个元素,但JDO专家组计划在JDO2.0中加入对返回单值结果的查询的支持,于是将Query的执行结果定义为Object类型。

  你有时会执行一个你确定结果只会有一条的查询(比如统计总数或者按具有唯一索引的会员帐号查找对象等等),在JDO2.0中,你可以调用Query方法来声明:

void setUnique(boolean unique)

  当你传入“true”后,Query执行的结果将是一个单独的值对象,如果无任何结果返回,则结果是null。如果JDO发现查询结果返回了多条记录,则会扔出一个异常。

  限制返回结果的大小

  设计用户界面的时候,我们常常会显示结果集的某一部分子集(比如分页显示或只显示前十条之类)。为了性能和效率,你多半会需要限制返回结果的范围。Query的方法可以完成这一点:

void setRange(int fromInclusive, int toExclusive)

  该方法返回的结果集只包含原结果集的第fromInclusive条到第toExclusive-1条。

  新的过滤条件操作符

  一些新的操作符被加到JDOQL中,以便执行针对引用、Map、字符串和数字的操作。instanceof操作符返回一个boolean值,可以让你过滤某个指定类的对象;同样返回boolean值的containsKey(Object)函数和containsValue(Object)用于访问Map元素。

  字符串处理方面加入了很多函数,toLowerCase()和toUpperCase()分别完成大小写转换,另外还有下列函数用于查找子串位置和获得子串:

int indexOf(String)
int indexOf(String, int) String substring(int) String substring(int,int)

  另外,String的方法:

boolean matches(String pattern)

  用于执行正则式匹配。目前只能提供有限的匹配功能。“.”和“.*”可表示通配符,而“(?i)”表示匹配不区分大小写。

  对数字型的字段,JDO2.0增加了两个函数:

Math.abs(numeric) Math.sqrt(numeric)

  预定义查询(Named Queries)

  你可以在JDO描述符(metadata)中声明常用的JDOQL查询语句,这样就不用将查询嵌入到Java源代码中。这样可以提供一些灵活性,比如将查询语句写到一个配置好的文本文件中,而需要修改时可以直接改该文件,而不用更改Java源码。描述符中的每个查询都有一个名字,而要执行某个查询时,可以使用下面的方法来创建查询:

Query newNamedQuery(Class cls, String queryName)

  JDO将会搜索描述符来找到对应的预定义查询语句并生成相应的Query对象。

  访问静态字段(static fields)

  你将可以在JDOQL中访问数据类中以public static final方式声明的常量。比如

public static final int FEMALE = 0;
public static final int MALE = 1;
public static final int UNKNOWN = 2;

  而在查询中使用类似“salary > 5000.0 && gender == MALE”的过滤条件。

  批量删除(Deletion by Query)

  在JDO1.0中,要删除一个对象,必须先将其载入内存,再删除,然而很多情况下,你在删除之前并不需要访问该对象,这样的做法比较低效。在JDO2.0中,提供了Query的几个方法来删除符合查询条件的一组对象:

Object deletePersistentAll(Object[] parameters) Object deletePersistentAll(Map parameters) Object deletePersistentAll()

  此查询结果的对象会被全部从数据库删除。这些方法返回被删除对象的集合。你的程序可以决定是否需要对被删除的对象逐个访问。如果你不访问这些对象,Query执行的性能将不会受到任何影响,换句话说,这些对象将不会在内存中生成。

    厂商扩展的查询特性

  JDO厂商可以给JDOQL提供各种各样的特殊查询功能。每个厂商可以定义一组属于该厂商自己的扩展功能。如果你需要使用其中的功能,你需要将该厂商的扩展加到程序运行环境中。每个扩展有一个名字和一个可选的值。你可以单独设置每个扩展,或者一次性设置多个扩展。Query的下列方法用于设置厂商扩展特性:

void setExtensions(Map extensions) void addExtension(String key, Object value)

  SQL直接访问

  如果JDO2.0的查询功能不能满足需要,并且以下条件都满足:

  你的应用运行在关系数据库上
  
  你需要的查询有SQL语句可以实现

  你知道从你的类模型到数据库的映射细节

  你就可以创建一个SQL查询,方法是调用PersistentManger的方法:

Query newQuery(String language, Object query)
  
  每一个参数需要设置为“javax.jdo.query.SQL”,而query是一个具体的SQL语句。如果你的查询需要返回类的实例,则这个SQL语句必须返回该类的相应主键字段。使用直接的SQL时,JDOQL提供的函数将不能被使用,否则将会扔出异常JDOUserException,比如,你不能对该Query设置过滤条件字符串、排序声明或变量声明。使用SQL查询时,参数都是未指定类型的,在SQL语句中以“?”表示,并且按出现的顺序被绑定。

  结束语

  各位读者已经看到,JDO2.0对查询语句增加了很多新的功能和特性,我认为其中的查询结果定义是最大的改进。正如我在文章开头说的,这一部分变化目前来说是JDO2.0中最稳定的部分,不会有大的变化。厂商可以开始提供很多这样的功能,不用考虑专家组还在讨论的JDO2.0其余部分将如何变化。

  在JDO2.0提供标准的对象/关系映射的前提下,这里描述的查询功能和一个用于多层结构的JDO应用的脱钩/挂钩(detach/attach)机制,将使JDO占领更多的市场。对这一点有深切体会的厂商将不遗余力地争取率先推出稳定、完整、高效的JDO2.0产品。JDO将是基于数据库存储和管理的应用开发的首先API,开发人员们将享受面向对象的模型设计和高效的数据存储管理系统。

(0)

相关推荐

  • 以实例简介Java中线程池的工作特点

    什么原因使我们不得不使用线程池? 个人认为主要原因是:短时间内需要处理的任务数量很多 使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存 以下是Java自带的几种线程池: 1.newFixedThreadPool  创建一个指定工作线程数量的线程池. 每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中. 2.newCachedThreadPool 创建

  • Java的特点和优点(动力节点整理)

    Java的特点 Java语言是一种优秀的编程语言.它最大的优点就是与平台无关,在Windows 9x.Windows NT.Solaris.Linux.MacOS以及其它平台上,都可以使用相同的代码."一次编写,到处运行"的特点,使其在互联网上广泛采用. 由于Java语言的设计者们十分熟悉C++语言,所以在设计时很好地借鉴了C++语言.可以说,Java语言是一种比C++语言"还面向对象"的一种编程语言.Java语言的语法结构与C++语言的语法结构十分相似,这使得C+

  • JAVA实现单例模式的四种方法和一些特点

    一.饿汉式单例类 复制代码 代码如下: public class Singleton  {      private Singleton(){ } private static Singleton instance = new Singleton(); private static Singleton getInstance(){          return instance;      }  } 特点:饿汉式提前实例化,没有懒汉式中多线程问题,但不管我们是不是调用getInstance()

  • Java数据对象JDO 2.0查询语言的特点

    查询语言的改进是JDO2.0规范中的重要环节,本文从较高的层面阐述JDO2.0所提供的一些新功能.由于JDO2.0规范还未进入公开草案状态,目前还没有任何内容敲定下来,一切都还可能面临变化.不过,JDO2.0将会很快进入最后阶段,而这里提到的查询特性是JDO2.0专家组(译者注:David Jordan就是专家组重要成员)花费时间最多,并且相对来说最为稳定.因此,我有足够理由相信,最终规范与这里的描述将会基本一致. 如果各位读者觉得本文遗漏了某些重要的特性,建议立即到JDO论坛(http://w

  • JDO 2.0查询语言的特点

    查询语言的改进是JDO2.0规范中的重要环节,本文从较高的层面阐述JDO2.0所提供的一些新功能.由于JDO2.0规范还未进入公开草案状态,目前还没有任何内容敲定下来,一切都还可能面临变化.不过,JDO2.0将会很快进入最后阶段,而这里提到的查询特性是JDO2.0专家组(译者注:David Jordan就是专家组重要成员)花费时间最多,并且相对来说最为稳定.因此,我有足够理由相信,最终规范与这里的描述将会基本一致. 如果各位读者觉得本文遗漏了某些重要的特性,建议立即到JDO论坛(http://w

  • 浅析Java中对象的创建与对象的数据类型转换

    Java:对象创建和初始化过程 1.Java中的数据类型     Java中有3个数据类型:基本数据类型(在Java中,boolean.byte.short.int.long.char.float.double这八种是基本数据类型).引用类型和null类型.其中,引用类型包括类类型(含数组).接口类型.     下列语句声明了一些变量: int k ; A a; //a是A数据类型的对象变量名. B b1,b2,-,b10000;// 假定B是抽象类或接口. String s; 注意:从数据类型

  • 浅谈java object对象在heap中的结构

    对象和其隐藏的秘密 java.lang.Object大家应该都很熟悉了,Object是java中一切对象的鼻祖. 接下来我们来对这个java对象的鼻祖进行一个详细的解剖分析,从而理解JVM的深层次的秘密. 工具当然是使用JOL: @Slf4j public class JolUsage { @Test public void useJol(){ log.info("{}", VM.current().details()); log.info("{}", ClassL

  • 深入讲解Java的对象头与对象组成

    目录 一,对象头 1,Mark Word 2,指向类的指针 3,数组长度 二,实例数据 三,对齐填充字节 总结 Java对象保存在内存中时,由以下三部分组成: 1,对象头 2,实例数据 3,对齐填充字节 一,对象头 java的对象头由以下三部分组成: 1,Mark Word 2,指向类的指针 3,数组长度(只有数组对象才有) 对象头分为三个部分: 一.Mark Word部分,从名字就能知道它是一个记录和描述对象的部分.这也是我接下来主要讲解的部分,因为其他的内容,基本没有多大的变化情况.占八字节

  • java序列化对象根据不同配置动态改变属性名的方法

    目录 实现方式 实现过程 自定义注解一:MyParamName 自定义注解二:NameEle 手写MyNameFilter,实现fastjson的NameFilter 实体类,属性上添加自定义注解 运行主方法测试 参考 使用场景:自己项目对接多个外部系统,各个外部系统使用的字段并没有统一,所以要根据不同系统动态的输出序列化数据,使适应各个系统的要求 实现方式 使用自定义注解和fastjson实现需求 fastjson的NameFilter的作用:序列化时,属性名变成自己指定的名称 实现过程 自定

  • Java实现对象转CSV格式

    目录 介绍 代码样例 测试样例 介绍 csv全称“Comma-Separated Values”,是一种逗号分隔值格式的文件,是一种用来存储数据的纯文本格式文件.CSV文件由任意数目的记录组成,记录间以某种换行符分隔:每条记录由字段组成,字段间的分隔符是其它字符或字符串. Java对象转CSV,有现成的工具包,commons-lang3 的ReflectionToStringBuilder 就可以简单的解决的对象转CSV 但是复杂点的处理还是不行,而且在运行速度上,我测试了下我自己写的,比这个快

  • Java基于对象流实现银行系统

    Java基于对象流实现银行系统的具体代码,供大家参考,具体内容如下 系统特点: 数据持久化到文件中,系统启动后,加载文件中数据到集合中,相当于做了一个缓存. 文件读写使用的是对象流(ObjectInputStream和ObjectOutputStream),用户是看不懂那些文件的,一定程度上保证了密码和余额的安全性. 采用了MVC分层设计思想,虽然没有C控制层和V视图层,但是有完备的M模型层,数据处理Service,数据读写Dao,数据存储POJO(每一层只负责处理自己的事情,层次内部的改动不会

  • Vue监听数据对象变化源码

    监听数据对象变化,最容易想到的是建立一个需要监视对象的表,定时扫描其值,有变化,则执行相应操作,不过这种实现方式,性能是个问题,如果需要监视的数据量大的话,每扫描一次全部的对象,需要的时间很长.当然,有些框架是采用的这种方式,不过他们用非常巧妙的算法提升性能,这不在我们的讨论范围之类. Vue 中数据对象的监视,是通过设置 ES5 的新特性(ES7 都快出来了,ES5 的东西倒也真称不得新)Object.defineProperty() 中的 set.get 来实现的. 目标 与官方文档第一个例

  • java 数据结构中栈和队列的实例详解

    java 数据结构中栈和队列的实例详解 栈和队列是两种重要的线性数据结构,都是在一个特定的范围的存储单元中的存储数据.与线性表相比,它们的插入和删除操作收到更多的约束和限定,又被称为限定性的线性表结构.栈是先进后出FILO,队列是先进先出FIFO,但是有的数据结构按照一定的条件排队数据的队列,这时候的队列属于特殊队列,不一定按照上面的原则. 实现栈:采用数组和链表两种方法来实现栈 链表方法: package com.cl.content01; /* * 使用链表来实现栈 */ public cl

随机推荐