Sincronizzare database locale e remoto

di il
10 risposte

Sincronizzare database locale e remoto

Buongiorno, gradirei qualche suggerimento per implementare quanto vi descrivo.

Un programma Vb.Net gestisce, in un database Access, una tabella di anagrafiche personali e una tabella di eventi. Il programma permette di registrare, in una terza tabella, le persone presenti ad un certo evento.
La richiesta che ho ricevuto è di poter effettuare la registrazione dei presenti ad un evento tramite smartphone o tablet. Disponendo già di uno spazio web con MySql, la soluzione che mi è venuta in mente è quella di creare un database MySql con tabelle analoghe a quelle locali e, tramite un "operazione pianificata" di Windows, inviare via FTP due file csv estratti dalle due tabelle Access. Dal lato web, tramite un CronJob, una pagina PHP dovrebbe recuperare i due CSV ed allineare le tabelle MySql. 
Ho il sospetto (e la speranza) che esista un metodo più efficiente.
Grazie.

10 Risposte

  • Re: Sincronizzare database locale e remoto

    E perchè non lavori sul MySql direttamente sia smartphone sia da tablet ??
    Così non devi fare allineamenti e hai tutto in tempo reale.

    Se non puoi accedere al MySQL in modo “diretto” (non tutti i provider ti permettono di vedere il database dall'esterno), sullo spazio web basta un banalissimo file PHP (che se vuoi ti fornisco) che ti permette di inviare comandi SQL e di ricevere la risposta.

  • Re: Sincronizzare database locale e remoto

    Ciao SirJo, grazie.

    Evidentemente non ho spiegato bene la situazione. Il database principale è un database Access, locale, su cui agisce un programma gestionale. Ovviamente dall'esterno della rete locale non c'è nessuna possibilità di arrivare a questo DB, quindi devo replicare i suoi contenuti su un DB su web, per esempio un MySql su uno spazio web disponibile. L'allineamento avverrebbe così:

    1) Tramite un'operazione pianificata, quindi a intervalli prestabiliti, Il gestionale locale estrae dal DB Access i dati interessanti creando un paio di file CSV, poi effettua un upload via FTP verso una determinata cartella di un sito.

    2) Nel sito, un CronJob comanda l'esecuzione (anche questa a tempo) di uno script PHP che legge i file CSV e aggiorna il DB MySql.

    Questo è il meccanismo che ho messo in piedi e che tutto sommato funziona, ma mi chiedevo se esistesse un metodo meno tortuoso.

  • Re: Sincronizzare database locale e remoto

    28/03/2023 - grumpy ha scritto:


    Questo è il meccanismo che ho messo in piedi e che tutto sommato funziona, ma mi chiedevo se esistesse un metodo meno tortuoso.

    Il problema della tua richiesta è che non sono chiari i requisiti. Mi spiego: al netto che avrei evitato l'uso di un server FTP, magari facendo l'upload direttamente da una pagina Web o da una API, “metodi meno tortuosi” sono pressoché infiniti, ma non è detto che siano applicabili alla tua situazione per merito di tempo necessario all'implementazione, costi o altro.

    L'unica semplificazione che posso vedere, come predetto, è quella di modificare il programma attuale affinché chiami una API al posto di effettuare un upload via FTP, inviando direttamente i dati che sono da sincronizzare a una pagina PHP che li importa su MySQL, senza dover gestire entrambe le schedulazioni.

  • Re: Sincronizzare database locale e remoto

    Ciao Alka. L'upload via FTP in verità è piuttosto semplice grazie ai metodi offerti da .NET.  La parte insidiosa e anche meno affidabile è la sincronizzazione delle schedulazioni, come giustamente hai osservato.

     SOAP ?  REST ? Non ho alcuna esperienza in merito. Sarebbero strade  non troppo sanguinose?

  • Re: Sincronizzare database locale e remoto

    Scusa non mi sono spiegato bene.
    io proponevo di eliminare il file Access locale e lavorare tutto sul MySQL.
    Devi solo installare sul server un file PHP che ti permette di inviare/ricevere dati ed eseguire le chiamate al MySQL.
    Farai quindi le chiamate a questo file PHP sia da smartphone, sia da tablet, sia da PC.
    Non è proprio la soluzione API che propone Alka, ma è una soluzione comunque valida per i meno esperti.
    Puoi lavorare in https, puoi eventualmente crittografare i dati, ed è comunque prevista una password quasi OTP, per cui il livello di sicurezza è abbastanza alto.
    Io lo uso da anni e non ho mai avuto problemi

  • Re: Sincronizzare database locale e remoto

    28/03/2023 - grumpy ha scritto:


    L'upload via FTP in verità è piuttosto semplice grazie ai metodi offerti da .NET.

    Non mi riferivo alla complessità della programmazione, bensì nella tendenziale fallacia (se non gestita bene) di questa tipologia di server rispetto ad altre soluzioni più “dirette” (un po' come inviare mail massive via SMTP al giorno d'oggi: c'è di meglio).

    28/03/2023 - SirJo ha scritto:


    Farai quindi le chiamate a questo file PHP sia da smartphone, sia da tablet, sia da PC.
    Non è proprio la soluzione API che propone Alka, ma è una soluzione comunque valida per i meno esperti.

    Beh sì, grossomodo intendevo questa soluzione. Il cenno alla Web API era per fare riferimento a un “protocollo comune” e standardizzato, ma il colloquio con la pagina per trasferire i dati da inserire su MySQL lo si può realizzare in qualunque modo si voglia. :)

  • Re: Sincronizzare database locale e remoto

    28/03/2023 - SirJo ha scritto:



    io proponevo di eliminare il file Access locale e lavorare tutto sul MySQL.

    Beh, questo no. Lo scenario che ho descritto è solo a scopo esemplificativo, in realtà l'applicazione locale con Access è molto più complicata.

    Tuttavia è interessante quello che mi proponi perché mi permetterebbe di tenere allineato il DB remoto ad ogni variazione significativa del DB locale, anziché trasferire intere tabelle spesso inutilmente se non ci sono state modifiche ai dati. Puoi darmi maggiori riferimenti? 

  • Re: Sincronizzare database locale e remoto

    Premessa: il programma l'ho realizzato per utenti con conoscenze medio-basse, non è ottimizzato, utilizza il protocollo HTTP con chiamata GET (sarebbe meglio usare un POST o altri sistemi), per cui ben vengano commenti e suggerimenti, ma volevo tenere la cosa semplice da capire e quindi semplice da studiare per i newbie.

    Innanzitutto devi copiare il file execute.php (che ti allego di seguito) nel server dove è installato il database MySQL.

    Dentro a quel file, alla riga #13 devi impostare una password che vuoi tu.

    File execute.php:

    <?php
    
    // esegue un comando SQL (SELECT - UPDATE - DELETE - INSERT o altri)
    
    $sql = '';
    if (isset($_GET['sql'])) $sql = $_GET['sql'];
    
    $chk = '';
    if (isset($_GET['chk'])) $chk = $_GET['chk'];
    
    include('include/config.php');
    
    $md5 = md5("lamiapassword".$sql);
    if ($md5 != strtolower($chk)) {
    	echo "E\nErrore parametro CHK\nParametro CHK non corretto\n"; // 4 righe
    	return;
    }
    
    //avvio connessione al database
    $db = @new mysqli($mysql_host,$mysql_user,$mysql_password,$mysql_database);
    if ($db->connect_error) {
    	echo "E\nErrore connessione al database\n".$db->connect_error."\n"; // 4 righe
    	return;
    }
    $db->query("SET CHARACTER SET utf8");
    
    $rs = $db->query($sql);
    if ($rs === false) {
    	echo "E\nErrore query\n".$db->error."\n".$sql;
    	$db->close();
    	return;
    }
    
    // estraggo il comando base
    $cmd = strtoupper($sql);
    $vn = strpos($cmd, " ");
    if ($vn !== false) $cmd = substr($cmd, 0, $vn);
    
    switch ($cmd) {
    case "SELECT":
    	$nrs = mysqli_num_rows($rs); // record count
    	$lst = [];
    	for ($i = 0; $i < $nrs; $i++) { $lst[] = mysqli_fetch_assoc($rs); } // porto i risultati sull'array $lst
    	echo json_encode($lst);
    	break;
    case "UPDATE":
    	echo "K\n".$db->affected_rows;
    	break;
    case "DELETE":
    	echo "K\n";
    	break;
    case "INSERT":
    	echo "K\n".$db->insert_id;
    	break;
    default:
    	echo "K\n";
    }
    
    //@mysql_free_result($rs);
    $db->close();
    
    ?>
    

    Devi inoltre copiare il file config.php impostando tutti i parametri che sono necessari per il collegamento al server MySQL, eccolo qui:

    <?php
    $mysql_host = "98.26.109.66";  // oppure mettere localhost
    $mysql_database = "nome del database";
    $mysql_user = "nome utente";
    $mysql_password = "password del database";
    ?>
    

    Questo file è consigliato metterlo nella sotto cartella “include”, ma casomai modifica la linea #11 del file execute.php specificando la posizione corretta.

    Per fare una chiamata da VB.NET puoi usare ad esempio (ovviamente la password è da configurare):

        Public Function DBexecute(Sql As String) As String()
    
            Dim md5 As String = MD5Calc("lamiapassword" & Sql)
            Dim query As String = System.Web.HttpUtility.UrlEncode(Sql)
    
            Dim str As String = ""
            Dim wc As New WebClient
            wc.Encoding = Encoding.UTF8
    
            Try
                Dim cmd As String = "http://www.ilmioserver.it/execute.php?chk=" & md5 & "&sql=" & query
                str = wc.DownloadString(cmd)
            Catch ex As Exception
                Return New String() {"E", "ERRORE", "Mancata connessione al server", ""}
            End Try
    
            If str.StartsWith("E") Then
                Dim err As String() = str.Split(Convert.ToChar(10))
                Return New String() {"E", err(1), err(2), err(3)}
            End If
    
            If str.StartsWith("K") Then
                Return str.Split(Convert.ToChar(10))
            End If
    
            Return New String() {str}
    
        End Function
    

    La funzione esegue una chiamata al server dove c'è MySQL e ritorna un array di stringhe dove la prima stringa è il risultato dell'operazione.
    Se la prima stringa è “E”, c'è un errore, e le altre stringhe contengono l'errore, se è “K” è andato tutto ok.

    Per fare una SELECT puoi ad esempio fare:

            Dim ris = DBexecute("SELECT nome,corso from pt_allievi where sigla='AX01' order by nome")
    
            If ris(0) = "E" Then ' c'è un errore e lo visualizzo
                MessageBox.Show(ris(2), ris(1), MessageBoxButtons.OK, MessageBoxIcon.Error)
                Exit Sub
            End If
            
            ' in risposta ho un JSON
    
            If ris(0).Trim <> "null" And ris(0) <> "[]" Then
                ' risposta corretta, la analizzo
                Dim json = New JsonParser(ris(0))
                Dim ar = json.NextArray
                json = Nothing
                For Each ht As Hashtable In ar
                    ' ........ faccio quello che devo fare, ad esempio importare i dati in una DataTable 
                    ' per poi mostrarli su di una DataGridView o cose del genere
                Next
            End If
    

    oppure ad esempio una UPDATE

            Dim ris = DBexecute("UPDATE pt_autoscuole SET maxpren=4,piugiorno=1 where autoscuola='RM0001'")
    
            If ris(0) <> "K" Then
                MessageBox.Show(ris(2), ris(1), MessageBoxButtons.OK, MessageBoxIcon.Error)
                Me.Dispose()
                Exit Sub
            End If
    


    Per altre info chiedi pure
    Sergio

  • Re: Sincronizzare database locale e remoto

    Se ti serve eccoti la funzione MD5Calc

        Public Function MD5Calc(Txt As String) As String
    
            Dim md5 As New MD5CryptoServiceProvider
            Dim dati() As Byte = Encoding.UTF8.GetBytes(Txt)
            Dim hash() As Byte = md5.ComputeHash(dati)
    
            Dim sb As New StringBuilder
            For Each b As Byte In hash
                sb.Append(b.ToString("x02"))
            Next
            Return sb.ToString
    
        End Function
    
  • Re: Sincronizzare database locale e remoto

    OK SirJo, ho capito il metodo che mi suggerisci. Nei prossimi giorni vedrò come posso applicarlo al mio caso.

    Grazie.

Devi accedere o registrarti per scrivere nel forum
10 risposte