Come replicare funzionalita 'generator' di altro db su MySql?

di il
13 risposte

Come replicare funzionalita 'generator' di altro db su MySql?

Sto passando i dati di alcune delle procedure software da Firebird a MySql

Su Firebird e' possibile definire dei ‘generator’ che sono sostanzialmente delle variabili permanenti che vengono incrementate ogni volta che vengono lette, quindi ad esempio se il generator di nome ‘codice_cliente’ attualmente e' a 100, la prima volta che eseguo una “select codice_cliente from generator” mi viene restituito 101, la seconda volta che eseguo la stessa lettura mi viene restituito 102 e cosi via

Sto tentando di ottenere una funzionalita' simile anche su MySql, ho creato una tabella ‘generator’ ho aggiunto un campo ‘codice_cliente’ ed assegnato un valore iniziale di 100

Poi ho tentato di creare un trigger per definire l'incremento del valore ‘codice_cliente’ ad ogni select ma vedo che non e' possibile definire l'esecuzione di un trigger su operazione di select, solamente su insert, update, delete

Quindi la domanda per la quale sto cercando il vostro aiuto e': come fare su MySql per ottenere lo stesso effetto dei 'generator' di Firebird ?

(attenzione che non e' possibile fare la lettura e l'immediata successiva scrittura per aggiornare il campo perche' rischierei che altri client leggano un valore ‘vecchio’ del campo ‘codice_cliente’, il valore un attimo prima dell'aggiornamento)

13 Risposte

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    https://www.mrw.it/mysql/modificare-auto-increment_12978.html

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    23/07/2023 - sihsandrea ha scritto:


    https://www.mrw.it/mysql/modificare-auto-increment_12978.html

    Cioe? Come faresti?

    Bisognerebbe inserire una nuova riga, poi andare a leggerne il valore ‘codice_cliente’ (definito come auto_increment) piu' alto?

    Se 10 client stanno facendo la stessa cosa, non sei sicuro che il valore letto sia quello hai appena incrementato tu, voglio dire se client1 avvia la procedura e poi client2 fa la stessa cosa, non e' detto che entrambi non leggano il valore ‘codice_cliente’ come incrementato da client2, e quindi leggono lo stesso valore

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    23/07/2023 - amorosik ha scritto:


    23/07/2023 - sihsandrea ha scritto:


    https://www.mrw.it/mysql/modificare-auto-increment_12978.html

    Cioe? Come faresti?

    Bisognerebbe inserire una nuova riga, poi andare a leggerne il valore ‘codice_cliente’ (definito come auto_increment) piu' alto?

    Se 10 client stanno facendo la stessa cosa, non sei sicuro che il valore letto sia quello hai appena incrementato tu, voglio dire se client1 avvia la procedura e poi client2 fa la stessa cosa, non e' detto che entrambi non leggano il valore ‘codice_cliente’ come incrementato da client2, e quindi leggono lo stesso valore

    Possono essere anche un miliardo… autoincrement lo inserisce mysql…

    Quel comando, come tua richiesta di voler cominciare da 100, ti fa cominciare da 100…

    Ma secondo te, cominciare da zero o da n, che sia mysql, firebird o vattelappescadb, cosa cambia?

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    Inizio da zero o 100 non cambia niente, non e' quello il punto

    Il punto e' che l'autoincrement funziona sull'insert di un nuovo record e quindi ti servono almeno due istruzioni per ‘leggere’ un nuovo ‘codice_cliente’

    Serve l'insert del nuovo record e poi serve la select con la quale vai a leggere il nuovo valore di ‘codice_cliente’

    E se da codice devo eseguire due operazioni per leggere il nuovo valore, allora e' possibile che qualcun altro abbia gia' avviato un'insert un attimo prima di me, e quando va a fare la select per leggere il nuovo valore, in realta' legge l'ultimo valore disponibile, che e' quello che sto attendendo anch'io

    Una roba del tipo

    Client1      Client2

    --------------------------

    Insert      

                    Insert

                   Select

    Select

    Ma potrebbe anche essere

    Client1      Client2

    --------------------------

    Insert      

                    Insert

    Select

                   Select

    Le due Select leggeranno comunque lo stesso valore, ed e' quello che non desidero ovviamente

    Oppure esiste una funzione unica che mi permetta di leggere e autoincrementare il valore 'codice_cliente' ?

    MariaDb 10.4.27

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    Manuale mysql

    https://www.google.com/url?sa=t&source=web&rct=j&opi=89978449&url=https://downloads.mysql.com/docs/administrator-it.pdf&ved=2ahUKEwjN2sD93KaAAxWJh_0HHTStB2YQFnoECA0QAQ&usg=AOvVaw08PZr6AzSyRXpWS0AY0ZV_

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    Ringrazio per il consiglio

    Avevo gia' letto il documento linkato, e non c'e' indicazione utile ai fini della soluzione problema posto

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    Prova a mettere in piedi questa soluzione.

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    24/07/2023 - Alka ha scritto:


    Prova a mettere in piedi questa soluzione.

    Si, credo che l'esempio del  GetSequenceVal   sia quello che fa per me

    Causalmente vedo anche un “.. SEQUENCES like it works on firebird:..”   

    Molte grazie

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    24/07/2023 - amorosik ha scritto:


    Il punto e' che l'autoincrement funziona sull'insert di un nuovo record e quindi ti servono almeno due istruzioni per ‘leggere’ un nuovo ‘codice_cliente’

    Serve l'insert del nuovo record e poi serve la select con la quale vai a leggere il nuovo valore di ‘codice_cliente’

    E se da codice devo eseguire due operazioni per leggere il nuovo valore, allora e' possibile che qualcun altro abbia gia' avviato un'insert un attimo prima di me, e quando va a fare la select per leggere il nuovo valore, in realta' legge l'ultimo valore disponibile, che e' quello che sto attendendo anch'io

    Ma tu hai provato in modo empirico a fare due insert e vedere come mysql gestisce l'indice? O pensi che un sito con mysql dove tutto il mondo inserisce ordini va in palla con un id autoincrement?

    Che significa fai l'insert e poi la select?

    L'id non viene rilasciato finché non fai il post. A che ti serve fare la select? 

    Da codice non andrai a mettere nessun id ci pensa mysql.

    Esempio parti da zero, fai nuovo record, ci ripensi e annulli, rifai insert, ci ripensi e annulli, così per 10 volte.

    Il contatore è ancora a zero.

    Tu stai solo istruendo di inserire un record, che verrà confermato su update o post. Prima di allora, se annulli l'inserimento il contatore non va avanti perché ye lo ritrovi in locale in attesa di essere inviato al db.

    Fai anche questa prova:

    Leggi l'ultimo id, fai una insert (avrai id+1) senza dare post e con la insert ancora aperta esegui una query su id+1 (l'id della insert aperta) e mi dici se ti arriva il record.

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    24/07/2023 - amorosik ha scritto:


    Causalmente vedo anche un “.. SEQUENCES like it works on firebird:..”   

    Sì, fondamentalmente il GENERATOR di Firebird è simile alle SEQUENCE in altri database.

    Laddove non sono presenti, è possibile simulare qualcosa del genere (non è la stessa cosa, ma si avvicina) usando una tabella in cui si inseriscono i contatori, e facendo l'incremento tramite stored procedure e usando una transazione possibilmente bloccante (es. serializable), in modo che nessuno possa leggere un nuovo valore se è in corso la lettura + incremento da parte di un'altra connessione.

    Implementando queste operatività tramite stored procedure, non dovrebbe essere difficile scrivere il codice necessario a

    • incrementare il contatore,
    • resettare il contatore,
    • staccare un numero cumulativo di N progressivi

    e così via.

    Un saluto! :)

  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    23/07/2023 - amorosik ha scritto:


    Se 10 client stanno facendo la stessa cosa, non sei sicuro che il valore letto sia quello hai appena incrementato tu, voglio dire se client1 avvia la procedura e poi client2 fa la stessa cosa, non e' detto che entrambi non leggano il valore ‘codice_cliente’ come incrementato da client2, e quindi leggono lo stesso valore

    Il tuo problema può essere risolto lato applicativo (dal Client), sfruttando il multistatement, se disponibile nei parametri messi a disposizione dal provider di accesso ai dati.

    Esempio : Access con driver ODBC per MySQL (dovremmo essere alla V8.0.23 o superiore)

    Nella connection string devi gestire le opzioni del driver ODBC e quindi aggiungi il parametro MULTI_STATEMENTS=1 (se non vuoi usare il nome del parametro puoi usare il suo valore 2^26)

    Abilitando il multi-staments puoi eseguire una ‘sola query’ così composta :

    sSql = "INSERT INTO NomeTabella (elenco campi) VALUES (elenco valori); SELECT LAST_INSERT_ID();"
    
    utilizzando un ADODB.recordset (ad esempio ArLog) e una ADODB.connection (ad esempio gAdoCnn)
    
    La “doppia query” viene eseguita utilizzando il metodo NextRecordset dell'oggetto ADODB.Recordset :
    
    Set ArLog = gAdoCnn.Execute(sSql).NextRecordset

    Recupero del last insert ID :

    If Not ArLog.EOF Then
        lIdLog = Nz(ArLog("Last_Insert_ID()"), 0)
    End If
  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    23/07/2023 - amorosik ha scritto:


    Se 10 client stanno facendo la stessa cosa, non sei sicuro che il valore letto sia quello hai appena incrementato tu, voglio dire se client1 avvia la procedura e poi client2 fa la stessa cosa, non e' detto che entrambi non leggano il valore ‘codice_cliente’ come incrementato da client2, e quindi leggono lo stesso valore

    Potresti anche risolverlo utilizzando una stored procedure (da testare) :

        '
        ' STORED PROCEDURE :
        '
        'DELIMITER $$
        '
        'Create
        '    PROCEDURE `nomedb`.`sp_ins_identity`(IN tablename VARCHAR(50))
        '    Begin
        '    SET @result = 0;
        '    SET @sqlproc = CONCAT("INSERT INTO ",tablename," () VALUES ();");
        '    PREPARE s1 FROM @sqlproc;
        '    EXECUTE s1;
        '    DEALLOCATE PREPARE s1;
        '    SELECT LAST_INSERT_ID();
        '    END$$
    
  • Re: Come replicare funzionalita 'generator' di altro db su MySql?

    24/07/2023 - max.riservo ha scritto:


    23/07/2023 - amorosik ha scritto:


    Se 10 client stanno facendo la stessa cosa, non sei sicuro che il valore letto sia quello hai appena incrementato tu, voglio dire se client1 avvia la procedura e poi client2 fa la stessa cosa, non e' detto che entrambi non leggano il valore ‘codice_cliente’ come incrementato da client2, e quindi leggono lo stesso valore

    Potresti anche risolverlo utilizzando una stored procedure (da testare) :

        '
        ' STORED PROCEDURE :
        '
        'DELIMITER $$
        '
        'Create
        '    PROCEDURE `nomedb`.`sp_ins_identity`(IN tablename VARCHAR(50))
        '    Begin
        '    SET @result = 0;
        '    SET @sqlproc = CONCAT("INSERT INTO ",tablename," () VALUES ();");
        '    PREPARE s1 FROM @sqlproc;
        '    EXECUTE s1;
        '    DEALLOCATE PREPARE s1;
        '    SELECT LAST_INSERT_ID();
        '    END$$
    

    Molto interessante, grazie

Devi accedere o registrarti per scrivere nel forum
13 risposte