每个数据存储区查询都使用一个索引,即包含按指定顺序排列的查询结果的表格。App Engine 应用程序会在一个名为 datastore-indexes.xml
的配置文件中定义其索引。 开发网络服务器在遇到未配置索引的查询时会自动为该文件生成建议。
基于索引的查询机制支持大多数常见查询类型,但不支持您可能惯用的来自其他数据库技术的一些查询。以下描述了对查询的限制及其对此所做的说明。
查询从数据存储区中检索满足一组条件的实体。查询会指定一种实体、基于属性值的零个或多个条件(有时称作“过滤器”)以及零个或多个排序顺序描述。执行查询时,它会抓取指定类型中满足所有指定条件并按照描述的顺序排序的全部实体。
JDO 可针对满足特定条件的实体执行查询。您还可使用 JDO Extent 来表示某种类型每个实体的集合(某个类的每个存储对象)。
JDO 包含一种查询语言,用于检索满足一组条件的对象。该语言名为 JDOQL,可直接引用 JDO 数据类和字段,并包括对查询参数和结果的类型检查。JDOQL 与 SQL 类似,但是更适合面向对象的数据库(如 App Engine 数据存储区)。(App Engine 数据存储区不支持对 JDO 接口的 SQL 查询)
查询 API 支持多种调用样式。可使用 JDOQL 字符串语法在字符串中指定一个完整的查询。还可通过对查询对象调用方法来指定查询的一部分或全部。
以下是一个使用方法调用样式的简单查询示例,带有一个过滤条件和一种排序顺序,对过滤条件中使用的值使用参数替换。查询对象的execute()
方法和要在查询中替换的值按照其声明的顺序一起调用。
import java.util.List; import javax.jdo.Query; // ... Query query = pm.newQuery(Employee.class); query.setFilter("lastName == lastNameParam"); query.setOrdering("hireDate desc"); query.declareParameters("String lastNameParam"); try { List<Employee> results = (List<Employee>) query.execute("Smith"); if (results.iterator().hasNext()) { for (Employee e : results) { // ... } } else { // ... no results ... } } finally { query.closeAll(); }
下面是使用字符串语法的相同查询:
Query query = pm.newQuery("select from Employee " + "where lastName == lastNameParam " + "order by hireDate desc " + "parameters String lastNameParam") List<Employee> results = (List<Employee>) query.execute("Smith");
可混合这些定义查询的样式。例如:
Query query = pm.newQuery(Employee.class, "lastName == lastNameParam order by hireDate desc"); query.declareParameters("String lastNameParam"); List<Employee> results = (List<Employee>) query.execute("Smith");
可通过多次调用 execute()
方法,使用不同的值替换参数来重用单个 Query 实例。每次调用都将执行查询,并以集合的形式返回结果。
JDOQL 字符串语法对字符串值和数字值支持字符串中的值字面量。用单引号 ('
) 或双引号 ("
) 将字符串引起。所有其他值类型必须使用参数替换。以下是使用字符串字面值的示例:
Query query = pm.newQuery(Employee.class, "lastName == 'Smith' order by hireDate desc");
过滤条件指定字段名称、运算符和值。值必须由应用程序提供;它不能引用其他属性或按照其它属性计算。运算符可以是任意以下运算符:< <= == >= >
注意:Java 数据存储区接口不支持在 Python 数据存储区接口中实现的 !=
和 IN
过滤条件运算符。(在 Python 接口中,这些运算符是在客户端的库中作为多数据存储区查询实现的,它们并非数据存储区本身的功能。)
过滤条件的主题可以是任意对象字段,包括主键和父实体组(请参阅事务)。
实体必须匹配所有的过滤条件才可成为结果。在 JDOQL 字符串语法中,用 &&
(逻辑“与”)分隔指定多个过滤条件。不支持过滤条件的其他逻辑组合(逻辑“或”、“非”)。
由于 App Engine 数据存储区执行查询的方式,单个查询无法对多个属性使用不等过滤条件 (< <= >= >
)。但允许对同一属性使用多个不等过滤条件(如查询值范围)。请参阅查询限制。
query.setFilter("lastName == 'Smith' && hireDate > hireDateMinimum"); query.declareParameters("Date hireDateMinimum");
排序顺序可指定属性和方向(升序或降序)。结果返回时将以给定的顺序排序(按照它们指定的顺序)。如果没有为查询指定排序顺序,则结果将按照其实体键排序。
由于 App Engine 数据存储区执行查询的方式,如果查询对一个属性指定了不等过滤条件并对其他属性指定了排序顺序,则使用不等过滤条件的属性必须在其他属性之前排序。请参阅查询限制。
query.setOrdering("hireDate desc, firstName asc");
查询可指定要返回到应用程序的结果的范围。范围可指定在完整结果集中哪个结果应最先返回,哪个应最后返回(使用数字索引,第一个结果从 0 开始)。例如,范围 5, 10
将返回第 6、7、8、9、10 个结果。
起始偏移具有性能含义:数据存储区必须检索然后丢弃起始偏移前的所有结果。例如,范围为 5, 10
的查询将先从数据存储区抓取 10 个结果,然后丢弃前 5 个并将剩余的 5 个返回到应用程序。
query.setRange(5, 10);
JDO Extent 表示特定类在数据存储区中的每个对象。
可使用 PersistenceManager 的 getExtent()
方法(向其传递数据类)开始 Extent。Extent 类可实现用于访问结果的 Iterable 接口。在完成访问结果后,可调用 closeAll()
方法。
以下示例循环访问数据存储区中的每个 Employee 对象:
import java.util.Iterator; import javax.jdo.Extent; // ... Extent extent = pm.getExtent(Employee.class, false); for (Employee e : extent) { // ... } extent.closeAll();
扩展可批量检索结果,并可超出应用到查询的 1000 个结果的限制。