2017-05-08 1 views
2

Selon mes connaissances, il n'y a pas d'option pour mettre à jour des colonnes individuelles en utilisant une requête dans gemfire. Pour mettre à jour une colonne individuelle, j'obtiens actuellement tout l'ancien objet et je modifie la valeur modifiée et je la stocke. Si quelqu'un a implémenté quelque chose sur la mise à jour de colonnes individuelles, merci de partager.Mise à jour d'une colonne individuelle dans Pivotal 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> { 
} 

Je suis nouveau à la mise en œuvre de la propagation de Delta. J'ai lu le guide de l'utilisateur et j'ai essayé de mettre en œuvre et reçu l'exception donnée ci-dessous. Pouvez-vous s'il vous plaît partager vos pensées sur cela.

Another.java - classe de domaine

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); 
     } 

    } 

} 

client 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 Namespace

<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"> 

Version GemFire ​​instance locale - pivot-GemFire-9.0.1

Région Création Créer région -name = delta -type = REPLICATE

Exception:

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] 

Répondre

2

Salut (nouveau) Vigneshwaran-

droit, si Query capabilities de GemFire ​​(via le QueryService) est strictement pour les requêtes en cours d'exécution (à savoir les instructions SELECT). Il n'y a pas d'équivalent dans GemFire ​​OQL pour UPDATES et DELETES. GemFire ​​est un magasin de clés/valeurs avec des opérations similaires à Map (par exemple, get(key), put(key, value), etc.), où vous travaillez généralement avec l'ensemble de l'objet de domaine d'application. Cependant, il existe quelques fonctionnalités de GemFire ​​qui peuvent vous aider, que votre application soit un cache homologue (membre du cluster) ou un client cache. Généralement, les applications sont des clients de cache et utilisent/utilisent un ClientCache où le cluster est autonome et les clients se connectent au cluster à la manière d'un SGBDR. Je dirais aussi que, bien que le service Function soit utile, il ne s'agit pas de la seule option et il pourrait en réalité y avoir plus de code.Il est très typique, comme Wes le mentionne plus haut, d'utiliser une région de PARTITION, en particulier pour les données "transactionnelles" (NOTE: les régions REPLICATE sont plus applicables aux données de référence qui changent rarement). Lorsque la «fonction» peut vous aider, vous devez coder le Function pour apporter la mise à jour à l'objet de domaine d'application. La "mise à jour" pourrait être transmise dans les "arguments" de la fonction. Pour appeler une fonction, vous utilisez FunctionService de GemFire ​​pour obtenir un Execution, en utilisant l'une des méthodes ciblées (par exemple [onRegion("tracking")][7]).

REMARQUE: les autres méthodes de ciblage (à savoir, onMember(s) et onServer(s)) sont spécifiques si votre application est un « pair » ou « client », respectivement. Par exemple, vous ne pouvez pas appeler onMember(s) si votre application est un client car elle suppose que votre application est un "homologue". De même, vous ne pouvez pas appeler onServer(s) si votre application est un pair car elle suppose que votre application est un "client". onRegion(..) fonctionne si l'application est un pair ou un client. Alors que vous pourriez penser à ne pas utiliser onRegion tout le temps, il y a des avantages techniques à utiliser les autres formes de ciblage en fonction de votre UC (par exemple, pensez aux groupes de serveurs et au routage). Quoi qu'il en soit ...

Lorsque la région est une partition, vous pouvez également définir [optimizeForWrite()][8] de la fonction, ce qui implique la fonction sera mise à jour des données de la région, et par conséquent, sera acheminé au seau primaire de la partition de la clé, lorsque la clé est spécifiée using the filtering option comme décrit par Wes ci-dessus. La cohérence d'une région provient du fait que toutes les mises à jour sont routées et écrites dans le «primaire» en premier (indépendamment du serveur qui reçoit la mise à jour du client, peut-être un serveur qui n'héberge même pas la région ou les données). clé en question, c'est-à-dire un fragment différent). Après la mise à jour du fichier principal, les modifications de données sont propagées (distribuées) aux autres nœuds du cluster hébergeant des fichiers secondaires pour l'ensemble de données partition/partitionné. C'est la cohérence «transactionnelle» à laquelle Wes fait référence ci-dessus. REMARQUE: PARTITION est juste un autre mot pour SHARDING les données, où les données sont réparties uniformément à travers le groupe de noeuds disponibles. Lorsque des nœuds sont ajoutés/supprimés, les données sont rééquilibrées. Une partition peut également avoir une redondance. Ceux-ci sont appelés secondaires. PARTITION Les régions aident à la latence et au débit puisque les données sont divisées (par défaut en 113 seaux), chaque compartiment ayant une copie primaire et peut-être 1 ou plusieurs copies (secondaires, pour la redondance) améliorant ainsi le débit en lecture et en écriture. En outre, si les données doivent coller, vous pouvez également définir la propriété HA de la fonction. Cela permettra des tentatives en cas d'échecs.

Cependant, malgré tous ces avantages, vous devez toujours gérer la procédure à suivre pour mettre à jour votre objet de domaine d'application dans la fonction sur le serveur. Vous devez également faire face à la "cartographie" car il n'y a vraiment pas d'équivalent à ORM dans les magasins Key/Value comme GemFire. Bien sûr, ce n'est pas si difficile, mais il y a peut-être un meilleur moyen. Il existe une autre caractéristique, appelée Delta Propagation. Essentiellement, vous obtenez toujours et mettre à jour la valeur complète dans GemFire ​​chaque fois que vous effectuez des mises à jour.REMARQUE: il est possible d'interroger des champs sélectionnés d'un objet, en quelque sorte comme une projection, mais ce n'est pas un proxy ou lié à l'objet réel dans tous les cas. Lorsque vous exploitez les fonctionnalités Serialization de GemFire, vous pouvez utiliser leverage Delta Propagation. Lors de l'implémentation de "Deltas", seule la différence dans l'objet de domaine d'application est réellement sérialisée, envoyée sur le réseau, que ce soit entre le client et le serveur, ou entre homologues lors du maintien des politiques de redondance. Ceci est complètement transparent pour vous. Vous obtenez votre objet (côté client), le mettre à jour et le mettre. GemFire ​​gère la logique d'envoi du "delta" pour vous.

De plus, lorsque vous utilisez les client/server topology et partitionner Régions sur les serveurs du cluster, vous pouvez activer Single-Hop access qui efficacement achemine les données vers le serveur contenant le seau « primaire », évitant ainsi les sauts de réseau supplémentaires, ce qui aura une incidence sur votre latence perçue par opération. Ainsi, entre Deltas et Single-Hop, vous obtenez une solution assez performante et pouvez toujours tirer parti de l'approche orientée objet, en utilisant vos API d'objet de domaine d'application comme vous vous en doutez. Toutefois, soyez conscient des pitfalls of using Deltas.

De toute façon, matière à réflexion. Vous avez généralement toujours plus d'une façon d'accomplir une tâche, mais la meilleure approche n'est pas toujours évidente tant que vous n'avez pas mesuré et évalué l'effet désiré en fonction de votre UC/objectif.

Cheers, John

+1

Hi John, Cette application est une application Cache-Client et utilise déjà les fonctionnalités de sérialisation de Gemfire. Nous avons décidé d'opter pour le Delta Propagation. Vos explications sont précises et super utiles. Je voudrais mettre en œuvre et ensuite, accepter votre réponse. Merci beaucoup. Votre aide a été inestimable pour moi. – Vigneshwaran

+0

Vous êtes les bienvenus. –

+0

J'ai essayé avec Delta Propagation ne me convenait pas à cause du PDX. Essayer d'implémenter en utilisant Function onRegion(). WithFilter (clé) .withArgs (columnsAndValuesMap). Pouvez-vous s'il vous plaît partager des extraits de code à écrire pour la fonction serveur (méthode Execute). Merci d'avance – Vigneshwaran

0

Vous Impossible de mettre à jour une colonne à l'aide du service Query. Je recommande que vous considériez le Fonction service pour la cohérence transactionnelle. Rendez la région partitionnée et appelez la fonction en utilisant le fichier .onRegion(). WithFilter (key) .withArgs (columnsAndValuesMap).

Votre fonction va lire l'objet, appliquer les mises à jour, et mettre. De cette façon, votre lecture et votre mise à jour se feront dans un seul thread sur le serveur, assurant une cohérence transactionnelle plutôt que de lire l'objet sur le client, de changer une valeur, de faire un put et d'espérer que personne d'autre ne glisse .

+0

Wes - Pouvez-vous s'il vous plaît partager l'extrait de code de fonction pour gérer ce scénario à la fonction. Apprécier ton aide. – Vigneshwaran

0

Une autre façon nous avons atteint le même but est une fonction personnalisée qui met à jour la valeur (BeanUtils) après avoir pris un verrou distribué.

Cela peut ajouter un surcoût lié aux performances, mais garantit l'intégrité des données. C'est le compromis.

Voir ci-dessous un pseudo-code

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); 

}