版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、云计算之GAE技术内容GAE概述GAE应用的限制数据持久化技术数据库访问:JDOQL和GQL应用层技术 JavaGAE服务GAE单元测试学习资料:/intl/zh-CN/appengine/articles/GAE架构GAE概述Google App Engine 可让开发者在 Google 的基础架构上运行您的网络应用程序。App Engine 应用程序易于构建和维护,并可根据运行者的访问量和数据存储需要的增长轻松扩展。使用 Google App Engine,将不再需要维护服务器:运行者只需上传应用程序,它便可立即为用户提供服务。Google App Engine 支持以几种编程语言编写的应
2、用程序。Python和Java在 App Engine 中,运行者只需为使用的资源付费。可以免费开始使用 App Engine。所有应用程序都可以使用多达 500 MB 的存储空间,以及可支持每月约 500 万页面浏览量的足够 CPU 和带宽,完全免费。GAE特性动态网络服务,提供对常用网络技术的完全支持持久存储空间,支持查询、分类和事务自动扩展和负载平衡用于对用户进行身份验证和使用 Google 帐户发送电子邮件的 API一种功能完整的本地开发环境,可以在开发者计算机上模拟 Google App Engine用于在指定时间和定期触发事件的计划任务GAE应用的限制带宽和CPU配额限制请求大小
3、10 兆字节 响应大小 10 兆字节 请求持续时间 30 秒 同时动态请求 30 * 应用程序文件的最大数目 1,000 静态文件的最大数目 1,000 应用程序文件的最大规模 10 兆字节 静态文件的最大大小 10 兆字节 所有应用程序和静态文件的最大总大小 150 兆字节GAE数据持久化技术App Engine 提供了一个强大的分布式数据存储服务,其中包含查询引擎和事务功能。就像分布式网络服务器随访问量增加一样,该分布式数据存储区也会随数据而增加。该 App Engine 数据存储区与传统关系数据库不同。数据对象(或“实体”)有一类和一组属性。查询可以检索按属性值过滤和分类的指定种类的实体
4、。属性值可以是受支持的属性值类型中的任何一种。数据存储区实体是“无架构”的。数据实体的结构由应用程序代码提供和执行。Java JDO/JPA 接口和 Python 数据存储区接口包括用于在您的应用程序内应用和执行结构的功能。您的应用程序还可以直接访问数据存储区以根据需要应用或多或少的结构。数据存储区高度一致并使用乐观并发控制。如果有其他进程尝试更新某实体,而同时该实体位于以固定次数进行重新尝试的事务中,此时该实体将更新。应用程序可以在一个事务中执行多项数据存储区操作(全部成功或者全部失败,从而确保数据的完整性)。数据存储区通过其分布式网络使用“实体组”实现事务。一个事务操作一个组内的实体。同一
5、组的实体存储在一起,以高效执行事务。应用程序可以在实体创建时将实体分配到组。数据存储区App Engine 数据存储区存储数据对象(称为“实体”)并对其执行查询。一个实体具有一个或多个属性(若干受支持数据类型中某一类型的命名值)。属性可以是对另一实体的引用。数据存储区可以在一个事务中执行多个操作,如果任一操作失败则回滚整个事务。这对于分布式网络应用程序尤其有用,在这种分布式网络应用中,多个用户可以同时访问或处理同一数据对象。与传统数据库不同,该数据存储区使用分布式体系结构管理向超大型数据集的扩展。App Engine 应用程序可以通过描述数据对象之间的关系,以及定义查询的索引,来优化数据的分布
6、方式。App Engine 数据存储区具有高度的一致性,但不是关系数据库。虽然该数据存储区接口有许多与传统数据库相同的功能,但也具有独特的特征,它采用了不同的数据设计和管理方式,可以充分利用自动扩展功能。实体和属性App Engine 数据存储区中的数据对象称为实体。一个实体具有一个或多个属性(若干数据类型中某一类型的命名值),包括整数值、浮点值、字符串、日期、二进制数据等。每个实体还有一个唯一标识该实体的键。最简单的键具有数据存储区提供的类型和唯一的数字 ID。ID 还可以是应用程序提供的字符串。应用程序可以使用实体的键或执行与实体属性匹配的查询,从数据存储区中抓取实体。查询可以返回零个或多
7、个实体,并可以返回按属性值排序的结果。查询还可以限制数据存储区返回的结果的数量,以节省内存和运行时间。与关系数据库不同,App Engine 数据存储区不要求指定类型的所有实体要有相同的属性。应用程序可指定并强制其数据模型使用 SDK 附带的库或其自己的代码。一个属性可具有一个或多个值。具有多个值的属性可具有混合类型的值。对具有多个值的属性进行查询可测试是否有任何值满足查询条件。这样可以使这些属性能够用于测试成员身份。查询和索引App Engine 数据存储区查询对某一指定类型(数据类)的每个实体进行操作。它对实体属性值和键指定零个或多个过滤条件,以及零个或多个排序顺序。如果一个实体对于查询的
8、过滤条件和排序顺序中所提及的每个属性都具有至少一个值(可能为 null),且属性值满足所有过滤条件,那么将返回该实体作为查询的结果。每个数据存储区查询都使用一个索引,即包含按指定顺序排列的查询结果的表格。App Engine 应用程序会在一个配置文件中定义其索引。开发网络服务器在遇到未配置索引的查询时会自动为该文件添加建议。您可以在上传该应用程序之前编辑该文件,以手动调整索引。当应用程序对数据存储区实体做出更改时,数据存储区会使用正确的结果更新索引。当应用程序执行查询时,数据存储区会直接从相应的索引中抓取结果。该机制可支持许多查询,且适用于大部分应用程序。然而,该机制不支持您可能惯用的其他数据
9、库技术中的一些查询类型。事务和实体组在 App Engine 数据存储区中,所有创建、更新或删除实体的尝试都可以在一个事务中进行。事务可确保对实体所做的所有更改都保存到数据存储区中,或者,在失败的情况下不做任何更改。这样便可确保实体中数据的一致性。您可以使用事务 API 在单一事务中对一个实体执行多个操作。例如,假设您要使对象中的计数器域递增。为此,您需要读取计数器的值,计算新的值,然后存储值。如果没有事务,那么在您读取值和更新值之间,可能有另一进程使计数器递增,这会导致应用程序覆盖已更新的值。在单一事务中进行读取、计算和写入操作可确保没有其他进程干扰递增。您可以在单一事务中对多个实体进行更改
10、。为了支持这种做法,App Engine 需要预先了解哪些实体将一起更新,从而使用支持事务的方式来存储这些实体。您在创建实体时,必须声明这一实体与另一实体同属一个实体组。在一个事务中抓取、创建、更新或删除的所有实体都必须位于同一实体组中。实体组是由实体之间关系的层次结构定义的。要在组中创建实体,您应声明该实体是组中现有的另一实体的子实体。另一实体为父实体。不通过父实体创建的实体是根实体。如果一个根实体没有任何子实体,则其所在的实体组中只有这一个实体。每个实体都有一条从根实体到其自身的父实体-子实体关系路径(最短的路径没有父实体)。该路径是实体完整键中必不可少的一部分。完整的键可以用路径中各实体
11、的类型以及 ID 或键名来表示。数据存储区使用开放式并发来管理事务。在一个应用程序实例将更改应用到实体组中的实体时,对于该组中任何实体的所有其他更新尝试都会立即失败。应用程序可再次尝试事务,将其应用到更新的数据。配额和限制对于数据存储区 API 的每次调用都会计算在数据存储区 API 调用配额内。请注意,有些库的调用会导致对基础数据存储区 API 的多次调用。由应用程序发送到数据存储区的数据会计算在数据发送到(数据存储区)API 配额内。应用程序从数据存储区接收的数据都会计算在数据接收自(数据存储区)API 配额内。应用程序当前存储在数据存储区中的数据总量不得超过存储的数据(可调整)配额。这包
12、括实体属性和键,但不包括索引。数据存储区操作消耗的 CPU 时间不得超过以下配额:CPU 时间(可调整) 数据存储区 CPU 时间 使用JDO和JDOQLPersistenceManager pm = PMF.get().getPersistenceManager(); String query = select * from + Employee.class.getName() + where lastName = Smith;List employees = (List) pm.newQuery(query).execute();设置 JDO要使用 JDO 访问数据存储区,App Engi
13、ne 应用程序需进行以下设置:JDO 和 DataNucleus App Engine 插件 JAR 必须位于应用程序的 war/WEB-INF/lib/ 目录。命名为 jdoconfig.xml 的配置文件必须位于应用程序的 war/WEB-INF/classes/META-INF/ 目录中,配置为使 JDO 使用 App Engine 数据存储区。项目的构建过程必须对编译的数据类执行后编译“增强”步骤以使其与 JDO 实现相关联。如果使用的是 Eclipse Google 插件,则以上三项已为处理。预先准备的类EmployeePrimaryKey Persistent(valueStrat
14、egy = IdGeneratorStrategy.IDENTITY) private Long id; Persistent private String firstName; Persistent private String lastName; Persistent private Date hireDate; 创建数据 PersistenceManager pm = PMF.get().getPersistenceManager(); Employee e = new Employee(Alfred, Smith, new Date(); try pm.makePersistent(e
15、); finally pm.close(); 键每个实体都具有一个在 App Engine 的所有实体中唯一的键。一个完整的键包含若干条信息,其中包括应用程序 ID、类型和实体 ID。对象的键存储在实例的某一个字段中。开发者可以使用 PrimaryKey 批注来标识主键字段。应用程序可在创建对象时以字符串形式提供键的 ID 部分,也可以允许数据存储区自动生成数字 ID。完整的键在数据存储区的所有实体中必须是唯一的。换句话说,在类型相同且具有相同父实体组(如果有)的所有对象中,一个对象必须具有唯一的 ID。您可以使用字段类型和批注来选择所需的键的行为。通过键获取对象Key k = KeyFact
16、ory.createKey(Employee.class.getSimpleName(), Alfred.Smith);Employee e = pm.getObjectById(Employee.class, k);更新对象使用 JDO 更新对象的一种方式是抓取对象,然后在返回该对象的 PersistenceManager 仍然处于打开状态的情况下对该对象进行修改。当关闭 PersistenceManager 时,会保留修改。public void updateEmployeeTitle(User user, String newTitle) PersistenceManager pm =
17、PMF.get().getPersistenceManager(); try Employee e = pm.getObjectById(Employee.class, user.getEmail(); if (titleChangeIsAuthorized(e, newTitle) e.setTitle(newTitle); else throw new UnauthorizedTitleChangeException(e, newTitle); finally pm.close(); 删除对象要将对象从数据存储区中删除,请对该对象调用 PersistenceManager 的 delete
18、Persistent() 方法。pm.deletePersistent(e);如果某个对象的字段同样包含持久的子对象,则这些子对象也将被删除。查询和索引Query query = pm.newQuery(Employee.class); query.setFilter(lastName = lastNameParam); query.setOrdering(hireDate desc); query.declareParameters(String lastNameParam);try List results = (List) query.execute(Smith); if (result
19、s.iterator().hasNext() for (Employee e : results) / . else / . no results . finally query.closeAll(); 字符串组装查询(SQL注入?) Query query = pm.newQuery(select from Employee + where lastName = lastNameParam + order by hireDate desc + parameters String lastNameParam) List results = (List) query.execute(Smith)
20、;混合型Query query = pm.newQuery(Employee.class, lastName = lastNameParam order by hireDate desc); query.declareParameters(String lastNameParam); List results = (List) query.execute(Smith);引入索引App Engine 数据存储区会为应用程序要进行的每个查询都保留一个索引。当应用程序对数据存储区实体做出更改时,数据存储区会使用正确的结果更新索引。当应用程序执行查询时,数据存储区会直接从相应的索引中抓取结果。应用程序
21、对查询中使用的每个类型、过滤器属性和操作符以及排序顺序的组合都具有一个索引。Text 和 Blob 值未编入索引,所以不能通过查询查找。数据存储区按照以下步骤执行查询数据存储区会标识符合查询的种类、过滤器属性、过滤器操作符和排序顺序的索引。数据存储区会使用该查询的过滤器值在满足全部过滤器条件的第一个实体处开始扫描该索引。数据存储区继续扫描索引,同时返回每个实体,直到发现不满足过滤条件的下一个实体,直到达到索引末尾,或者直到已收集了查询所请求的最多结果。事务事务是一项或一系列数据存储区操作,这些操作要么全部成功,要么全部失败。如果事务成功完成,则会对数据存储区产生所有预期的作用。如果事务失败,则
22、不会起任何作用。每个数据存储区写入操作都是原子操作。要么试图创建、更新或删除实体,要么不执行。如果有太多用户试图同时修改一个实体,那么这种高占用率将可能引发操作失败。当应用程序达到配额限制时,也可能会引发操作失败。数据存储区内部错误也是引发操作失败的原因。在上述所有情况下,操作将不起作用,且数据存储区 API 将引发异常。JDO事务的一个案例import javax.jdo.Transaction;import ClubMembers; / not shown/ . / PersistenceManager pm = .; Transaction tx = pm.currentTransact
23、ion(); try tx.begin(); ClubMembers members = pm.getObjectById(ClubMembers.class, k12345); members.incrementCounterBy(1); pm.makePersistent(members); mit(); finally if (tx.isActive() tx.rollback(); 使用JPAJava 持久性 API (JPA) 是一个用于将包含数据的对象存储在关系数据库中的标准接口。该标准定义用于对 Java 对象进行批注、通过查询检索对象,并使用事务与数据库交互的接口。使用 JPA
24、 接口的应用程序可以在不使用任何供应商特定的数据库代码的情况下使用不同的数据库。JPA 使您的应用程序可轻松地在不同的数据库供应商之间移植。GQL语法SELECT * FROM WHERE AND . ORDER BY ASC | DESC , ASC | DESC . LIMIT , OFFSET := | | = | = | != := IN := ANCESTOR IS GQL要点与使用 SQL 一样,GQL 关键字不区分大小写。类型和属性名称区分大小写。每个 GQL 查询始终以 SELECT * FROM 开头可选 WHERE 子句对结果集进行过滤以得出符合一个或多个条件的实体。IN
25、运算符将属性的值与列表中的每一项进行比较IN 和 != 运算符在后台使用多个查询可选的 LIMIT 子句使查询在前 count 个实体后停止返回结果。LIMIT 子句最大为 1000。SQL与GQL的区别Google App Engine的Datastore使用一个与SQL类似的语言,叫做“GQL”。在GQL中,SELECT语句仅可以用于一个表。因为要跨越不只一台机器, GQL不支持效率很低的JOIN语句。欲创建一对多和多对多的关系,可使用ReferenceProperty()。采用这种无共享的方式,即使磁盘坏了,系统也不致瘫痪。在GQL中,SELECT语句中的WHERE从句只容许对仅仅一列进
26、行、=、或5 AND level 20ORDER BY level ASC, score DESCJava 服务 APIMemcache网址抓取邮件图像Google 帐户Memcache对于某些任务,高性能的可扩展网络应用程序通常在稳定持久存储之前使用分布式内存数据缓存,或用分布式内存数据缓存来代替稳定持久存储。App Engine 提供了此用途的内存缓存服务。网址抓取App Engine 应用程序可以抓取资源,并通过互联网使用 HTTP 和 HTTPS 请求与其他主机通信。应用程序使用网址抓取服务来进行请求。邮件App Engine 应用程序可以代表应用程序管理员和拥有 Google 帐户的
27、用户发送电子邮件。应用程序使用邮件服务来发送电子邮件。图像App Engine 提供了使用专用图像服务来操作图像数据的功能。图像服务可以调整图像大小,旋转、翻转和裁剪图像。它还能够使用预先定义的算法提高照片质量。Google 帐户App Engine 应用程序可以使用 Google 帐户验证用户。应用程序可以检测到当前用户是否以 Google 帐户登录,并且可以将用户重定向到 Google 帐户登录页面,以便登录或新建一个帐户。在用户登录到应用程序时,应用程序可以访问用户的电子邮件地址。应用程序也可以检测当前用户是否为管理员,这样便可在应用程序中轻松实现仅管理员区域。使用本地服务实现进行单元测
28、试这里将描述如何使用 JUnit 3 完成此任务。建立执行环境创建基础 TestCase编写数据存储区测试建立执行环境您首先需要做的是确保您的单元测试的类路径上存在 appengine-api-stubs.jar 和 appengine-local-runtime.jar(这些 jar 作为 SDK 的一部分发行)。接下来,您需要创建一个 ApiProxy.Environment 实例并使用 ApiProxy 注册该实例。当您的应用程序在本地运行时,容器将使用 appengine-web.xml 配置文件中的内容为您创建该实例,但在本例中,我们的容器是 JUnit,且 JUnit 对 App
29、Engine 或 appengine-web.xml 一无所知。因此,应由测试负责确保 ApiProxy.Environment 已正确构造并注册。建立执行环境(续)import com.google.apphosting.api.ApiProxy;class TestEnvironment implements ApiProxy.Environment public String getAppId() return Unit Tests; public String getVersionId() return 1.0; public void setDefaultNamespace(Stri
30、ng s) public String getRequestNamespace() return null; public String getDefaultNamespace() return null; public String getAuthDomain() return null; public boolean isLoggedIn() return false; public String getEmail() return null; public boolean isAdmin() return false; / .ApiProxy.setEnvironmentForCurre
31、ntThread(new TestEnvironment();创建基础 TestCaseimport com.google.appengine.tools.development.ApiProxyLocalImpl;import com.google.apphosting.api.ApiProxy;public class LocalServiceTestCase extends TestCase Override public void setUp() throws Exception super.setUp(); ApiProxy.setEnvironmentForCurrentThrea
32、d(new TestEnvironment(); ApiProxy.setDelegate(new ApiProxyLocalImpl(new File(.); Override public void tearDown() throws Exception / not strictly necessary to null these out but theres no harm either ApiProxy.setDelegate(null); ApiProxy.setEnvironmentForCurrentThread(null); super.tearDown(); 测试错误发生时电
33、子邮件是否正常发送的示例import com.google.appengine.api.mail.dev.LocalMailService;import com.google.appengine.tools.development.ApiProxyLocalImpl;public class BugNotificationTest extends TestCase public void testEmailGetsSent() ApiProxyLocalImpl proxy = (ApiProxyLocalImpl) ApiProxy.getDelegate(); LocalMailServi
34、ce mailService = (LocalMailService) proxy.getService(mail); mailService.clearSentMessages(); Bug b = new Bug(); b.setSeverity(Severity.LOW); b.setText(NullPointerException when trying to update phone number.); b.setOwner(max); new BugDAO().createBug(b); assertEquals(1, mailService.getSentMessages().
35、size(); / . tests the content and recipient of the email 编写数据存储区测试默认情况下,数据存储区服务的本地实现会按固定间隔将其内容刷新到磁盘。如果您是在本地运行应用程序,那么该功能很有用,因为它将在您关闭服务器之后保存您的状态。但是在运行测试时,如果每个测试都从干净的数据存储区开始,则编写确定性测试将更容易,将状态刷新至磁盘然后读回可能会产生妨碍。我们将扩展 LocalServiceTestCase 来演示如何完成该操作:代码import com.google.appengine.api.datastore.dev.LocalDatas
36、toreService;import com.google.appengine.tools.development.ApiProxyLocalImpl;public class LocalDatastoreTestCase extends LocalServiceTestCase Override public void setUp() throws Exception super.setUp(); ApiProxyLocalImpl proxy = (ApiProxyLocalImpl) ApiProxy.getDelegate(); proxy.setProperty(LocalDatastoreService.NO_STORAGE_PROPERTY, Boolean.TRUE.toString(); Override public void tearDown() throws Excepti
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 手动圆锯机转让合同
- 车辆买卖合同起诉状
- 《乙醛脱氢酶1作为喉癌Hep-2细胞系肿瘤干细胞标志物的实验研究及初步临床分析》
- 桥梁工程围堰防渗墙施工方案
- 月施工进度报告范文
- 吉林工程职业学院《房地产估价与方法》2023-2024学年第一学期期末试卷
- 老旧小区消防水改造施工方案
- 旅游团就餐协议书
- 离婚协议书的公证与认证
- 高标准仿古建筑施工质量控制方案
- 加强眼科医疗服务体系建设
- AECOPD护理查房 课件
- 公司届次职代会暨年工作会宣传方案
- 星级酒店组织架构图
- 七年级数学上有理数的乘方练习题40道带答案
- 脱硫液提盐操作规程
- 结婚函调报告表(A4双面打印)
- (完整word版)餐券模板
- 清水砖墙面修复专项施工方案
- 设备操作三好四会四项要求五项原则培训教材
- CCTV《开门大吉》选手报名表VM
评论
0/150
提交评论