Notificar cliente quando houver alguma alteração no banco de dados

Olá. Eu estou fazendo uma aplicação em JavaFX, e quando eu acabar ela vou fazer uma versão para Android e outra pra IOS. Todas precisam compartilhar informações através de uma banco de dados Mysql, até aí tudo bem, mas o que me intriga é que cada um dos clientes precisa saber quando o outro fez alguma alteração em determinada tabela. No momento não é necessário se preocupar porque eu ainda estou criando o primeiro cliente, mas eu já notei a necessidade de algo do tipo porque enquanto se enquanto minha aplicação estiver rodando, eu fazer alguma alteração no banco de dados, a aplicação precisa saber que eu fiz isso.
Alguém tem alguma ideia de como fazer isso? Um trigger? Como faço para enviar essas informações para os clientes?

Existem algumas formas diferentes de fazer isso. Quão necessário é esse update? É em tempo real?

Você pode criar uma API (em Java ou em qualquer outra linguagem) para ser um ponto único de acesso ao banco de dados. Em outras palavras, todos os clientes vão acessar os dados através dessa API.

Dessa forma, você tem como saber quando as mudanças ocorrem, e pode notificar os clientes conectados. Vou te passar duas formas de fazer isso:

  1. Pooling: de tempos em tempos, o programa cliente consulta o servidor e verifica se há alguma alteração. Caso haja uma alteração, você baixa os dados novos e atualiza a interface.

    Vantagens: é simples de implementar
    Desvantagens: consultas o tempo inteiro podem rapidamente se tornar um problema de performance

  2. Socket: quando o usuário abre o cliente, uma conexão tcp é aberta entre o cliente e o servidor. O servidor deve manter as referências para as conexões de alguma forma que seja possível identificar quem é cada cliente. Dessa forma, toda vez que ocorre uma alteração, o servidor verifica se quem estaria possivelmente interessado naquela mudança está conectado, e envia uma notificação de atualização para os mesmos. Os clientes que recebem a notificação podem trabalhar de forma reativa, sendo que toda vez que chega uma notificação de atualização do servidor, eles devem baixar os novos dados.

    Vantagens: um pouco mais eficiente se bem implementado
    Desvantagens: complexo de se fazer, porém existem bibliotecas prontas que podem ajudar bastante, como Socket IO

Esse é um problema antigo, que não é muito simples de se resolver. Porém, há soluções propostas. Se você quiser saber mais sobre isso, procura livros sobre Sistemas Distribuídos.

Sim, tem que ser em tempo real, e são vários registros de várias tabelas que precisam ser atualizados.[quote=“lvbarbosa, post:2, topic:343653”]
Você pode criar uma API (em Java ou em qualquer outra linguagem) para ser um ponto único de acesso ao banco de dados. Em outras palavras, todos os clientes vão acessar os dados através dessa API.
[/quote]

Eu não preciso criar uma API, pois meu programa utiliza o modelo MVC. Quando eu for fazer para outras plataformas é só utilizar a mesma lógica na model não?

Dessa maneira pode até funcionar, mas como são muitos dados realmente iria resultar em um problema de performance. Além disso, como tu disse, essa verificação ocorre de tempos em tempos, dependendo desse “tempos em tempos” pode não ficar em tempo real.

É possível fazer isso no Mysql? Peço perdão pela ignorância, mas tenho pouca experiência em Java com redes.

Você está fazendo a aplicação para desktop com JavaFX, certo? O banco de dados é local?

Se você quer fazer a versão mobile e utilizar o mesmo banco de dados para todos os apps, você precisa necessariamente criar uma forma para distribuir a aplicação. Dessa forma, todos os clientes( O JavaFX, o iOS, o Android, o Browser, qualquer coisa) vão conectar na API para obter e enviar dados. As aplicações não devem conectar diretamente no banco de dados, isso pode gerar várias brechas de segurança e performance.

Todos esses problemas de sincronização somem se você faz tudo localmente no desktop, com apenas um cliente mexendo nos dados.

O ideal é construir uma camada em cima do banco de dados, com toda a lógica de negócio. Os clientes conectam nessa camada e são apenas uma especie de view.

Eu aposto que não, apesar de não ter certeza. Ficaria surpreso se soubesse que pode. Esse não é o propósito de um banco de dados. Essa lógica está muito mais relacionada ao negócio do que ao armazenamento de dados em si.

Essa que eu te falei é uma arquitetura bem utilizada hoje em dia. Na hora de fazer um sistema distribuido, ao invés de fazer um site e depois ficar tentando adaptar pra funcionar em mobile, criar desde o zero como uma API que pode ser utilizada universalmente.

Tá mas e a questão de notificar o cliente? Não tem como fazer um trigger para mandar uma mensagem por socket para os clientes conectados por exemplo?

Nativamente? Não. Porém, eu dei uma pesquisada aqui e parece que você pode chamar funções externas dentro de um trigger. Tem que implementar essas funções em C ou C++, então dá pra fazer qualquer coisa. Você vai ter que bolar um jeito de passar o ip e a porta do cliente para o MySQL, para que ele saiba qual cliente notificar.

Dá uma olhada aqui: https://dev.mysql.com/doc/refman/5.7/en/adding-udf.html

Eu acho que seria bem mais interessante implementar isso em uma camada à parte, na forma de uma API como conversamos antes, porque essas chamadas de rede podem ser bem custosas e comprometer a performance do DB. Mas depende do caso, as vezes numa aplicação pequena não faz tanta diferença.

Acho que não existe uma solução multiplataforma para notificar clientes que rodam em plataformas diferentes. Algumas plataformas mais modernas como iOS oferecem suporte a push notifications para clientes iOS e até para aplicações que rodam no browser da Apple, o Safari, mas outras plataformas antigas como Javafx, acho que não existe o conceito de ser notificado no desktop, existe? isso é algo que surgiu agora com mobile. Não me lembro de ter visto uma aplicação desktop ser notificada.

resumindo, seu backend vai ter que usar APIs diferentes pra notificar clientes de cada plataforma (iOS, Android) e algumas plataformas (JavaFX) simplesmente não existe API, vc vai ter que criar algum framework de notificações para os clientes Javafx.

Polling geralmente é suficiente para “tempo real”. Ex. O que o Donald Trump twita está disponível em “tempo real” para todos que acessam sua pagina no Twitter.

Bacana, vou estudar uma maneira de fazer assim. Vai demorar bastante porque eu só sei o básico do C, mas pode funcionar. Valeu pela dica.

Tem sim notificações no JavaFX, usando tray, na realidade é do AWT, mas eu tô usando. Eu não me importo de ter que fazer um sistema desses pra cada cliente, só preciso que funcione e não interfira na performance da aplicação e nem do banco.

É, mas se for muitas vezes pode gerar uma sobrecarga, e se for poucas pode não dar no “tempo real”, algo como verificar a cada segundo por exemplo (sem levar em conta o tempo de receber a resposta e interpretar).

Acredito que o tray é apenas um componente de interface gráfica (por isso o pacote AWT), e não um sistema de notificações que eu estou falando… que você vai precisar usar no backend pra enviar uma notificação para a aplicação javafx.

Acho que eu entendi. Tu quer dizer para eu encontrar uma maneira de trocar as informações entre os clientes sem utilizar o banco? Tipo, o cliente Android alterou determinado registro, daí ele manda pro cliente IOS e para o cliente desktop uma mensagem por TCP dizendo que algo foi alterado?

Não. Eles se comunicam apenas com um servidor no backend por meio de uma API. O backend então notifica os clientes por meio de APIs específicas pra cada plataforma.

Sim, mas essa comunicação teria que ser por algo como TCP não? Daí eu teria que ter uma tabela com os clientes ativos. Eu vou tentar desenvolver uma lógica desse tipo. Parece que assim não gera muito problema de performance, mas só testando todas as alternativas pra ver, eu vou fazer e depois eu volto e digo como foi.

Isso mesmo, o backend onde esta o banco de dados sabe quando tem alguma coisa pra enviar, ele então se comunica com os sistema de notificações, que é quem trata de entregar as notificações para os clientes.

Eu estou montando o sistema. Eu vou fazer assim: Eu tenho uma tabela com todos os dispositivos que estão usando os dados do usuário, nessa tabela tem também o IP. Eu vou criar um sistema de comunicação por socket em cada cliente. Se o cliente Android modificar por exemplo, ele vai mandar uma mensagem por socket para todos os ips de dipositivos que estão com um cliente aberto, então eles vão atualizar a lista deles. Até aí tudo bem, o problema é a alteração direto no banco. Eu vou criar uma função em C++ assim como o @lvbarbosa citou, e sempre quando eu fizer uma atualização direto no banco eu vou chamar ela, então uma mensagem por socket deve ser enviada a cada cliente ativo. Mas eu não estou conseguindo de maneira alguma criar essa função. @lvbarbosa você poderia me dar um exemplo de sintaxe?

Eu não tenho nem ideia de como é que se implementa a função pra utilizar dentro do MySQL, só dei uma lida por cima e te mandei o link. Pelo que eu vi ontem, existem algumas estruturas que você deve seguir (tem naquele link que mandei) para funcionar direitinho. Tem exemplos lá.

Mas falando de C++: não existe biblioteca de socket nativa em C++. Porém, você pode utilizar as bibliotecas do C (socket.h, no caso de sistemas UNIX) para fazer a comunicação. Se quiser, também pode utilizar alguma biblioteca feita para C++ (que por sua vez vai utilizar socket.h por baixo dos panos).

Não acho que vai ser tão simples você simplesmente manter uma tabela com os endereços IP dos clientes no banco de dados. Não é só IP e porta, tem uma série de outras coisas envolvidas. Se o cliente estiver atras de um NAT, por exemplo, você não vai conseguir acesso a ele diretamente, mas ele que tem que se conectar a você (servidor) que tem um IP público. Da pra configurar isso no roteador, mas aí você teria que obrigar cada cliente a mexer em seu roteador para poder receber atualizações.

Quando você utiliza os chamados “WebSockets” em uma API pública (pública no sentido de estar na Internet), é muito mais simples manter uma estrutura em memória com os sockets de cada cliente dentro da API do que ter isso no banco de dados. Com o socket do cliente em mãos (já aberto), é muito mais fácil efetuar a transmissão de dados, porque o roteador do cliente vai saber pra qual dispositivo mandar os pacotes, já que ele é o NAT.

Em contraste, pensando no C++ chamado pelo MySQL, você vai ter que abrir um socket com o cliente (e o cliente vai ter que estar esperando para receber uma conexão), ou então de alguma maneira acessar o FD (file descriptor) do socket que o cliente abriu.

Sinceramente, não tenho a menor ideia de como fazer isso. É uma abordagem muito complexa.

Você me falou antes que não entende muito de redes. Talvez tudo que eu falei aqui não tenha feito o menor sentido kkkkkkkk Dá uma estudada nisso que você vai entender o meu argumento!

Cara, eu não acho que precisa de tudo isso, eu estou fazendo um aplicação simples para gerenciar dados pessoais. Por hora eu só preciso que essa sincronização funcione, essas coisas eu vejo mais tarde. O sistema de comunicação entre os clientes está pronto (pelo menos no Java, depois eu faço outro para o Android e para o IOS), mas o que me intriga é quando eu faço alterações pelo Workbench por exemplo. Daí eu preciso desse trigger para notificar que o administrador alterou algo. Eu tentei implementar um exemplo que eu encontrei na internet mas deu só erro de sintaxe. Eu não encontrei nada de exemplo dessa sintaxe no link. Eu notei que tinha algo de errado já quando o Workbench não deixou azul o extern.

Será que algo como uma tabela temporária com as alterações serviria? Seria muita manutenção né?