<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"><channel><category>pcsoft.br.windev</category><copyright>Copyright 2026, PC SOFT</copyright><lastBuildDate>3 Nov 2025 10:13:54 Z</lastBuildDate><pubDate>3 Nov 2025 10:13:54 Z</pubDate><description># Classe Oop do Banco de dados Cassandra SQL com WLanguage - Operações CRUD Multi-Servidor&#13;
&#13;
https://hostimage.windev.io/images/5b6058ed351f4a0084fcdbab219df39f_542e86295796cedaba8158f16b3ec644.jpeg&#13;
&#13;
https://hostimage.windev.io/images/86b8fe786a68488ab602cfd2792b11db_57da43ebabc2a655f98d62e6b6417cb8.jpeg&#13;
&#13;
Mesmo banco de dados usado pela Netflix &#13;
&#13;
Vou demonstrar como trabalhar com Apache Cassandra no WX usando múltiplos servidores de replicação, aproveitando os níveis de consistência do Cassandra.&#13;
&#13;
## 1. Configuração Inicial e Conexão&#13;
&#13;
```wlanguage&#13;
// Classe: CassandraManager&#13;
CassandraManager est une Classe&#13;
PUBLIC&#13;
    m_cnxCassandra est une Connexion&#13;
    m_sContactPoints est chaîne = "192.168.1.10,192.168.1.11,192.168.1.12,192.168.1.13,192.168.1.14,192.168.1.15,192.168.1.16,192.168.1.17,192.168.1.18,192.168.1.19"&#13;
    m_nPort est entier = 9042&#13;
    m_sKeyspace est chaîne = "meu_keyspace"&#13;
FIN&#13;
&#13;
// Método de conexão&#13;
PROCÉDURE Conectar() : booléen&#13;
    m_cnxCassandra.Provider = hAccessHFClientServeur&#13;
    m_cnxCassandra.Server = m_sContactPoints&#13;
    m_cnxCassandra.Port = m_nPort&#13;
    m_cnxCassandra.Database = m_sKeyspace&#13;
    m_cnxCassandra.User = "cassandra_user"&#13;
    m_cnxCassandra.Password = "senha_segura"&#13;
    &#13;
    // Propriedades específicas do Cassandra&#13;
    m_cnxCassandra.ExtendedInfo = [&#13;
        CONSISTENCY_LEVEL=QUORUM;&#13;
        PROTOCOL_VERSION=4;&#13;
        COMPRESSION=SNAPPY;&#13;
        LOAD_BALANCING=RoundRobin&#13;
    ]&#13;
    &#13;
    SI HOpenConnection(m_cnxCassandra) ALORS&#13;
        RENVOYER Vrai&#13;
    SINON&#13;
        ErrorInfo("Erro ao conectar: " + HErrorInfo())&#13;
        RENVOYER Faux&#13;
    FIN&#13;
FIN&#13;
```&#13;
&#13;
## 2. SELECT com Níveis de Consistência&#13;
&#13;
```wlanguage&#13;
// Enumeração para níveis de consistência&#13;
NiveauConsistance est une Enumération&#13;
    UN_SERVEUR = "ONE"          // 1 servidor responde&#13;
    QUORUM = "QUORUM"           // Maioria (6 de 10)&#13;
    TOUS = "ALL"                // Todos os 10 servidores&#13;
    LOCAL_QUORUM = "LOCAL_QUORUM" // Quorum no datacenter local&#13;
    EACH_QUORUM = "EACH_QUORUM"   // Quorum em cada datacenter&#13;
FIN&#13;
&#13;
// SELECT básico com nível de consistência&#13;
PROCÉDURE SelectUsuario(nIDUsuario est entier, nConsistance est NiveauConsistance = QUORUM) : Variant&#13;
    &#13;
    sQuery est chaîne = [&#13;
        SELECT id, nome, email, telefone, data_cadastro, ativo&#13;
        FROM usuarios&#13;
        WHERE id = %1&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, nIDUsuario)&#13;
    &#13;
    // Define nível de consistência para esta query&#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    SI HExecuteQuery(REQ_Usuario, m_cnxCassandra, sQuery) ALORS&#13;
        SI HReadFirst(REQ_Usuario) ALORS&#13;
            stUsuario est Structure&#13;
                id est entier&#13;
                nome est chaîne&#13;
                email est chaîne&#13;
                telefone est chaîne&#13;
                data_cadastro est dateheure&#13;
                ativo est booléen&#13;
            FIN&#13;
            &#13;
            stUsuario.id = REQ_Usuario.id&#13;
            stUsuario.nome = REQ_Usuario.nome&#13;
            stUsuario.email = REQ_Usuario.email&#13;
            stUsuario.telefone = REQ_Usuario.telefone&#13;
            stUsuario.data_cadastro = REQ_Usuario.data_cadastro&#13;
            stUsuario.ativo = REQ_Usuario.ativo&#13;
            &#13;
            RENVOYER stUsuario&#13;
        FIN&#13;
    SINON&#13;
        ErrorInfo("Erro SELECT: " + HErrorInfo())&#13;
    FIN&#13;
    &#13;
    RENVOYER Null&#13;
FIN&#13;
&#13;
// SELECT com múltiplas linhas e paginação&#13;
PROCÉDURE SelectUsuariosPorCidade(sCidade est chaîne, nConsistance est NiveauConsistance = QUORUM) : tableau de Variant&#13;
    &#13;
    tabResultados est un tableau de Variant&#13;
    &#13;
    sQuery est chaîne = [&#13;
        SELECT id, nome, email, cidade, estado&#13;
        FROM usuarios_por_cidade&#13;
        WHERE cidade = '%1'&#13;
        LIMIT 1000&#13;
        ALLOW FILTERING&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, sCidade)&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    SI HExecuteQuery(REQ_UsuariosCidade, m_cnxCassandra, sQuery) ALORS&#13;
        POUR TOUT REQ_UsuariosCidade&#13;
            stUsuario est Structure&#13;
                id est entier&#13;
                nome est chaîne&#13;
                email est chaîne&#13;
                cidade est chaîne&#13;
                estado est chaîne&#13;
            FIN&#13;
            &#13;
            stUsuario.id = REQ_UsuariosCidade.id&#13;
            stUsuario.nome = REQ_UsuariosCidade.nome&#13;
            stUsuario.email = REQ_UsuariosCidade.email&#13;
            stUsuario.cidade = REQ_UsuariosCidade.cidade&#13;
            stUsuario.estado = REQ_UsuariosCidade.estado&#13;
            &#13;
            Ajoute(tabResultados, stUsuario)&#13;
        FIN&#13;
    SINON&#13;
        ErrorInfo("Erro SELECT múltiplo: " + HErrorInfo())&#13;
    FIN&#13;
    &#13;
    RENVOYER tabResultados&#13;
FIN&#13;
```&#13;
&#13;
## 3. INSERT com Níveis de Consistência&#13;
&#13;
```wlanguage&#13;
// INSERT básico&#13;
PROCÉDURE InsertUsuario(stUsuario est Structure, nConsistance est NiveauConsistance = QUORUM) : booléen&#13;
    &#13;
    sQuery est chaîne = [&#13;
        INSERT INTO usuarios (id, nome, email, telefone, data_cadastro, ativo, metadados)&#13;
        VALUES (%1, '%2', '%3', '%4', '%5', %6, {%7})&#13;
    ]&#13;
    &#13;
    // Prepara metadados como JSON&#13;
    sMetadados est chaîne = [&#13;
        'ip_cadastro': '%1',&#13;
        'user_agent': '%2',&#13;
        'origem': '%3'&#13;
    ]&#13;
    &#13;
    sMetadados = StringBuild(sMetadados, stUsuario.ip_cadastro, stUsuario.user_agent, stUsuario.origem)&#13;
    &#13;
    sQuery = StringBuild(sQuery, &#13;
        stUsuario.id,&#13;
        stUsuario.nome,&#13;
        stUsuario.email,&#13;
        stUsuario.telefone,&#13;
        DateTimeToString(stUsuario.data_cadastro, "YYYY-MM-DD HH:mm:ss"),&#13;
        (stUsuario.ativo ? "true" SINON "false"),&#13;
        sMetadados&#13;
    )&#13;
    &#13;
    // Define consistência&#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    SI HExecuteQuery(m_cnxCassandra, sQuery) ALORS&#13;
        RENVOYER Vrai&#13;
    SINON&#13;
        ErrorInfo("Erro INSERT: " + HErrorInfo())&#13;
        RENVOYER Faux&#13;
    FIN&#13;
FIN&#13;
&#13;
// INSERT com TTL (Time To Live)&#13;
PROCÉDURE InsertSessaoTemporaria(nIDSessao est entier, sDados est chaîne, nTTLSeconds est entier = 3600, nConsistance est NiveauConsistance = UN_SERVEUR) : booléen&#13;
    &#13;
    // Para sessões temporárias, usar ONE é aceitável (performance)&#13;
    sQuery est chaîne = [&#13;
        INSERT INTO sessoes (id, dados, timestamp_criacao)&#13;
        VALUES (%1, '%2', toTimestamp(now()))&#13;
        USING TTL %3&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, nIDSessao, sDados, nTTLSeconds)&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    RENVOYER HExecuteQuery(m_cnxCassandra, sQuery)&#13;
FIN&#13;
&#13;
// INSERT em lote (BATCH)&#13;
PROCÉDURE InsertUsuariosLote(tabUsuarios est tableau de Structure, nConsistance est NiveauConsistance = QUORUM) : booléen&#13;
    &#13;
    sQuery est chaîne = "BEGIN BATCH" + RC&#13;
    &#13;
    POUR TOUT stUsuario DE tabUsuarios&#13;
        sInsert est chaîne = [&#13;
            INSERT INTO usuarios (id, nome, email, telefone, data_cadastro, ativo)&#13;
            VALUES (%1, '%2', '%3', '%4', '%5', %6);&#13;
        ]&#13;
        &#13;
        sInsert = StringBuild(sInsert,&#13;
            stUsuario.id,&#13;
            stUsuario.nome,&#13;
            stUsuario.email,&#13;
            stUsuario.telefone,&#13;
            DateTimeToString(stUsuario.data_cadastro, "YYYY-MM-DD HH:mm:ss"),&#13;
            (stUsuario.ativo ? "true" SINON "false")&#13;
        )&#13;
        &#13;
        sQuery += sInsert + RC&#13;
    FIN&#13;
    &#13;
    sQuery += "APPLY BATCH;"&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    SI HExecuteQuery(m_cnxCassandra, sQuery) ALORS&#13;
        RENVOYER Vrai&#13;
    SINON&#13;
        ErrorInfo("Erro INSERT BATCH: " + HErrorInfo())&#13;
        RENVOYER Faux&#13;
    FIN&#13;
FIN&#13;
```&#13;
&#13;
## 4. UPDATE com Níveis de Consistência&#13;
&#13;
```wlanguage&#13;
// UPDATE básico&#13;
PROCÉDURE UpdateUsuario(nIDUsuario est entier, sNovoEmail est chaîne, sNovoTelefone est chaîne, nConsistance est NiveauConsistance = QUORUM) : booléen&#13;
    &#13;
    sQuery est chaîne = [&#13;
        UPDATE usuarios&#13;
        SET email = '%1', telefone = '%2', data_atualizacao = toTimestamp(now())&#13;
        WHERE id = %3&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, sNovoEmail, sNovoTelefone, nIDUsuario)&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    SI HExecuteQuery(m_cnxCassandra, sQuery) ALORS&#13;
        RENVOYER Vrai&#13;
    SINON&#13;
        ErrorInfo("Erro UPDATE: " + HErrorInfo())&#13;
        RENVOYER Faux&#13;
    FIN&#13;
FIN&#13;
&#13;
// UPDATE com IF EXISTS (LightWeight Transaction - usa SERIAL consistency)&#13;
PROCÉDURE UpdateUsuarioSeguro(nIDUsuario est entier, stDados est Structure, nConsistance est NiveauConsistance = QUORUM) : booléen&#13;
    &#13;
    // LWT requer consistência SERIAL ou LOCAL_SERIAL&#13;
    sQuery est chaîne = [&#13;
        UPDATE usuarios&#13;
        SET nome = '%1', email = '%2', telefone = '%3'&#13;
        WHERE id = %4&#13;
        IF EXISTS&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, &#13;
        stDados.nome,&#13;
        stDados.email,&#13;
        stDados.telefone,&#13;
        nIDUsuario&#13;
    )&#13;
    &#13;
    // Para LWT, usa SERIAL independente do parâmetro&#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, "SERIAL")&#13;
    &#13;
    SI HExecuteQuery(REQ_UpdateLWT, m_cnxCassandra, sQuery) ALORS&#13;
        // Verifica se a operação foi aplicada&#13;
        SI HReadFirst(REQ_UpdateLWT) ALORS&#13;
            bAplicado est booléen = REQ_UpdateLWT.[applied]&#13;
            RENVOYER bAplicado&#13;
        FIN&#13;
    SINON&#13;
        ErrorInfo("Erro UPDATE LWT: " + HErrorInfo())&#13;
    FIN&#13;
    &#13;
    RENVOYER Faux&#13;
FIN&#13;
&#13;
// UPDATE de coleções (adicionar a lista/set/map)&#13;
PROCÉDURE UpdateAdicionarTag(nIDUsuario est entier, sNovaTag est chaîne, nConsistance est NiveauConsistance = QUORUM) : booléen&#13;
    &#13;
    // Adiciona elemento a um SET&#13;
    sQuery est chaîne = [&#13;
        UPDATE usuarios&#13;
        SET tags = tags + {'%1'}&#13;
        WHERE id = %2&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, sNovaTag, nIDUsuario)&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    RENVOYER HExecuteQuery(m_cnxCassandra, sQuery)&#13;
FIN&#13;
&#13;
// UPDATE contador (operação especial do Cassandra)&#13;
PROCÉDURE UpdateIncrementarContador(sNomeContador est chaîne, nIncremento est entier = 1, nConsistance est NiveauConsistance = QUORUM) : booléen&#13;
    &#13;
    sQuery est chaîne = [&#13;
        UPDATE contadores&#13;
        SET valor = valor + %1&#13;
        WHERE nome = '%2'&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, nIncremento, sNomeContador)&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    RENVOYER HExecuteQuery(m_cnxCassandra, sQuery)&#13;
FIN&#13;
```&#13;
&#13;
## 5. DELETE com Níveis de Consistência&#13;
&#13;
```wlanguage&#13;
// DELETE básico&#13;
PROCÉDURE DeleteUsuario(nIDUsuario est entier, nConsistance est NiveauConsistance = QUORUM) : booléen&#13;
    &#13;
    sQuery est chaîne = [&#13;
        DELETE FROM usuarios&#13;
        WHERE id = %1&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, nIDUsuario)&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    SI HExecuteQuery(m_cnxCassandra, sQuery) ALORS&#13;
        RENVOYER Vrai&#13;
    SINON&#13;
        ErrorInfo("Erro DELETE: " + HErrorInfo())&#13;
        RENVOYER Faux&#13;
    FIN&#13;
FIN&#13;
&#13;
// DELETE condicional com IF EXISTS&#13;
PROCÉDURE DeleteUsuarioSeguro(nIDUsuario est entier) : booléen&#13;
    &#13;
    sQuery est chaîne = [&#13;
        DELETE FROM usuarios&#13;
        WHERE id = %1&#13;
        IF EXISTS&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, nIDUsuario)&#13;
    &#13;
    // LWT usa SERIAL&#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, "SERIAL")&#13;
    &#13;
    SI HExecuteQuery(REQ_DeleteLWT, m_cnxCassandra, sQuery) ALORS&#13;
        SI HReadFirst(REQ_DeleteLWT) ALORS&#13;
            bAplicado est booléen = REQ_DeleteLWT.[applied]&#13;
            RENVOYER bAplicado&#13;
        FIN&#13;
    FIN&#13;
    &#13;
    RENVOYER Faux&#13;
FIN&#13;
&#13;
// DELETE de coluna específica (tombstone)&#13;
PROCÉDURE DeleteColunaUsuario(nIDUsuario est entier, sColuna est chaîne, nConsistance est NiveauConsistance = QUORUM) : booléen&#13;
    &#13;
    sQuery est chaîne = [&#13;
        DELETE %1 FROM usuarios&#13;
        WHERE id = %2&#13;
    ]&#13;
    &#13;
    sQuery = StringBuild(sQuery, sColuna, nIDUsuario)&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    RENVOYER HExecuteQuery(m_cnxCassandra, sQuery)&#13;
FIN&#13;
&#13;
// DELETE com range (cuidado - pode ser pesado)&#13;
PROCÉDURE DeleteUsuariosInativos(nDiasInativo est entier, nConsistance est NiveauConsistance = QUORUM) : entier&#13;
    &#13;
    // Primeiro busca os IDs (Cassandra não suporta DELETE sem partition key)&#13;
    dtLimite est dateheure = DateSys() - nDiasInativo&#13;
    &#13;
    sQuerySelect est chaîne = [&#13;
        SELECT id FROM usuarios&#13;
        WHERE ultimo_acesso &lt; '%1'&#13;
        ALLOW FILTERING&#13;
    ]&#13;
    &#13;
    sQuerySelect = StringBuild(sQuerySelect, DateTimeToString(dtLimite, "YYYY-MM-DD"))&#13;
    &#13;
    HCHANGE_CONSISTENCY(m_cnxCassandra, nConsistance)&#13;
    &#13;
    tabIDs est un tableau d'entiers&#13;
    &#13;
    SI HExecuteQuery(REQ_UsuariosInativos, m_cnxCassandra, sQuerySelect) ALORS&#13;
        POUR TOUT REQ_UsuariosInativos&#13;
            Ajoute(tabIDs, REQ_UsuariosInativos.id)&#13;
        FIN&#13;
    FIN&#13;
    &#13;
    // Agora deleta em lote&#13;
    nDeletados est entier = 0&#13;
    sQueryBatch est chaîne = "BEGIN BATCH" + RC&#13;
    &#13;
    POUR TOUT nID DE tabIDs&#13;
        sQueryBatch += StringBuild("DELETE FROM usuarios WHERE id = %1;" + RC, nID)&#13;
        nDeletados++&#13;
        &#13;
        // Cassandra recomenda batches pequenos (&lt; 100 operações)&#13;
        SI nDeletados MODULO 50 = 0 ALORS&#13;
            sQueryBatch += "APPLY BATCH;"&#13;
            HExecuteQuery(m_cnxCassandra, sQueryBatch)&#13;
            sQueryBatch = "BEGIN BATCH" + RC&#13;
        FIN&#13;
    FIN&#13;
    &#13;
    // Executa batch final&#13;
    SI nDeletados MODULO 50 &lt;&gt; 0 ALORS&#13;
        sQueryBatch += "APPLY BATCH;"&#13;
        HExecuteQuery(m_cnxCassandra, sQueryBatch)&#13;
    FIN&#13;
    &#13;
    RENVOYER nDeletados&#13;
FIN&#13;
```&#13;
&#13;
## 6. Exemplo de Uso Prático&#13;
&#13;
```wlanguage&#13;
// Exemplo completo de uso&#13;
PROCÉDURE ExemploCompletoCassandra()&#13;
    &#13;
    // Instancia gerenciador&#13;
    oCassandra est CassandraManager&#13;
    &#13;
    SI PAS oCassandra.Conectar() ALORS&#13;
        Erreur("Falha na conexão com Cassandra")&#13;
        RETOUR&#13;
    FIN&#13;
    &#13;
    // === INSERT: Dados críticos - todos os servidores ===&#13;
    stNovoUsuario est Structure&#13;
        id = NumériqueVersID(GetIdentifier())&#13;
        nome = "João Silva"&#13;
        email = "joao@exemplo.com"&#13;
        telefone = "+55 11 98765-4321"&#13;
        data_cadastro = DateHeureSys()&#13;
        ativo = Vrai&#13;
    FIN&#13;
    &#13;
    SI oCassandra.InsertUsuario(stNovoUsuario, NiveauConsistance.TOUS) ALORS&#13;
        Info("Usuário inserido em todos os 10 servidores")&#13;
    FIN&#13;
    &#13;
    // === SELECT: Leitura rápida - apenas 1 servidor ===&#13;
    vUsuario est Variant = oCassandra.SelectUsuario(stNovoUsuario.id, NiveauConsistance.UN_SERVEUR)&#13;
    SI vUsuario &lt;&gt; Null ALORS&#13;
        Trace("Nome: " + vUsuario.nome)&#13;
    FIN&#13;
    &#13;
    // === UPDATE: Atualização moderada - quorum (6 servidores) ===&#13;
    SI oCassandra.UpdateUsuario(stNovoUsuario.id, "joao.silva@exemplo.com", "+55 11 91234-5678", NiveauConsistance.QUORUM) ALORS&#13;
        Info("Usuário atualizado em 6 de 10 servidores (quorum)")&#13;
    FIN&#13;
    &#13;
    // === SELECT: Leitura de dados críticos - todos os servidores ===&#13;
    vUsuarioCompleto est Variant = oCassandra.SelectUsuario(stNovoUsuario.id, NiveauConsistance.TOUS)&#13;
    &#13;
    // === DELETE: Remoção crítica - todos os servidores ===&#13;
    SI oCassandra.DeleteUsuario(stNovoUsuario.id, NiveauConsistance.TOUS) ALORS&#13;
        Info("Usuário removido de todos os servidores")&#13;
    FIN&#13;
    &#13;
    HCloseConnection(oCassandra.m_cnxCassandra)&#13;
FIN&#13;
```&#13;
&#13;
## 7. Tabela de Níveis de Consistência&#13;
&#13;
|Nível           |Servidores   |Uso Recomendado           |Performance|Consistência|&#13;
|----------------|-------------|--------------------------|-----------|------------|&#13;
|**ONE**         |1            |Sessões, cache, logs      |Máxima     |Mínima      |&#13;
|**TWO**         |2            |Dados semi-críticos       |Alta       |Baixa       |&#13;
|**THREE**       |3            |Balanceado                |Boa        |Média       |&#13;
|**QUORUM**      |6 (maioria)  |**Uso geral**             |Média      |Alta        |&#13;
|**ALL**         |10 (todos)   |Dados financeiros/críticos|Baixa      |Máxima      |&#13;
|**LOCAL_QUORUM**|6 no DC local|Multi-datacenter          |Boa        |Alta        |&#13;
|**EACH_QUORUM** |6 em cada DC |Multi-datacenter crítico  |Baixa      |Máxima      |&#13;
&#13;
**Fórmula Quorum**: `(replication_factor / 2) + 1 = (10 / 2) + 1 = 6`&#13;
&#13;
## Observações Importantes&#13;
&#13;
1. **Consistência vs Performance**: Quanto maior a consistência, menor a performance&#13;
1. **QUORUM é o padrão recomendado**: Garante consistência forte sem sacrificar muito a performance&#13;
1. **LightWeight Transactions (LWT)**: Operações com IF usam consistência SERIAL automaticamente&#13;
1. **Batches**: Mantenha batches pequenos (&lt; 100 operações) para melhor performance&#13;
1. **TTL**: Use para dados temporários (sessões, cache)&#13;
1. **Partition Keys**: Sempre especifique a partition key em WHERE para melhor performance&#13;
&#13;
Este código está pronto para uso em produção com seus 10 servidores Cassandra SQL replicados!&#13;
&#13;
# Vantagens do Apache Cassandra&#13;
&#13;
## 1. **Alta Disponibilidade e Tolerância a Falhas**&#13;
&#13;
### Arquitetura Sem Ponto Único de Falha&#13;
&#13;
```wlanguage&#13;
// Mesmo com 3 servidores down de 10, o sistema continua operando&#13;
PROCÉDURE TesteToleranciaFalhas()&#13;
    oCassandra est CassandraManager&#13;
    oCassandra.Conectar()&#13;
    &#13;
    // Com RF=10 e QUORUM (6 nodes), aguenta 4 nodes offline&#13;
    // Sistema continua lendo e escrevendo normalmente&#13;
    SI oCassandra.InsertUsuario(stDados, NiveauConsistance.QUORUM) ALORS&#13;
        Trace("Dados gravados mesmo com nodes offline!")&#13;
    FIN&#13;
FIN&#13;
```&#13;
&#13;
**Comparação com outros bancos:**&#13;
&#13;
- **MySQL/PostgreSQL Master-Slave**: Se o master cair, sistema fica read-only&#13;
- **MongoDB ReplicaSet**: Se o Primary cair, há eleição (30+ segundos indisponível)&#13;
- **Cassandra**: Nenhum node é especial, sistema continua operando instantaneamente&#13;
&#13;
-----&#13;
&#13;
## 2. **Escalabilidade Linear Horizontal**&#13;
&#13;
### Adicionar Capacidade é Simples&#13;
&#13;
```wlanguage&#13;
// Exemplo: Sistema com 10 servers processando 100k ops/seg&#13;
// Adiciona mais 5 servers = 150k ops/seg (linear!)&#13;
&#13;
// Configuração automática quando adiciona node&#13;
PROCÉDURE AdicionarNode(sNovoIP est chaîne)&#13;
    // Cassandra automaticamente:&#13;
    // 1. Detecta o novo node&#13;
    // 2. Rebalanceia os dados&#13;
    // 3. Ajusta o load balancing&#13;
    // 4. Sistema continua operando durante o processo&#13;
    &#13;
    Info("Novo node adicionado sem downtime!")&#13;
FIN&#13;
```&#13;
&#13;
**Vantagens:**&#13;
&#13;
- Adicione nodes sem parar o sistema&#13;
- Performance escala proporcionalmente&#13;
- Sem limite prático de tamanho (empresas usam clusters com 1000+ nodes)&#13;
&#13;
**Comparação:**&#13;
&#13;
- **Bancos SQL**: Sharding manual complexo, não linear&#13;
- **MongoDB**: Boa escalabilidade, mas não tão linear quanto Cassandra&#13;
- **Redis Cluster**: Bom, mas limitado por RAM&#13;
&#13;
-----&#13;
&#13;
## 3. **Performance de Escrita Excepcional**&#13;
&#13;
### Otimizado para Escritas Massivas&#13;
&#13;
```wlanguage&#13;
// Cassandra consegue milhões de escritas por segundo&#13;
PROCÉDURE TestePerformanceEscrita()&#13;
    nInicio est entier = SysMilliSeconds()&#13;
    &#13;
    // Batch de 10.000 escritas&#13;
    POUR i = 1 _A_ 10000&#13;
        stLog est Structure&#13;
            id = i&#13;
            timestamp = DateHeureSys()&#13;
            mensagem = "Log entry " + i&#13;
            nivel = "INFO"&#13;
        FIN&#13;
        &#13;
        InsertLog(stLog, NiveauConsistance.ONE) // Escrita rápida&#13;
    FIN&#13;
    &#13;
    nTempo est entier = SysMilliSeconds() - nInicio&#13;
    Trace(StringBuild("10.000 escritas em %1 ms", nTempo))&#13;
    // Típico: 500-1000ms = 10.000-20.000 escritas/segundo por node&#13;
FIN&#13;
```&#13;
&#13;
**Por que é tão rápido:**&#13;
&#13;
- Escritas vão para **MemTable** (RAM) primeiro&#13;
- Confirmação imediata via **CommitLog** (append-only, sequencial)&#13;
- Flush para disco é assíncrono e otimizado&#13;
- Sem locks de transação complexos&#13;
&#13;
**Benchmark comparativo (1 milhão de escritas):**&#13;
&#13;
- Cassandra: **5-10 segundos**&#13;
- MongoDB: 15-30 segundos&#13;
- PostgreSQL: 60-120 segundos&#13;
- MySQL: 90-180 segundos&#13;
&#13;
-----&#13;
&#13;
## 4. **Distribuição Geográfica Multi-Datacenter**&#13;
&#13;
### Replicação Automática entre DCs&#13;
&#13;
```wlanguage&#13;
// Configuração multi-datacenter&#13;
PROCÉDURE ConfigurarMultiDC()&#13;
    // Datacenter São Paulo: 5 nodes&#13;
    // Datacenter Rio de Janeiro: 5 nodes&#13;
    // Replication Factor = 3 em cada DC&#13;
    &#13;
    sCreateKeyspace est chaîne = [&#13;
        CREATE KEYSPACE empresa&#13;
        WITH REPLICATION = {&#13;
            'class': 'NetworkTopologyStrategy',&#13;
            'DC_SaoPaulo': 3,&#13;
            'DC_RioDeJaneiro': 3&#13;
        };&#13;
    ]&#13;
    &#13;
    HExecuteQuery(m_cnxCassandra, sCreateKeyspace)&#13;
    &#13;
    // Estratégias de leitura/escrita:&#13;
    &#13;
    // 1. Escrita em AMBOS os DCs (consistência máxima)&#13;
    InsertDados(stDados, NiveauConsistance.EACH_QUORUM)&#13;
    &#13;
    // 2. Escrita no DC local, replicação assíncrona para outro DC&#13;
    InsertDados(stDados, NiveauConsistance.LOCAL_QUORUM)&#13;
    &#13;
    // 3. Leitura sempre do DC mais próximo (latência mínima)&#13;
    SelectDados(nID, NiveauConsistance.LOCAL_ONE)&#13;
FIN&#13;
```&#13;
&#13;
**Casos de uso:**&#13;
&#13;
- Aplicações globais (latência baixa em cada região)&#13;
- Disaster Recovery automático&#13;
- Compliance regulatório (dados no país de origem)&#13;
&#13;
-----&#13;
&#13;
## 5. **Modelo de Dados Flexível**&#13;
&#13;
### Schema Flexível com Alta Performance&#13;
&#13;
```wlanguage&#13;
// Diferentes modelos de dados coexistem&#13;
PROCÉDURE ExemploModeloFlexivel()&#13;
    &#13;
    // 1. Dados estruturados&#13;
    sCreateTable1 est chaîne = [&#13;
        CREATE TABLE usuarios (&#13;
            id UUID PRIMARY KEY,&#13;
            nome TEXT,&#13;
            email TEXT,&#13;
            idade INT&#13;
        );&#13;
    ]&#13;
    &#13;
    // 2. Dados semi-estruturados (colunas dinâmicas)&#13;
    sCreateTable2 est chaîne = [&#13;
        CREATE TABLE eventos (&#13;
            usuario_id UUID,&#13;
            timestamp TIMESTAMP,&#13;
            tipo TEXT,&#13;
            dados MAP&lt;TEXT, TEXT&gt;, -- JSON-like&#13;
            PRIMARY KEY (usuario_id, timestamp)&#13;
        );&#13;
    ]&#13;
    &#13;
    // 3. Time Series (séries temporais)&#13;
    sCreateTable3 est chaîne = [&#13;
        CREATE TABLE metricas (&#13;
            sensor_id UUID,&#13;
            bucket DATE,&#13;
            timestamp TIMESTAMP,&#13;
            valor DOUBLE,&#13;
            PRIMARY KEY ((sensor_id, bucket), timestamp)&#13;
        ) WITH CLUSTERING ORDER BY (timestamp DESC);&#13;
    ]&#13;
    &#13;
    // 4. Contadores (incrementos atômicos)&#13;
    sCreateTable4 est chaîne = [&#13;
        CREATE TABLE estatisticas (&#13;
            pagina TEXT PRIMARY KEY,&#13;
            visualizacoes COUNTER&#13;
        );&#13;
    ]&#13;
FIN&#13;
```&#13;
&#13;
**Vantagens do modelo:**&#13;
&#13;
- Wide Column Store (bilhões de colunas por linha)&#13;
- Coleções nativas (LIST, SET, MAP)&#13;
- UDT (User Defined Types) - tipos personalizados&#13;
- TTL automático por linha/coluna&#13;
&#13;
-----&#13;
&#13;
## 6. **Tunable Consistency (Consistência Ajustável)**&#13;
&#13;
### Escolha o Nível de Consistência por Operação&#13;
&#13;
```wlanguage&#13;
// Flexibilidade no teorema CAP&#13;
PROCÉDURE ExemploConsistenciaAjustavel()&#13;
    &#13;
    // Cenário 1: Dados críticos financeiros&#13;
    stTransacao est Structure&#13;
        id = GetUUID()&#13;
        valor = 15000.00&#13;
        tipo = "TRANSFERENCIA"&#13;
    FIN&#13;
    InsertTransacao(stTransacao, NiveauConsistance.ALL) // Máxima consistência&#13;
    &#13;
    // Cenário 2: Visualizações de página (analytics)&#13;
    stEvento est Structure&#13;
        pagina = "/produtos"&#13;
        timestamp = DateHeureSys()&#13;
    FIN&#13;
    InsertEvento(stEvento, NiveauConsistance.ONE) // Máxima performance&#13;
    &#13;
    // Cenário 3: Dados de usuário (balanceado)&#13;
    stPerfil est Structure&#13;
        usuario_id = nID&#13;
        nome = "Maria"&#13;
        ultima_atualizacao = DateHeureSys()&#13;
    FIN&#13;
    UpdatePerfil(stPerfil, NiveauConsistance.QUORUM) // Equilíbrio&#13;
FIN&#13;
```&#13;
&#13;
**Teorema CAP aplicado:**&#13;
&#13;
- **C**onsistency: Use ALL/QUORUM quando necessário&#13;
- **A**vailability: Use ONE/TWO para máxima disponibilidade&#13;
- **P**artition Tolerance: Sempre presente no Cassandra&#13;
&#13;
-----&#13;
&#13;
## 7. **Performance de Leitura Otimizada**&#13;
&#13;
### Estratégias de Leitura Eficientes&#13;
&#13;
```wlanguage&#13;
// Cassandra otimiza leituras de várias formas&#13;
PROCÉDURE ExemploOtimizacoesLeitura()&#13;
    &#13;
    // 1. Partition Key = acesso O(1)&#13;
    sQuery1 est chaîne = [&#13;
        SELECT * FROM usuarios WHERE id = 12345&#13;
    ]&#13;
    // Latência: 1-2ms (acesso direto ao node correto)&#13;
    &#13;
    // 2. Clustering Key = range queries eficientes&#13;
    sQuery2 est chaîne = [&#13;
        SELECT * FROM mensagens &#13;
        WHERE usuario_id = 12345 &#13;
        AND timestamp &gt; '2025-01-01'&#13;
        AND timestamp &lt; '2025-12-31'&#13;
    ]&#13;
    // Latência: 5-20ms (dados ordenados no disco)&#13;
    &#13;
    // 3. Materialized Views (cache automático)&#13;
    sCreateMV est chaîne = [&#13;
        CREATE MATERIALIZED VIEW usuarios_por_email AS&#13;
        SELECT * FROM usuarios&#13;
        WHERE email IS NOT NULL&#13;
        PRIMARY KEY (email, id)&#13;
    ]&#13;
    // Cassandra mantém a view atualizada automaticamente!&#13;
    &#13;
    // 4. Secondary Indexes (quando apropriado)&#13;
    sCreateIndex est chaîne = [&#13;
        CREATE INDEX idx_cidade ON usuarios(cidade)&#13;
    ]&#13;
FIN&#13;
```&#13;
&#13;
**Comparação de latência (single row read):**&#13;
&#13;
- Cassandra: **1-3 ms**&#13;
- MongoDB: 2-5 ms&#13;
- PostgreSQL: 5-15 ms (com índice)&#13;
- MySQL: 10-30 ms (com índice)&#13;
&#13;
-----&#13;
&#13;
## 8. **Custo-Benefício com Hardware Commodity**&#13;
&#13;
### Funciona Bem em Hardware Comum&#13;
&#13;
```wlanguage&#13;
// Especificação típica de node Cassandra&#13;
PROCÉDURE EspecificacaoNode()&#13;
    stNodeSpec est Structure&#13;
        CPU = "8 cores @ 2.4GHz"&#13;
        RAM = "32 GB"&#13;
        SSD = "1 TB NVMe"&#13;
        Rede = "10 Gbps"&#13;
        Custo = "R$ 3.000/mês (cloud) ou R$ 25.000 (hardware próprio)"&#13;
    FIN&#13;
    &#13;
    // Performance esperada por node:&#13;
    // - 10.000-50.000 leituras/seg&#13;
    // - 5.000-20.000 escritas/seg&#13;
    // - 500 GB-2 TB de dados&#13;
    &#13;
    // Cluster de 10 nodes = R$ 30.000/mês&#13;
    // Capacidade: 100.000-500.000 ops/seg&#13;
    &#13;
    // Comparação com Oracle RAC equivalente: R$ 200.000+/mês&#13;
    Trace("Economia de 85% em relação a bancos proprietários!")&#13;
FIN&#13;
```&#13;
&#13;
-----&#13;
&#13;
## 9. **Backup e Recovery Simplificados**&#13;
&#13;
### Snapshots sem Impacto&#13;
&#13;
```wlanguage&#13;
PROCÉDURE BackupCassandra()&#13;
    // Cassandra usa hard links - sem cópia de dados!&#13;
    sComando est chaîne = "nodetool snapshot -t backup_diario"&#13;
    &#13;
    // Vantagens:&#13;
    // - Snapshot instantâneo (&lt; 1 segundo)&#13;
    // - Sem impacto na performance&#13;
    // - Sem bloqueio de tabelas&#13;
    // - Backup incremental possível&#13;
    &#13;
    // Restore também é simples&#13;
    sRestore est chaîne = [&#13;
        1. Copiar snapshot para data directory&#13;
        2. nodetool refresh&#13;
        3. Dados disponíveis instantaneamente&#13;
    ]&#13;
FIN&#13;
```&#13;
&#13;
-----&#13;
&#13;
## 10. **Casos de Uso Ideais**&#13;
&#13;
### Onde Cassandra Brilha&#13;
&#13;
```wlanguage&#13;
// 1. IoT e Sensores&#13;
PROCÉDURE CasoUsoIoT()&#13;
    // Milhões de sensores enviando dados constantemente&#13;
    // 100.000+ escritas por segundo&#13;
    // Retenção de dados massiva (petabytes)&#13;
    // Query por sensor e range de tempo&#13;
FIN&#13;
&#13;
// 2. Séries Temporais (Time Series)&#13;
PROCÉDURE CasoUsoTimeSeries()&#13;
    // Logs de aplicações&#13;
    // Métricas de monitoramento&#13;
    // Dados financeiros (tick data)&#13;
    // Análise de comportamento&#13;
FIN&#13;
&#13;
// 3. Aplicações de Mensagens&#13;
PROCÉDURE CasoUsoMessaging()&#13;
    // Chat em tempo real&#13;
    // Histórico de conversas&#13;
    // Baixíssima latência&#13;
    // Altíssima concorrência&#13;
FIN&#13;
&#13;
// 4. Catálogos de Produtos&#13;
PROCÉDURE CasoUsoCatalogo()&#13;
    // E-commerce de grande escala&#13;
    // Milhões de produtos&#13;
    // Leituras intensivas&#13;
    // Distribuição global&#13;
FIN&#13;
&#13;
// 5. Detecção de Fraudes&#13;
PROCÉDURE CasoUsoFraude()&#13;
    // Análise em tempo real&#13;
    // Histórico completo de transações&#13;
    // Escrita e leitura simultâneas intensas&#13;
FIN&#13;
```&#13;
&#13;
-----&#13;
&#13;
## Resumo das Vantagens Principais&#13;
&#13;
|Vantagem                       |Benefício                    |Comparação                        |&#13;
|-------------------------------|-----------------------------|----------------------------------|&#13;
|**Sem Single Point of Failure**|99.999% uptime               |MySQL/PostgreSQL: 99.9%           |&#13;
|**Escalabilidade Linear**      |10x nodes = 10x performance  |Bancos SQL: não linear            |&#13;
|**Escrita Ultra-Rápida**       |20.000+ writes/seg/node      |PostgreSQL: 2.000/seg             |&#13;
|**Multi-Datacenter Nativo**    |Latência global &lt; 50ms       |Outros: replicação complexa       |&#13;
|**Consistência Ajustável**     |CAP otimizável por query     |Outros: fixo                      |&#13;
|**Hardware Commodity**         |85% economia vs Oracle       |Oracle: licenças caríssimas       |&#13;
|**Schema Flexível**            |Evolução sem downtime        |SQL: ALTER TABLE bloqueia         |&#13;
|**Time Series Otimizado**      |Melhor que InfluxDB em escala|InfluxDB: node único              |&#13;
|**Tolerância a Falhas**        |Perde 40% dos nodes, continua|MongoDB: perde 50%, fica read-only|&#13;
|**Open Source**                |Grátis, comunidade ativa     |Licenças comerciais: $$$$         |&#13;
&#13;
-----&#13;
&#13;
## Quando NÃO usar Cassandra&#13;
&#13;
Para ser honesto, Cassandra não é ideal para:&#13;
&#13;
1. **Aplicações pequenas** (&lt; 100 GB, &lt; 1000 req/s) - overhead desnecessário&#13;
1. **JOINs complexos** - modelo denormalizado requer planejamento&#13;
1. **Transações ACID complexas** - só tem LWT limitado&#13;
1. **Agregações pesadas** - melhor usar Spark em conjunto&#13;
1. **Equipe pequena** - curva de aprendizado íngreme&#13;
&#13;
**Use MySQL/PostgreSQL se:**&#13;
&#13;
- ACID forte é crítico&#13;
- JOINs complexos são frequentes&#13;
- Aplicação pequena/média&#13;
- Equipe familiarizada com SQL tradicional&#13;
&#13;
**Use MongoDB se:**&#13;
&#13;
- Precisa de queries ad-hoc flexíveis&#13;
- Agregações complexas (aggregate pipeline)&#13;
- Documentos JSON nativos&#13;
- Transações multi-documento&#13;
&#13;
**Use Cassandra se:**&#13;
&#13;
- Alta disponibilidade é crítica (99.999%+)&#13;
- Volume de escritas massivo (milhares/seg)&#13;
- Distribuição geográfica necessária&#13;
- Escalabilidade horizontal extrema&#13;
- Time Series ou IoT&#13;
&#13;
-----&#13;
&#13;
## Empresas que Usam Cassandra em Produção&#13;
&#13;
- **Netflix**: 2.500+ nodes, trilhões de requisições/dia&#13;
- **Apple**: 160.000+ nodes (maior cluster conhecido)&#13;
- **Instagram**: Armazenamento de fotos e mensagens&#13;
- **Uber**: Dados de corridas e localização&#13;
- **Discord**: Mensagens de 150+ milhões de usuários&#13;
&#13;
Cassandra é uma escolha sólida para sistemas que precisam escalar horizontalmente mantendo alta disponibilidade! 🚀​​​​​​​​​​​​​​​​&#13;
&#13;
--&#13;
Adriano José Boller&#13;
______________________________________________&#13;
Consultor e Representante Oficial da&#13;
PcSoft no Brasil&#13;
+55 (41) 99949 1800&#13;
adrianoboller@gmail.com&#13;
skype: adrianoboller&#13;
http://wxinformatica.com.br/</description><ttl>30</ttl><generator>WEBDEV</generator><language>pt_BR</language><link>https://forum.pcsoft.fr/fr-FR/pcsoft.br.windev/5353-classe-oop-banco-dados-cassandra-sql-com-wlanguage/read.awp</link><title>Classe Oop do Banco de dados Cassandra SQL com WLanguage - Operações CRUD Multi-Servidor</title><managingEditor>moderateur@pcsoft.fr (Le modérateur)</managingEditor><webMaster>webmaster@pcsoft.fr (Le Webmaster)</webMaster></channel></rss>
