据我所知,没有选项可以使用gemfire中的查询更新单个列。要更新单个列,我当前正在获取整个旧对象并修改更改的值并将其存储。如果有人在更新各个列时实施了任何内容,请分享。
@Region("tracking")
public class Tracking implements Serializable {
public String id;
public String status;
public String program;
}
@Region("tracking")
public interface TrackingQueryRepository extends CrudRepository<Tracking, String> {
}
我是Delta传播实施的新手。我已阅读用户指南并尝试实施并收到下面给出的例外情况。你能分享一下你的想法吗? 此
Another.java - 域类
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import org.springframework.data.gemfire.mapping.Region;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.gemstone.gemfire.Delta;
import com.gemstone.gemfire.InvalidDeltaException;
@Region("delta")
public class Another implements Delta, Serializable {
private static final long serialVersionUID = 1L;
@Id
private String anotherId;
@JsonProperty("anotherProgramId")
private String anotherProgramId;
public Another() {
}
public Another(String anotherId, String anotherProgramId) {
this.anotherId = anotherId;
this.anotherProgramId = anotherProgramId;
}
public String getAnotherId() {
return anotherId;
}
public void setAnotherId(String anotherId) {
this.anotherIdChd = true;
this.anotherId = anotherId;
}
public String getAnotherProgramId() {
return anotherProgramId;
}
public void setAnotherProgramId(String anotherProgramId) {
this.anotherProgramIdChd = true;
this.anotherProgramId = anotherProgramId;
}
private transient boolean anotherIdChd = false;
private transient boolean anotherProgramIdChd = false;
@Override
public String toString() {
return "Another [anotherId=" + anotherId + ", anotherProgramId=" + anotherProgramId + "]";
}
@Override
public void fromDelta(DataInput in) throws IOException, InvalidDeltaException {
if (in.readBoolean()) {
// Read the change and apply it to the object
this.anotherId = in.toString();
System.out.println(" Applied delta to field 'anotherId' = " + this.anotherId);
}
if (in.readBoolean()) {
this.anotherProgramId = in.toString();
System.out.println(" Applied delta to field 'anotherProgramId' = " + this.anotherProgramId);
}
}
@Override
public boolean hasDelta() {
return this.anotherIdChd || this.anotherProgramIdChd;
}
@Override
public void toDelta(DataOutput out) throws IOException {
System.out.println("Extracting delta from " + this.toString());
out.writeBoolean(anotherIdChd);
if (anotherIdChd) {
// Write just the changes into the data stream
out.writeUTF(this.anotherId);
// Once the delta information is written, reset the delta status
// field
this.anotherIdChd = false;
System.out.println(" Extracted delta from field 'anotherId' = " + this.anotherId);
}
out.writeBoolean(anotherProgramIdChd);
if (anotherProgramIdChd) {
out.writeUTF(this.anotherProgramId);
this.anotherProgramIdChd = false;
System.out.println(" Extracted delta from field 'anotherProgramId' = " + this.anotherProgramId);
}
}
}
客户cache.xml
<pdx>
<pdx-serializer>
<class-name>com.gemstone.gemfire.pdx.ReflectionBasedAutoSerializer</class-name>
<parameter name="classes">
<string>com\.rs\.main\..+</string>
</parameter>
</pdx-serializer>
</pdx>
Spring XML命名空间
<util:properties id="gemfire-props">
<prop key="delta-propagation">true</prop>
</util:properties>
<gfe:client-cache pool-name="serverPool" cache-xml-location="classpath:client-cache.xml" properties-ref="gemfire-props"/>
<gfe:client-region id="delta" pool-name="serverPool" shortcut="PROXY" cloning-enabled="true">
本地gemfire实例版 - pivotal-gemfire-9.0.1
区域创建 创建区域-name = delta -type = REPLICATE
例外:
2017-05-08 22:17:12.370 ERROR 14696 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataAccessResourceFailureException: remote server on 10.148.210.249(:loner):53784:e10627eb: com.gemstone.gemfire.pdx.PdxSerializationException: Could not create an instance of a class com.rs.main.Another; nested exception is com.gemstone.gemfire.cache.client.ServerOperationException: remote server on 10.148.210.249(:loner):53784:e10627eb: com.gemstone.gemfire.pdx.PdxSerializationException: Could not create an instance of a class com.rs.main.Another] with root cause
java.lang.ClassNotFoundException: com.rs.main.Another
at org.apache.geode.internal.ClassPathLoader.forName(ClassPathLoader.java:437) ~[na:na]
at org.apache.geode.internal.InternalDataSerializer.getCachedClass(InternalDataSerializer.java:4010) ~[na:na]
at org.apache.geode.pdx.internal.PdxType.getPdxClass(PdxType.java:235) ~[na:na]
at org.apache.geode.pdx.internal.PdxReaderImpl.basicGetObject(PdxReaderImpl.java:687) ~[na:na]
at org.apache.geode.pdx.internal.PdxReaderImpl.getObject(PdxReaderImpl.java:682) ~[na:na]
at org.apache.geode.internal.InternalDataSerializer.readPdxSerializable(InternalDataSerializer.java:3218) ~[na:na]
at org.apache.geode.internal.InternalDataSerializer.basicReadObject(InternalDataSerializer.java:3005) ~[na:na]
at org.apache.geode.DataSerializer.readObject(DataSerializer.java:2897) ~[na:na]
at org.apache.geode.internal.util.BlobHelper.deserializeBlob(BlobHelper.java:90) ~[na:na]
at org.apache.geode.internal.cache.EntryEventImpl.deserialize(EntryEventImpl.java:1891) ~[na:na]
at org.apache.geode.internal.cache.EntryEventImpl.deserialize(EntryEventImpl.java:1884) ~[na:na]
at org.apache.geode.internal.cache.VMCachedDeserializable.getDeserializedValue(VMCachedDeserializable.java:134) ~[na:na]
at org.apache.geode.internal.cache.EntryEventImpl.processDeltaBytes(EntryEventImpl.java:1687) ~[na:na]
at org.apache.geode.internal.cache.EntryEventImpl.setNewValueInRegion(EntryEventImpl.java:1558) ~[na:na]
at org.apache.geode.internal.cache.EntryEventImpl.putExistingEntry(EntryEventImpl.java:1504) ~[na:na]
at org.apache.geode.internal.cache.AbstractRegionMap.updateEntry(AbstractRegionMap.java:2959) ~[na:na]
at org.apache.geode.internal.cache.AbstractRegionMap.basicPut(AbstractRegionMap.java:2782) ~[na:na]
at org.apache.geode.internal.cache.LocalRegion.virtualPut(LocalRegion.java:5750) ~[na:na]
at org.apache.geode.internal.cache.DistributedRegion.virtualPut(DistributedRegion.java:337) ~[na:na]
at org.apache.geode.internal.cache.LocalRegionDataView.putEntry(LocalRegionDataView.java:151) ~[na:na]
at org.apache.geode.internal.cache.LocalRegion.basicUpdate(LocalRegion.java:5730) ~[na:na]
at org.apache.geode.internal.cache.LocalRegion.basicBridgePut(LocalRegion.java:5374) ~[na:na]
at org.apache.geode.internal.cache.tier.sockets.command.Put65.cmdExecute(Put65.java:381) ~[na:na]
at org.apache.geode.internal.cache.tier.sockets.BaseCommand.execute(BaseCommand.java:141) ~[na:na]
at org.apache.geode.internal.cache.tier.sockets.ServerConnection.doNormalMsg(ServerConnection.java:776) ~[na:na]
at org.apache.geode.internal.cache.tier.sockets.ServerConnection.doOneMessage(ServerConnection.java:904) ~[na:na]
at org.apache.geode.internal.cache.tier.sockets.ServerConnection.run(ServerConnection.java:1160) ~[na:na]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_121]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_121]
at org.apache.geode.internal.cache.tier.sockets.AcceptorImpl$1$1.run(AcceptorImpl.java:519) ~[na:na]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]
答案 0 :(得分:2)
嗨(再次)Vigneshwaran -
是的,所以GemFire的Query capabilities(通过QueryService)严格用于运行查询(即SELECT语句)。对于UPDATES和DELETES,GemFire OQL中没有等效词。 GemFire是具有Map
的键/值存储 - 类似操作(例如get(key)
,put(key, value)
等),您通常使用整个应用程序域对象。但是,无论您的应用程序是对等缓存(即群集成员)还是缓存客户端,GemFire都有一些功能可以帮助您。通常,应用程序是缓存客户端,并且/或者使用ClientCache,其中集群是独立的,客户端连接到集群,就像RDBMS一样。
我还要说,虽然功能服务很有用,但它并不是唯一的选择,实际上可能是代码更多的开销。
正如Wes在上面提到的那样,使用PARTITION区域是非常典型的,特别是对于&#34;事务性&#34;数据(注意:REPLICATE区域更适用于不经常更改的参考数据)。
&#34;功能&#34;可以帮助您,您可以编写Function代码来更新应用程序域对象。 &#34;更新&#34;可以通过函数&#34;参数&#34;传递。要调用函数,您可以使用GemFire的FunctionService来获取Execution,使用其中一种有针对性的方法(例如[onRegion("tracking")][7]
)。
注意:其他定位方法(即
onMember(s)
和onServer(s)
)特定于您的应用程序是否是&#34; peer&#34;或者&#34;客户&#34;分别。例如,如果您的应用程序是客户端,则无法调用onMember(s)
,因为它假定您的应用程序是&#34; peer&#34;。同样,如果您的应用程序是同行,则无法调用onServer(s)
,因为它假定您的应用程序是&#34;客户端&#34;。onRegion(..)
适用于应用程序是同级还是客户端。虽然您可能会想到为什么不一直使用onRegion
,但根据您的UC(例如,思考服务器组和路由),使用其他形式的定位会有技术优势。总之...
当Region为PARTITION时,您还可以设置Function [optimizeForWrite()][8]
,这意味着Function将更新Region数据,因此将被路由到PARTITION的primary密钥的存储区,当指定密钥using the filtering选项时,如 Wes 所述。
PARTITION Region的一致性来自于所有更新都被路由并写入&#34; primary&#34;首先(无论哪个服务器接收客户端的更新,其可能是甚至不托管该区域或所讨论的数据/密钥的服务器;即,不同的分片)。更新主数据库之后,数据更改会传播(分发)到托管辅助节点的群集中的其他节点,以用于分区/分片数据集。这是&#34;交易&#34; Wes在上面提到的一致性。
注意:PARTITION只是SHARDING数据的另一个词,数据在可用节点集群中均匀分布。添加/删除节点时,将重新平衡数据。 PARTITION也可以有冗余。这些被称为次要。 PARTITION区域有助于延迟和吞吐量,因为数据被划分(默认为113个桶),其中每个存储桶都有主存,可能有1个或更多副本(辅助节点,用于冗余; HA),从而提高了读写吞吐量。
此外,如果数据必须坚持,那么您还可以设置功能HA属性。这将允许在失败的情况下重试。
然而,尽管有这些优点,你仍然需要处理&#34;操作方法&#34;在服务器上的Function中更新应用程序域对象。你还必须处理&#34;映射&#34;因为像GemFire这样的Key / Value商店确实没有相当于ORM的东西。当然,这并不困难,但也许有更好的方法。
还有一个名为Delta Propagation的功能。从本质上讲,无论何时进行更新,您总是可以获得并更新GemFire的全部价值。
注意:可以像时尚一样查询对象的选择字段,但它不是代理或与实际对象相关。
当您利用GemFire的Serialization功能时,您可以leverage Delta Propagation。
在实施&#34; Deltas&#34;时,只有应用程序域对象的差异实际上是序列化的,通过网络发送,无论是在客户端和服务器之间,还是在维护冗余策略时在对等体之间。这对你来说完全无缝。你得到你的对象(客户端),更新它,并把它。 GemFire处理发送&#34; delta&#34;的逻辑。对你而言。
此外,在群集中的服务器上使用client/server topology和PARTITION区域时,您可以启用Single-Hop access,它可以有效地将数据路由到包含&#34; primary&#34;存储桶,从而避免额外的网络跳数,这将影响您每次操作的感知延迟。
因此,在Deltas和Single-Hop之间,您最终会得到一个性能相当高的解决方案,并且仍然可以使用面向对象的方法,使用您期望的应用程序域对象API。
无论如何,值得深思。您通常总是有多种方法来完成任务,但在您根据UC /目标衡量和评估所需效果之前,更好的方法并不总是显而易见。
干杯, 约翰
答案 1 :(得分:0)
您无法使用查询服务更新列。我建议您考虑 Function 服务以实现事务一致性。使区域分区并使用.onRegion()。withFilter(key).withArgs(columnsAndValuesMap)调用该函数。
您的函数将读取对象,应用更新并放置。
通过这种方式,您的读取和更新将发生在服务器上的单个线程中,确保事务一致性,而不是读取客户端上的对象,更改值,执行put并希望没有其他人在您下面滑动。
答案 2 :(得分:0)
我们实现相同目标的另一种方法是使用自定义函数,该函数在采用分布式锁之后更新值(BeanUtils)。
这可能会增加性能开销,但可以保证数据完整性。这是一种权衡。
见下面的伪代码
try{
//this can be regionName
dls = DistributedLockService.getServiceNamed(arbitrary-lock-name)
//the key is normally the object @Id
dls.lock(some-key, waitTimeOut, leaseTimeOut)
row = region.get(id)
//Here we copy the desired value (input to function) to the latest value
BeanUtils.copyProperty(row, key, value);
//Insert the modified record to Gemfire - now this becomes equivalent of update <region> set value = for a specific property.
region.put(id, row)
} finally{
dls.unlock(some-key);
}