OVH Cloud OVH Cloud

SQLServer et DAO et Transactions

5 réponses
Avatar
SerGioGio
Bonjour,

Je cherche a utiliser les transactions dans SQLServer avec DAO/ODBC.
Voici un extrait de code:

BeginTrans
Call db.Execute("UPDATE counter SET value = value + 1 WHERE name =
'mycounter'", dbSQLPassThrough)
Set Rec = db.OpenRecordSet("SELECT value FROM counter WHERE name =
'mycounter'", dbOpenSnapshot, dbSQLPassThrough)
value = Rec(0)
CommitTrans

Donc il s'agit dans ce code de récupérer une valeur unique à partir d'un
compteur, en faisant l'UPDATE en premier pour se protéger des transactions
concurrentes. Rien de plus facile, c'est ce qu'on apprend à l'école.
Eh bien ça marche sur Oracle, Sybase, SQLServer sous OSQL, mais pas sur
SQLServer sous DAO.

La ligne du SELECT blocque entierement le programme. Que se passe t'il? Je
pense que le driver ODBC SQLServer ouvre plusieurs connections à la base et
envoie l'UPDATE sur l'une et le SELECT sur... une autre, d'ou deadlock!!
http://support.microsoft.com/default.aspx?scid=kb;EN-US;170548 parle de ce
problème mais je n'utilise pas Jet, puisque tous mes appels ont le flag
dbSQLPassThrough.

C'est vraiment rageant. Si un code aussi simple ne marche pas, je ne vois
pas trop l'intérêt des transactions dans SQLServer... Le code marche sous
OSQL, mais sous DAO/ODBC le driver se croit plus intelligent que moi et
plante même les choses les plus élémentaires.

Qu'en pensez vous?
Comment faites vous pour contourner ce probleme? ou bien personne n'utilise
de transactions sur SQLServer DAO...?

Merci d'avance,

SerGioGio

5 réponses

Avatar
Fred BROUARD
gérer des transactions sur le poste client est aussi dangereux que, pour un
chirurgien, d'opérer à distance !

Passer par des procédures stockée me semble la chose la plus naturelle et la
plus simple.

De plus tu as utilisé un mot réservé en tant que nom de colonne (name). Il faut
donc le qualifier en l'entourant de guillemets. Mais mieux vaudrait l'éviter !

Exemple :


CREATE PROCEDURE SP_GET_NEW_KEY @COUNTER VARCHAR(32),
@NEWVALUE INTEGER OUTPUT
AS

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRANSACTION

UPDATE counter
SET value = value + 1
WHERE "name" = @COUNTER
IF @@ERROR <> 0
GOTO LBL_ERROR

SELECT @NEWVALUE = value
FROM counter
WHERE "name" = @COUNTER
IF @@ERROR <> 0
GOTO LBL_ERROR

COMMIT TRANSACTION

RETURN

LBL_ERROR:
ROLLBACK

GO



A +



--
Frédéric BROUARD, MVP SQL Server. Expert SQL / spécialiste Delphi, web
Livre SQL - col. Référence : http://sqlpro.developpez.com/bookSQL.html
Le site du SQL, pour débutants et pros : http://sqlpro.developpez.com
************************ www.datasapiens.com *************************

> 'mycounter'

SerGioGio a écrit:
Bonjour,

Je cherche a utiliser les transactions dans SQLServer avec DAO/ODBC.
Voici un extrait de code:

BeginTrans
Call db.Execute("UPDATE counter SET value = value + 1 WHERE name > 'mycounter'", dbSQLPassThrough)
Set Rec = db.OpenRecordSet("SELECT value FROM counter WHERE name > 'mycounter'", dbOpenSnapshot, dbSQLPassThrough)
value = Rec(0)
CommitTrans

Donc il s'agit dans ce code de récupérer une valeur unique à partir d'un
compteur, en faisant l'UPDATE en premier pour se protéger des transactions
concurrentes. Rien de plus facile, c'est ce qu'on apprend à l'école.
Eh bien ça marche sur Oracle, Sybase, SQLServer sous OSQL, mais pas sur
SQLServer sous DAO.

La ligne du SELECT blocque entierement le programme. Que se passe t'il? Je
pense que le driver ODBC SQLServer ouvre plusieurs connections à la base et
envoie l'UPDATE sur l'une et le SELECT sur... une autre, d'ou deadlock!!
http://support.microsoft.com/default.aspx?scid=kb;EN-US;170548 parle de ce
problème mais je n'utilise pas Jet, puisque tous mes appels ont le flag
dbSQLPassThrough.

C'est vraiment rageant. Si un code aussi simple ne marche pas, je ne vois
pas trop l'intérêt des transactions dans SQLServer... Le code marche sous
OSQL, mais sous DAO/ODBC le driver se croit plus intelligent que moi et
plante même les choses les plus élémentaires.

Qu'en pensez vous?
Comment faites vous pour contourner ce probleme? ou bien personne n'utilise
de transactions sur SQLServer DAO...?

Merci d'avance,

SerGioGio




Avatar
SerGioGio
Merci pour ta réponse.

Selon moi les procédures stockées ont leurs avantages (rapidité, intégrité
intrinsèque de la base...), mais elles ont aussi leurs inconvénients
(portabilité, lisibilité, fonctionnalités, mise au point...). Et c'est aussi
un débat idéologique - j'aime bien penser que les données sont sur la bdd et
les process sur le serveur, mais je comprends qu'on puisse voir les choses
d'une autre façon.

Je ne comprends pas en revanche ta remarque selon laquelle gérer des
transactions sur le poste client serait aussi dangereux que d'opérer à
distance. A peu de choses près (les procédures stockées sont plus rapides
donc les verrous sur les tables/pages/lignes sont moins longs) ça revient
exactement au même selon moi. Dans la plupart des applications utilisant
ODBC, OLE... c'est le driver lui même (c'est à dire le poste client) qui
gère les transactions de manière transparente pour le programmeur en
finissant chaque requête SQL par un COMMIT.

Enfin, pour ce qui concerne ton exemple sp, je ne vois pas pourquoi utiliser
un niveau d'isolation aussi fort (l'UPDATE place déjà un verrou sur la
table/ligne/page), ni pourquoi encapsuler le code par un BEGIN
TRANSACTION...COMMIT (et si SP_GET_NEW_KEY devait être appelé d'une autre
sp?).

SerGioGio


"Fred BROUARD" a écrit dans le message de
news:
gérer des transactions sur le poste client est aussi dangereux que, pour


un
chirurgien, d'opérer à distance !

Passer par des procédures stockée me semble la chose la plus naturelle et


la
plus simple.

De plus tu as utilisé un mot réservé en tant que nom de colonne (name). Il


faut
donc le qualifier en l'entourant de guillemets. Mais mieux vaudrait


l'éviter !

Exemple :


CREATE PROCEDURE SP_GET_NEW_KEY @COUNTER VARCHAR(32),
@NEWVALUE INTEGER OUTPUT
AS

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRANSACTION

UPDATE counter
SET value = value + 1
WHERE "name" = @COUNTER
IF @@ERROR <> 0
GOTO LBL_ERROR

SELECT @NEWVALUE = value
FROM counter
WHERE "name" = @COUNTER
IF @@ERROR <> 0
GOTO LBL_ERROR

COMMIT TRANSACTION

RETURN

LBL_ERROR:
ROLLBACK

GO



A +



--
Frédéric BROUARD, MVP SQL Server. Expert SQL / spécialiste Delphi, web
Livre SQL - col. Référence : http://sqlpro.developpez.com/bookSQL.html
Le site du SQL, pour débutants et pros : http://sqlpro.developpez.com
************************ www.datasapiens.com *************************

> 'mycounter'

SerGioGio a écrit:
> Bonjour,
>
> Je cherche a utiliser les transactions dans SQLServer avec DAO/ODBC.
> Voici un extrait de code:
>
> BeginTrans
> Call db.Execute("UPDATE counter SET value = value + 1 WHERE name > > 'mycounter'", dbSQLPassThrough)
> Set Rec = db.OpenRecordSet("SELECT value FROM counter WHERE name > > 'mycounter'", dbOpenSnapshot, dbSQLPassThrough)
> value = Rec(0)
> CommitTrans
>
> Donc il s'agit dans ce code de récupérer une valeur unique à partir d'un
> compteur, en faisant l'UPDATE en premier pour se protéger des


transactions
> concurrentes. Rien de plus facile, c'est ce qu'on apprend à l'école.
> Eh bien ça marche sur Oracle, Sybase, SQLServer sous OSQL, mais pas sur
> SQLServer sous DAO.
>
> La ligne du SELECT blocque entierement le programme. Que se passe t'il?


Je
> pense que le driver ODBC SQLServer ouvre plusieurs connections à la base


et
> envoie l'UPDATE sur l'une et le SELECT sur... une autre, d'ou deadlock!!
> http://support.microsoft.com/default.aspx?scid=kb;EN-US;170548 parle de


ce
> problème mais je n'utilise pas Jet, puisque tous mes appels ont le flag
> dbSQLPassThrough.
>
> C'est vraiment rageant. Si un code aussi simple ne marche pas, je ne


vois
> pas trop l'intérêt des transactions dans SQLServer... Le code marche


sous
> OSQL, mais sous DAO/ODBC le driver se croit plus intelligent que moi et
> plante même les choses les plus élémentaires.
>
> Qu'en pensez vous?
> Comment faites vous pour contourner ce probleme? ou bien personne


n'utilise
> de transactions sur SQLServer DAO...?
>
> Merci d'avance,
>
> SerGioGio
>
>



Avatar
Med Bouchenafa
Je pense qu'il s'agit effectivement d'un problème de driver
Pour confirmer ton hypothèse de plusieurs connexions et voir réellement ce
qui se passe, il serait intéressant de regarder ce qui se passe réellement
au travers de l'outil "Profiler"
Je pense que cet outil te permettra de comprendre ce qui se passe réellement
et trouver une solution de contournement


--
Bien cordialement
Med Bouchenafa


"SerGioGio" wrote in message
news:#RDbk#
Bonjour,

Je cherche a utiliser les transactions dans SQLServer avec DAO/ODBC.
Voici un extrait de code:

BeginTrans
Call db.Execute("UPDATE counter SET value = value + 1 WHERE name > 'mycounter'", dbSQLPassThrough)
Set Rec = db.OpenRecordSet("SELECT value FROM counter WHERE name > 'mycounter'", dbOpenSnapshot, dbSQLPassThrough)
value = Rec(0)
CommitTrans

Donc il s'agit dans ce code de récupérer une valeur unique à partir d'un
compteur, en faisant l'UPDATE en premier pour se protéger des transactions
concurrentes. Rien de plus facile, c'est ce qu'on apprend à l'école.
Eh bien ça marche sur Oracle, Sybase, SQLServer sous OSQL, mais pas sur
SQLServer sous DAO.

La ligne du SELECT blocque entierement le programme. Que se passe t'il? Je
pense que le driver ODBC SQLServer ouvre plusieurs connections à la base


et
envoie l'UPDATE sur l'une et le SELECT sur... une autre, d'ou deadlock!!
http://support.microsoft.com/default.aspx?scid=kb;EN-US;170548 parle de ce
problème mais je n'utilise pas Jet, puisque tous mes appels ont le flag
dbSQLPassThrough.

C'est vraiment rageant. Si un code aussi simple ne marche pas, je ne vois
pas trop l'intérêt des transactions dans SQLServer... Le code marche sous
OSQL, mais sous DAO/ODBC le driver se croit plus intelligent que moi et
plante même les choses les plus élémentaires.

Qu'en pensez vous?
Comment faites vous pour contourner ce probleme? ou bien personne


n'utilise
de transactions sur SQLServer DAO...?

Merci d'avance,

SerGioGio




Avatar
SerGioGio
Bonjour,

Pour ceux que ça intéresse, la réponse est d'utiliser ODBCDirect. Il suffit
d'ajouter un flag dbUseODBC dans le workspace, et on a ensuite un bon
contrôle des connections à la database!

Je pense maintenant que le problème ne vient pas des drivers ODBC, mais de
Jet.

SerGioGio



"SerGioGio" a écrit dans le message de
news:%23RDbk%
Bonjour,

Je cherche a utiliser les transactions dans SQLServer avec DAO/ODBC.
Voici un extrait de code:

BeginTrans
Call db.Execute("UPDATE counter SET value = value + 1 WHERE name > 'mycounter'", dbSQLPassThrough)
Set Rec = db.OpenRecordSet("SELECT value FROM counter WHERE name > 'mycounter'", dbOpenSnapshot, dbSQLPassThrough)
value = Rec(0)
CommitTrans

Donc il s'agit dans ce code de récupérer une valeur unique à partir d'un
compteur, en faisant l'UPDATE en premier pour se protéger des transactions
concurrentes. Rien de plus facile, c'est ce qu'on apprend à l'école.
Eh bien ça marche sur Oracle, Sybase, SQLServer sous OSQL, mais pas sur
SQLServer sous DAO.

La ligne du SELECT blocque entierement le programme. Que se passe t'il? Je
pense que le driver ODBC SQLServer ouvre plusieurs connections à la base


et
envoie l'UPDATE sur l'une et le SELECT sur... une autre, d'ou deadlock!!
http://support.microsoft.com/default.aspx?scid=kb;EN-US;170548 parle de ce
problème mais je n'utilise pas Jet, puisque tous mes appels ont le flag
dbSQLPassThrough.

C'est vraiment rageant. Si un code aussi simple ne marche pas, je ne vois
pas trop l'intérêt des transactions dans SQLServer... Le code marche sous
OSQL, mais sous DAO/ODBC le driver se croit plus intelligent que moi et
plante même les choses les plus élémentaires.

Qu'en pensez vous?
Comment faites vous pour contourner ce probleme? ou bien personne


n'utilise
de transactions sur SQLServer DAO...?

Merci d'avance,

SerGioGio




Avatar
SerGioGio
Salut Fred,

Je n'ai pas beaucoup d'expérience dans la programmation DB et j'aimerai
apprendre le plus possible.
Je comprends que tu mentionnes les procédures stockées, mais je ne comprends
pas en revanche ton commentaire sur le danger de gérer des transactions sur
le poste client.
Pourrais-tu nous en dire plus la-dessus?

Merci d'avance,

SerGioGio


"Fred BROUARD" a écrit dans le message de
news:
gérer des transactions sur le poste client est aussi dangereux que, pour


un
chirurgien, d'opérer à distance !

Passer par des procédures stockée me semble la chose la plus naturelle et


la
plus simple.

De plus tu as utilisé un mot réservé en tant que nom de colonne (name). Il


faut
donc le qualifier en l'entourant de guillemets. Mais mieux vaudrait


l'éviter !

Exemple :


CREATE PROCEDURE SP_GET_NEW_KEY @COUNTER VARCHAR(32),
@NEWVALUE INTEGER OUTPUT
AS

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

BEGIN TRANSACTION

UPDATE counter
SET value = value + 1
WHERE "name" = @COUNTER
IF @@ERROR <> 0
GOTO LBL_ERROR

SELECT @NEWVALUE = value
FROM counter
WHERE "name" = @COUNTER
IF @@ERROR <> 0
GOTO LBL_ERROR

COMMIT TRANSACTION

RETURN

LBL_ERROR:
ROLLBACK

GO



A +



--
Frédéric BROUARD, MVP SQL Server. Expert SQL / spécialiste Delphi, web
Livre SQL - col. Référence : http://sqlpro.developpez.com/bookSQL.html
Le site du SQL, pour débutants et pros : http://sqlpro.developpez.com
************************ www.datasapiens.com *************************

> 'mycounter'

SerGioGio a écrit:
> Bonjour,
>
> Je cherche a utiliser les transactions dans SQLServer avec DAO/ODBC.
> Voici un extrait de code:
>
> BeginTrans
> Call db.Execute("UPDATE counter SET value = value + 1 WHERE name > > 'mycounter'", dbSQLPassThrough)
> Set Rec = db.OpenRecordSet("SELECT value FROM counter WHERE name > > 'mycounter'", dbOpenSnapshot, dbSQLPassThrough)
> value = Rec(0)
> CommitTrans
>
> Donc il s'agit dans ce code de récupérer une valeur unique à partir d'un
> compteur, en faisant l'UPDATE en premier pour se protéger des


transactions
> concurrentes. Rien de plus facile, c'est ce qu'on apprend à l'école.
> Eh bien ça marche sur Oracle, Sybase, SQLServer sous OSQL, mais pas sur
> SQLServer sous DAO.
>
> La ligne du SELECT blocque entierement le programme. Que se passe t'il?


Je
> pense que le driver ODBC SQLServer ouvre plusieurs connections à la base


et
> envoie l'UPDATE sur l'une et le SELECT sur... une autre, d'ou deadlock!!
> http://support.microsoft.com/default.aspx?scid=kb;EN-US;170548 parle de


ce
> problème mais je n'utilise pas Jet, puisque tous mes appels ont le flag
> dbSQLPassThrough.
>
> C'est vraiment rageant. Si un code aussi simple ne marche pas, je ne


vois
> pas trop l'intérêt des transactions dans SQLServer... Le code marche


sous
> OSQL, mais sous DAO/ODBC le driver se croit plus intelligent que moi et
> plante même les choses les plus élémentaires.
>
> Qu'en pensez vous?
> Comment faites vous pour contourner ce probleme? ou bien personne


n'utilise
> de transactions sur SQLServer DAO...?
>
> Merci d'avance,
>
> SerGioGio
>
>