{"id":1262,"date":"2011-03-29T11:38:27","date_gmt":"2011-03-29T03:38:27","guid":{"rendered":"http:\/\/www.andreanolanusse.com\/pt\/?p=1262"},"modified":"2014-03-03T20:55:26","modified_gmt":"2014-03-04T04:55:26","slug":"implementando-cache-de-dados-em-servidores-datasnap","status":"publish","type":"post","link":"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/","title":{"rendered":"Implementando cache de dados em servidores DataSnap"},"content":{"rendered":"<p>O gerenciamento de mem\u00f3ria do DataSnap \u00e9 muito\u00a0poderoso e\u00a0uma caracter\u00edstica chave\u00a0para a implementa\u00e7\u00e3o de cache.\u00a0Imagine\u00a0o cen\u00e1rio onde a aplica\u00e7\u00e3o cliente solicita os mesmos dados milhares de vezes durante o dia, certamente teremos que tocar o banco de dados a cada solicita\u00e7\u00e3o. Vamos supor que\u00a0esses dados\u00a0n\u00e3o\u00a0mudam com muita\u00a0freq\u00fc\u00eancia, por exemplo: tabela de pa\u00edses, estados ou\u00a0cidades.<\/p>\n<p>Quando implementamos cache para este\u00a0cen\u00e1rio, a primeira solicita\u00e7\u00e3o obt\u00e9m os dados a partir do banco de dados e os mant\u00e9m em mem\u00f4ria, a partir da segunda solicita\u00e7\u00e3o o servidor de aplica\u00e7\u00e3o ir\u00e1 buscar estes dados em mem\u00f3ria e retornar para a aplica\u00e7\u00e3o cliente, em outra palavras a aplica\u00e7\u00e3o tocou o\u00a0banco de dados apenas uma \u00fanica vez.<\/p>\n<p>A combina\u00e7\u00e3o\u00a0entre o gerenciamento de mem\u00f3ria do DataSnap, DBXReader e ClientDataSet\u00a0\u00e9 o que\u00a0voc\u00ea\u00a0precisa para implementar\u00a0uma solu\u00e7\u00e3o\u00a0de cache.<\/p>\n<p>O gerenciamento\u00a0de mem\u00f3ria do DataSnap\u00a0\u00e9\u00a0definido atrav\u00e9s do componente\u00a0DSServerClass e sua respectiva propriedade LifeCycle,\u00a0que\u00a0voc\u00ea pode ser definida como:<\/p>\n<ul>\n<li>Server \u2192 O servidor mant\u00e9m uma \u00fanica inst\u00e2ncia da classe no server, todos os clientes ao solicitar essa classe receber\u00e3o sempre a mesma inst\u00e2ncia (Singleton)<\/li>\n<li>Session \u2192 O servidor mant\u00e9m uma inst\u00e2ncia da classe por sess\u00e3o do DataSnap, cada cliente recebe uma inst\u00e2ncia diferente da classe (Statefull)<\/li>\n<li>Invocation \u2192 A cada execu\u00e7\u00e3o de um server method uma inst\u00e2ncia da classe ser\u00e1 criada e logo depois destru\u00edda (Stateless), voc\u00ea pode intervir no processo de cria\u00e7\u00e3o e destrui\u00e7\u00e3o desta classe a partir do servidor.<\/li>\n<\/ul>\n<p>Vamos ver como podemos implementar uma solu\u00e7\u00e3o de cache usando o cen\u00e1rio onde terei que armazenar uma lista de estados, esta informa\u00e7\u00e3o est\u00e1 na tabela de STATE.<\/p>\n<p>A minha classe no servidor (ServerClass) foi criada a partir de um DSServerModule e se chama TDMDataSet5, cont\u00e9m dois m\u00e9todos privados (private) e um p\u00fablico (public), que s\u00e3o:<\/p>\n<pre class=\"brush: delphi\">private\r\n   function GetRecords(Fields, Table: String): TDBXReader;\r\n   function GetData(Cds : TClientDataSet; Fields, Table: String) : TDBXReader;\r\npublic\r\n   function GetState: TDBXReader;<\/pre>\n<p>O m\u00e9todo GetRecords ir\u00e1 consultar o banco de dados e retornar os registros como um DBXReader, este m\u00e9todo n\u00e3o implementa nenhuma l\u00f3gica para verificar se o cache j\u00e1 est\u00e1 preenchido.<\/p>\n<pre class=\"brush: delphi\">function TDMDataSet5.GetRecords(Fields, Table: String): TDBXReader;\r\nvar\r\n    cmd: TDBXCommand;\r\nbegin\r\n\r\n    cmd := DMServerContainer.GetConnection.DBXConnection.CreateCommand;\r\n    try\r\n      cmd.Text := 'Select ' + Fields + ' from ' + Table;\r\n      Result := cmd.ExecuteQuery;\r\n    except\r\n      raise;\r\n    end;\r\nend;<\/pre>\n<p>Como o DBXReader \u00e9 unidirecional n\u00e3o podemos manter os dados em mem\u00f3ria, a solu\u00e7\u00e3o para isso \u00e9 copiar os dados e mant\u00ea-los em um ClientDataSet.<\/p>\n<p>GetData \u00e9 um m\u00e9todo interno respons\u00e1vel por criar, manter e retornar os dados como DBXReader.<\/p>\n<p>Conforme a implementa\u00e7\u00e3o abaixo o m\u00e9todo ir\u00e1 obter os dados a partir do banco de dados (GetRecords) somente se o ClientDataSet n\u00e3o est\u00e1 ativo, em outras palavras n\u00f3s nunca tivemos os dados em cache e somente iremos executar este c\u00f3digo uma \u00fanica vez. Ap\u00f3s o bloco do IF a classe TDBXDataSetReader ir\u00e1 copiar os dados do ClientDataSet para um DBXReader e retorn\u00e1-lo.<\/p>\n<pre class=\"brush: delphi\">function TDMDataSet5.GetData(Cds: TClientDataSet; Fields, Table: String): TDBXReader;\r\nvar\r\n    Reader : TDBXReader;\r\nbegin\r\n    if not Cds.Active then \/\/ Not active means, never move the data to ClientDataSet \u2013 no cache\r\n      begin\r\n      Reader := GetRecords(Fields, Table);\r\n      TDBXDataSetReader.CopyReaderToClientDataSet( Reader, Cds );\r\n      Reader.Free;\r\n      Cds.Open;\r\n    end;\r\n\r\n    Result := TDBXDataSetReader.Create(Cds, False (* InstanceOwner *) );\r\nend;<\/pre>\n<p>Voc\u00ea pode estar se perguntando por que estou copiando os dados do ClientDataSet para DBXReader e n\u00e3o retornando diretamente o ClientDataSet, duas raz\u00f5es:<\/p>\n<ul>\n<li>N\u00e3o \u00e9 poss\u00edvel fazer o marshal\/unmarshal de ClientDataSet para um objeto JSON<\/li>\n<li>DataSnap converte DBXReader em JSON quando o server methods \u00e9 chamado a partir de uma interface REST.<\/li>\n<\/ul>\n<p>Um ponto importante, o DSServerModule TDMDataSet5 ir\u00e1 gerenciar o cache, se o LifeCycle para esta classe for definido como server isso ir\u00e1 significar uma \u00fanica inst\u00e2ncia do cache para todos os clientes, podemos chamar isso de &#8220;cache global&#8221;, caso defina como Session estaremos criando um cache para cada cliente conectado ao servidor.<\/p>\n<p>Caso a sua aplica\u00e7\u00e3o cliente utilize o DBXClient ir\u00e1 receber um DBXReader a partir da execu\u00e7\u00e3o do server method, a partir dai \u00e9 sua responsabilidade decidir o que fazer com os dados, mas sendo necess\u00e1rio conectar estes dados a componentes data-aware ser\u00e1 necess\u00e1rio copiar os dados do DBXReader para um ClientDataSet, o m\u00e9todo TDBXDataSetReader.CopyReaderToClientDataSet \u00e9 a solu\u00e7\u00e3o pra isso.<\/p>\n<pre class=\"brush: delphi\">   TDBXDataSetReader.CopyReaderToClientDataSet(Reader, CDSCity);<\/pre>\n<p>Se algum dados relacionado com a tabela State mudar ser\u00e1 necess\u00e1rio implementar um server method para atualizar os dados. Al\u00e9m disso, ao definir o LifeCycle como Server o cache ser\u00e1 destru\u00eddo no momento que o servidor parar (Stop), mas se utilizamos o LifeCycle Session o cache ser\u00e1 destru\u00eddo no momento em que a aplica\u00e7\u00e3o cliente se desconecta do server.<\/p>\n<p>Usando esta t\u00e9cnica voc\u00ea garante que o cache no servidor n\u00e3o depende da implementa\u00e7\u00e3o do lado cliente, al\u00e9m disso quero lembrar que essa solu\u00e7\u00e3o ir\u00e1 funcionar como DataSnap Servers, se voc\u00ea implementou o server usando DataSnap REST Interface voc\u00ea n\u00e3o ter\u00e1 cache, porque cada solicita\u00e7\u00e3o ao server funciona como o lifecycle invocation.<\/p>\n<p>Este \u00e9 um exemplo realista que explica como implementar cache em servidores DataSnap usando dados a partir de um banco de dados como exemplo, al\u00e9m disso, voc\u00ea aprendeu como mover dados de\/para ClientDataSet de\/para DBXReader.<\/p>\n<p>O download do c\u00f3digo fonte utilizado como exemplo <a href=\"http:\/\/cc.embarcadero.com\/download.aspx?id=28243\">est\u00e1 dispon\u00edvel aqui<\/a>, veja a unit DataSetDM5.pas (Servidor) e FormDataSet5 (Cliente).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>O gerenciamento de mem\u00f3ria do DataSnap \u00e9 muito\u00a0poderoso e\u00a0uma caracter\u00edstica chave\u00a0para a implementa\u00e7\u00e3o de cache.\u00a0Imagine\u00a0o cen\u00e1rio onde a aplica\u00e7\u00e3o cliente solicita os mesmos dados milhares de vezes durante o dia, certamente teremos que tocar o banco de dados a cada solicita\u00e7\u00e3o. Vamos supor que\u00a0esses dados\u00a0n\u00e3o\u00a0mudam com muita\u00a0freq\u00fc\u00eancia, por exemplo: tabela de pa\u00edses, estados ou\u00a0cidades. Quando [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1456,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_s2mail":"yes","footnotes":""},"categories":[16,102],"tags":[173,23,181],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v16.2 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Cache de dados em servidores DataSnap com Delphi XE e C++Builder XE<\/title>\n<meta name=\"description\" content=\"Saiba como explorar o gerenciamento de mem\u00f3ria do DataSnap para implementar cache de dados no servidor utilizando Delphi XE ou C++Builder XE\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Cache de dados em servidores DataSnap com Delphi XE e C++Builder XE\" \/>\n<meta property=\"og:description\" content=\"Saiba como explorar o gerenciamento de mem\u00f3ria do DataSnap para implementar cache de dados no servidor utilizando Delphi XE ou C++Builder XE\" \/>\n<meta property=\"og:url\" content=\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/\" \/>\n<meta property=\"og:site_name\" content=\"Andreano Lanusse | Tecnologia e Desenvolvimento de Software\" \/>\n<meta property=\"article:published_time\" content=\"2011-03-29T03:38:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2014-03-04T04:55:26+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/07\/Icon_Delphi_CBuilder.png\" \/>\n\t<meta property=\"og:image:width\" content=\"340\" \/>\n\t<meta property=\"og:image:height\" content=\"170\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@andreanolanusse\" \/>\n<meta name=\"twitter:site\" content=\"@andreanolanusse\" \/>\n<meta name=\"twitter:label1\" content=\"Est. tempo de leitura\">\n\t<meta name=\"twitter:data1\" content=\"5 minutos\">\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#website\",\"url\":\"http:\/\/www.andreanolanusse.com\/pt\/\",\"name\":\"Andreano Lanusse | Tecnologia e Desenvolvimento de Software\",\"description\":\"Andreano Lanusse blog - artigos, tutoriais e v&iacute;deos sobre tecnologia, desenvolvimento de software (Delphi XE4, C#, PHP, .NET) e t&eacute;cnicas de programa&ccedil;&atilde;o\",\"publisher\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#\/schema\/person\/620bd05e81598c3aba4781796cbe8903\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"http:\/\/www.andreanolanusse.com\/pt\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#primaryimage\",\"inLanguage\":\"pt-BR\",\"url\":\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/07\/Icon_Delphi_CBuilder.png\",\"contentUrl\":\"http:\/\/www.andreanolanusse.com\/pt\/wp-content\/uploads\/2011\/07\/Icon_Delphi_CBuilder.png\",\"width\":340,\"height\":170},{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#webpage\",\"url\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/\",\"name\":\"Cache de dados em servidores DataSnap com Delphi XE e C++Builder XE\",\"isPartOf\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#website\"},\"primaryImageOfPage\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#primaryimage\"},\"datePublished\":\"2011-03-29T03:38:27+00:00\",\"dateModified\":\"2014-03-04T04:55:26+00:00\",\"description\":\"Saiba como explorar o gerenciamento de mem\\u00f3ria do DataSnap para implementar cache de dados no servidor utilizando Delphi XE ou C++Builder XE\",\"breadcrumb\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"item\":{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/\",\"url\":\"http:\/\/www.andreanolanusse.com\/pt\/\",\"name\":\"In\\u00edcio\"}},{\"@type\":\"ListItem\",\"position\":2,\"item\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#webpage\"}}]},{\"@type\":\"Article\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#article\",\"isPartOf\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#webpage\"},\"author\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#\/schema\/person\/620bd05e81598c3aba4781796cbe8903\"},\"headline\":\"Implementando cache de dados em servidores DataSnap\",\"datePublished\":\"2011-03-29T03:38:27+00:00\",\"dateModified\":\"2014-03-04T04:55:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#webpage\"},\"commentCount\":8,\"publisher\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#\/schema\/person\/620bd05e81598c3aba4781796cbe8903\"},\"image\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#primaryimage\"},\"keywords\":[\"C++Builder\",\"DataSnap\",\"Delphi\"],\"articleSection\":[\"C++Builder\",\"Delphi\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"http:\/\/www.andreanolanusse.com\/pt\/implementando-cache-de-dados-em-servidores-datasnap\/#respond\"]}]},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#\/schema\/person\/620bd05e81598c3aba4781796cbe8903\",\"name\":\"Andreano Lanusse\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#personlogo\",\"inLanguage\":\"pt-BR\",\"url\":\"http:\/\/0.gravatar.com\/avatar\/6a9c6f73c7c480fb826c7303288abfd3?s=96&d=mm&r=g\",\"contentUrl\":\"http:\/\/0.gravatar.com\/avatar\/6a9c6f73c7c480fb826c7303288abfd3?s=96&d=mm&r=g\",\"caption\":\"Andreano Lanusse\"},\"logo\":{\"@id\":\"http:\/\/www.andreanolanusse.com\/pt\/#personlogo\"},\"sameAs\":[\"https:\/\/twitter.com\/andreanolanusse\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/posts\/1262"}],"collection":[{"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/comments?post=1262"}],"version-history":[{"count":0,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/posts\/1262\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/media\/1456"}],"wp:attachment":[{"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/media?parent=1262"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/categories?post=1262"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.andreanolanusse.com\/pt\/wp-json\/wp\/v2\/tags?post=1262"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}