在GIS应用中,常常会出现这样一种情况,空间数据库中对某个数据集进行的一次操作(比如编辑)很复杂,或者是出于某种原因无法在有限的特定时间内完成,全部完成操作需要比较长的时间,而传统的关系数据库在编辑的数据时要锁定数据,这样就会造成别的用户在很长一段时间内也无法访问(至少是无法编辑)这些数据集,所以GIS中通过长事务解决这类问题。
在关系数据库中,事务应该具有四个属性:原子性、一致性、隔离性、持续性,这四个属性通常称为ACID特性。
l 原子性(Atomicity):一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
l 一致性(Consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态,一致性与原子性是密切相关的。
l 隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
l 持久性(Durability):持续性也称永久性(Permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的,接下来的其他操作或故障不应该对其有任何影响。
长事务是一种持续时间可以持续几天、几个月甚至更长的时间,可以涉及多个会话(Session)的事务,它除了具有ACID特性外,一般会在当前基态数据库版本的基础上建立分支版本,采用“乐观锁定”的策略,在提交事务的时候由事务管理程序统一协调处理,没有冲突的直接提交,有冲突的返回通知消息给用户,交互式解决或按事先规定好的规则处理。
大部分空间数据库都采用版本管理的方式来实现长事务,版本管理的实质是以某个数据作为基准数据,只记录变化的情况和信息,不重复记录不变的数据。在空间数据库中,使用特定的表来分别记录特征和对象被添加、删除或修改的情况。当数据库创建之时,就建立了数据库缺省的状态和版本,即根版本(Root Version)。所以,在MapGuide中所有长事务都有一个根长事务作为它的祖先。许多空间数据库支持嵌套的长事务,即在一个长事务A中可以启动另一个长事务B,长事务B的父亲为长事务A,这样长事务之间的依赖关系最后会形成一个树。
MapGuide是一个GIS数据的发布平台,并不是GIS数据的编辑平台,所以要素服务没有提供启动、提交和回滚长事务的API,仅是提供了遍历要素源中已经启动的长事务和设置当前用户会话(Session)所使用的长事务的功能。
调用方法MgFeatureService::GetLongTransactions(…)可以获得指定要素源中的长事务,该方法的签名如下所示,参数resource用于指定一个要素源,参数bActiveOnly为true,则返只回要素源中活动的长事务,否则返回要素源中所有的长事务,返回值为长事务读取器MgLongTransactionReader的一个实例。长事务读取器是一个前向只读读取器,在访问任何数据之前需要调用方法MgLongTransactionReader::ReadNext(),调用MgLongTransactionReader:: GetParents()可以得到当前长事务的父长事务,调用MgLongTransactionReader::GetChildren()可以得到当前长事务的子长事务。
MgLongTransactionReader GetLongTransactions( MgResourceIdentifier resource, bool bActiveOnly); |
如下的代码将指定长事务读取器中的所有信息输出到一个文件。
function printLongTransactionReader($longTransactionReader) { global $logFileHandle; $i = 0; fwrite($logFileHandle, "Printing long transaction readern"); while ($longTransactionReader->ReadNext()) { $i++; $name = $longTransactionReader->GetName(); fwrite($logFileHandle, "Name: $namen"); $desc = $longTransactionReader->GetDescription(); fwrite($logFileHandle, "Description: $descn"); $owner = $longTransactionReader->GetOwner(); fwrite($logFileHandle, "Owner: $ownern"); $dateTime = $longTransactionReader->GetCreationDate(); $printableDateTime = printDateTime($dateTime); fwrite($logFileHandle, "Creation Date: $printableDateTimen"); $isActive = $longTransactionReader->IsActive(); $printableIsActive = prtBool($isActive); fwrite($logFileHandle, "IsActive: $printableIsActiven"); $isFrozen = $longTransactionReader->IsFrozen(); $printableIsFrozen = prtBool($isFrozen); fwrite($logFileHandle, "IsFrozen: $printableIsFrozenn"); $parentLongTransactionReader = $longTransactionReader->GetParents(); if ($parentLongTransactionReader == NULL) { fwrite($logFileHandle, "There is no parent long transactionn"); } else { fwrite($logFileHandle, "Printing parent long transaction readern"); printLongTransactionReader($parentLongTransactionReader); $parentLongTransactionReader->Close(); } $childrenLongTransactionReader = $longTransactionReader->GetChildren(); if ($childrenLongTransactionReader == NULL) { fwrite($logFileHandle, "There are no child long transactionsn"); } else { fwrite($logFileHandle, "Printing children long transaction readern"); printLongTransactionReader($childrenLongTransactionReader); $childrenLongTransactionReader->Close(); } } fwrite($logFileHandle, "Printed $i long transaction(s)n"); } |