Italian community of Lazarus and Free Pascal

Programmazione => Databases => Topic aperto da: tito_livio - Novembre 27, 2019, 01:27:40 am

Titolo: Lavorare in rete
Inserito da: tito_livio - Novembre 27, 2019, 01:27:40 am
Buongiorno,
con le nuove versioni di Lazarus ho questo problema:
Ho due applicazioni Lazarus: A e B che lavorano sulla stessa tabella mysql che chiamo attesa.
Uso come componente tsqlquery.
Quando B modifica attesa basta che nell'altra applicazione, A, eseguo   attesa.refresh   oppure   attesa.close; attesa.open,   ed i cambamenti sono visibili.
Fin qui tutto normale, e la versione di Lazarus che uso è 0.9.30.2 ed ha funzionato per lunghi anni.
Lo so, è una vecchia versione e volendo usarne una nuova ho installato la versione 2.0.6 e ricompilato i progetti.
Con questa versione però, l'applicazione A, quella che dovrebbe leggere i cambiamenti, legge sempre gli stessi record, il risultato della query non cambia.
Per "vedere" i cambiamenti devo chiudere e rieseguire A. Ho lo stesso problema anche con una versione intermedia: 1.6.
I sorgenti sono gli stessi, ho solo ricompilato con la nuova versione.
La query di A è questa:

select * from attesa
where chiamato='1'
order by data_chiamata desc, ora_chiamata desc

Cosa sbaglio?
Penso che molti di voi avranno affrontato il problema dell'uso concorrente di una tabella, in questo caso mysql ma dovrebbe essere lo stesso per firebird o altri dbms.

Vi ringrazio per l'attenzione
Titolo: Re:Lavorare in rete
Inserito da: xinyiman - Novembre 27, 2019, 09:23:06 am
Mi sembra di ricordare che si tratta di qualche livello di isolamento della transazione. Ora non posso controllare il mio codice. Ma se hai fretta e vuoi evitare di chiudere il programma la soluzione più grezza ma sicuramente efficace è chiudere e riaprire la connessione. Poi sarebbe utile sapere se:
usi ApplyUpdate dopo aver fatto degli update sul database. Se esegui il commit o il commitretaining, se hai impostato qualche valore non di default sul connettore. L'ideale sarebbe sempre fornire un esempio che replica il problema, in modo che possiamo analizzarlo e velocizzare l'isolamento del problema.
Titolo: Re:Lavorare in rete
Inserito da: tito_livio - Novembre 27, 2019, 02:50:19 pm
Grazie Xinyiman per la risposta, ti confermo che chiudendo e riaprendo la connessione funziona. C'è lo svantaggio che aprire e chiudere la connessione prende un po' di tempo in più rispetto a chiudere ed aprire la tabella (si nota). Inoltre, qui va bene perche il progetto è piccolo ma con progetti con diverse tabelle aperte diventa più complicato.
Uso ApplyUpdate e commitretaining e nella connessione imposto giusto il minimo indispensabile, cioè setto le proprietà: DatabaseName, HostName, Password, Transaction e UserName.

Allego un progettino di esempio dove tramite una DbGrid si possono modificare i contenuti della tabella. Ci sono poi due bottoni: Salva e Aggiorna.
Io l'ho compilato con Lazarus V1.6.
Basta lanciare il programma due volte (due istanze), se da uno si modifica e si clicca  "Salva", dall'altro, anche se si clicca "Aggiorna", le modifiche non appaiono a meno di chiudere e riaprire il programma.
Nell'esempio vanno riempite le proprietà HostName,Password,Username di mysqlconnection con i propri dati.
Grazie di nuovo.
Titolo: Re:Lavorare in rete
Inserito da: xinyiman - Novembre 28, 2019, 08:12:00 am
Ciao tito_livio. Allora ieri sera ho fatto una piccola prova cambiando il connettore. Ho usato sqlite perchè a casa non ho installato mysql. Ho usato lazarus trunk version e ha funzionato correttamente. Prova a compilare anche tu usando la trunk version di lazarus. Se anche così non ti funziona installerò mysql a casa e proverò con quel connettore cercando la differenza.
Titolo: Re:Lavorare in rete
Inserito da: Stilgar - Novembre 28, 2019, 10:20:43 am
Ciao.Se il refresh() non funziona, prova il resync(..).
Fammi sapere
Stilgar
Titolo: Re:Lavorare in rete
Inserito da: xinyiman - Novembre 29, 2019, 08:30:57 am
Ciao tito_livio. Ieri sera ho provato a fare delle prove a casa ed effettivamente si comporta come segnali tu (mysql 8 su ubuntu 18.10).
Sono sempre più convinto che sia un problema di isolation level. Con zeoslib saprei come risolvere ma con i componenti standard no. Infatti ho aperto un 3d sul forum internazionale:

https://forum.lazarus.freepascal.org/index.php/topic,47580.0.html

Così vediamo di estendere la richiesta d'aiuto ad una platea più ampia.
Titolo: Re:Lavorare in rete
Inserito da: tito_livio - Novembre 29, 2019, 11:26:33 pm
Ciao ragazzi,
ho provato con resync e non funziona ugualmente.
Buona l'idea di mettere il problema sul forum internazionale.
Forse funzionerebbe "distruggendo" l'oggetto sqlquery e ricreandolo, però sinceramente non so come si fa.
Titolo: Re:Lavorare in rete
Inserito da: Stilgar - Novembre 29, 2019, 11:44:56 pm
Se hai bisogno di ricreare l'oggetto,
grossomodo dovresti procedere più o meno in questo ordine.
1) definisci la query la tieni in una stringa (magari in una costante).
2) crei un oggetto TQuery quando ti serve.
3) lo agganci ad un datasource (se devi collegare dei componenti visuali alla query)
4) Attivi la query.
5) Distruggi la query quando non ti seve più.
Stilgari
Titolo: Re:Lavorare in rete
Inserito da: xinyiman - Dicembre 01, 2019, 12:34:01 pm
Visto la risposta sul forum internazionale? Devi chiudere e riaprire sia la query che la transaction.
Titolo: Re:Lavorare in rete
Inserito da: Diego1981 - Dicembre 02, 2019, 09:27:14 am
Ciao Tito
io ho trovato lo stesso problema usando zeos ed ho risolto settando "tiReadCommitted" nel "transacisolationlevel" della ZConnection...spero ti sia utile
Ciauz
Titolo: Re:Lavorare in rete
Inserito da: xinyiman - Dicembre 02, 2019, 10:04:07 am
Diego1981 infatti è quello che ho detto anche io dall'inizio, mi sembra un problema di livello d'isolamento della transazione. Su zeos si sistema come dici tu, ma per quanto riguarda i componenti standard non ho trovato la soluzione. Penso che chiudendo e riaprendo la transazione oltre che la query il problema si risolva.
Titolo: Re:Lavorare in rete
Inserito da: tito_livio - Dicembre 03, 2019, 12:46:43 pm
Ciao a tutti, ho trovato una soluzione, il problema si è risolto cambiando il tipo di tabella da InnoDB a MyIsam. MyIsam è molto più veloce ed è il tipo di tabella Mysql che adotto di solito, quindi per me va bene, per chi usa invece InnoDB il problema rimane.

Credo sia un problema di gestione delle transazioni, gestione modificata nelle ultime versioni di Lazarus.
Sempre rimanendo con la tabella di tipo InnoDB, ho provato le soluzioni consigliate, sia qui che sul forum internazionale, ma purtroppo non rivolvono il problema, ecco perché:

1)Chiudere la transazione non funziona, i record rimangono sempre uguali. Inoltre chiudere la transazione implica la chiusura  di tutte le tabelle, quindi non è una soluzione applicabile. In un progetto per un programma di solito ci sono molte tabelle aperte, chiuderle e riaprirle tutte, per aggiornarne solo una, diventa problematico e rallenta il programma.
Da considerare inoltre che il componenente SQLTransaction non ha un metodo "close", io l'ho chiuso così:
 
  attesa.close;
  sqltransaction1.Active:=false;
  sqltransaction1.active:=true;
  attesa.open

2)Distruggere il componente SQLQuery non è praticabile, vanno ridefinite troppe proprietà: database, sql, campi usati, campo indice, eventuali parametri usati, ecc.

3)Usare commit anzichè commitretaining non va bene, perchè commit chiude tutte le tabelle della connessione.

4)L'unica soluzione che non ho provato è quella di Diego1981, dovrei usare Zeos che fino ad adesso non ho usato perchè mi sono trovato benissimo con i componenti standard.

Comunque grazie per l'aiuto.
Titolo: Re:Lavorare in rete
Inserito da: xinyiman - Dicembre 03, 2019, 01:34:20 pm
A questo punto presumo che sia un bug. Mi sa che va segnalato sul bugtracker di free pascal.
Titolo: Re:Lavorare in rete
Inserito da: tito_livio - Dicembre 06, 2019, 11:28:30 am
Il bug lo segnali tu? Vorrei sapere cosa ti rispondono.
Grazie e ciao.
Titolo: Re:Lavorare in rete
Inserito da: xinyiman - Dicembre 07, 2019, 11:27:48 am
Segnalato: https://bugs.freepascal.org/view.php?id=36404

Speriamo qualcuno risponda velocemente.
Titolo: Re:Lavorare in rete
Inserito da: xinyiman - Dicembre 09, 2019, 08:46:20 am
Risposta ottenuta
Citazione
This is normal. Refreshing does not refresh the transaction.

You must do a
SQLTransaction1.commit;
SQLTransaction1.starttransaction;
before opening/closing or refreshing the dataset in the Button2Click/Button3Click.
Titolo: Re:Lavorare in rete
Inserito da: tito_livio - Dicembre 09, 2019, 08:47:07 pm
Funziona ma "SQLTransaction1.commit" chiude tutte le tabelle della connessione.
Ho trovato però che in questo modo aggiorna e non chiude le tabelle:

sqltransaction1.CommitRetaining;
attesa.refresh;   

oppure

sqltransaction1.CommitRetaining;
attesa.close;
attesa.open;

In questo modo il problema si può considerare risolto anche per le tabelle di tipo InnoDB.   
Titolo: Re:Lavorare in rete
Inserito da: nomorelogic - Dicembre 10, 2019, 04:58:36 pm
prima del commit della transazione devi fare un

Table1.ApplyUpdates(0);

Per il fatto che la transazione chiude tutte le tabelle, puoi fare 2 transazioni: una per la lettura (che lasci sempre aperta) ed una per la scrittura.

Altrimenti CommitRetaining