STATIC FUNCTION Cobr_Grabar( lNuevo )
LOCAL lGrabado := FALSE
LOCAL cWhere
oServer:lThrowError := TRUE
TRY
oServer:BeginTransaction()
IF lNuevo .and. ( nNumero := IncCount( "control", "cont_cobr" ) ) > 0
oServer:Insert2( "cobradores", { { "num_cobr" , nNumero }, ;
{ "nombre" , cNombre }, ;
{ "cedula" , cCedula }, ;
{ "ciudad" , cCiudad }, ;
{ "direccion" , cDireccion }, ;
{ "telefonos" , cTelefonos }, ;
{ "fdi" , dFechaI }, ;
{ "activo" , lActivo }, ;
{ "fdr" , dFechaR }, ;
{ "nota" , cNota } } )
ELSE
cWhere := "num_cobr=" + Var2Str( nNumero )
oServer:Update2( "cobradores", { { "nombre" , cNombre }, ;
{ "cedula" , cCedula }, ;
{ "ciudad" , cCiudad }, ;
{ "direccion" , cDireccion }, ;
{ "telefonos" , cTelefonos }, ;
{ "fdi" , dFechaI }, ;
{ "activo" , lActivo }, ;
{ "fdr" , dFechaR }, ;
{ "nota" , cNota } }, cWhere )
ENDIF
oServer:Commit()
oQryCobr:Refresh()
lGrabado := TRUE
CATCH oError
ShowError( oError )
oServer:Rollback()
END
oServer:lThrowError := FALSE
IF lGrabado
IIf( lNuevo, ( oBrw:GoBottom(), oBrw:Refresh() ), oBrw:RefreshCurrent() )
ELSE
oBrw:GoTop()
ENDIF
RETURN lGrabado
FUNCTION IncCount( cTable, cField )
LOCAL oQryTmp
LOCAL nCount := 0
oQryTmp := oServer:Query( "SELECT " + cField + " FROM " + cTable + " FOR UPDATE" )
IF oQryTmp:RecCount() >= 0
nCount := oQryTmp:FieldGet( 1 ) + 1
oServer:Execute( "UPDATE " + cTable + " SET " + cField + " = " + Var2Str( nCount ) )
ENDIF
oQryTmp:End()
RETURN nCount
CREATE TABLE `control` (
`cont_usua` BIGINT(10) UNSIGNED NOT NULL DEFAULT '0',
`cont_ruta` BIGINT(10) UNSIGNED NOT NULL DEFAULT '0',
`cont_cobr` BIGINT(10) UNSIGNED NOT NULL DEFAULT '0',
`cont_clie` BIGINT(10) UNSIGNED NOT NULL DEFAULT '0',
`cont_pres` BIGINT(10) UNSIGNED NOT NULL DEFAULT '0',
`cont_abon` BIGINT(10) UNSIGNED NOT NULL DEFAULT '0',
`cont_docu` BIGINT(10) UNSIGNED NOT NULL DEFAULT '0',
`my_recno` BIGINT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`my_recno`) USING BTREE
)
COLLATE='latin1_spanish_ci'
ENGINE=InnoDB
cTabla:= _cPrefijo+'_docventa' //nombre de tu tabla
cQuery:=''
cQuery:="SELECT * FROM "+ cTabla + " FOR UPDATE; " // seleccionamos el UNICO registro de la tabla con la clausula FOR UPDATE
oQuery:= _oSqlConex:Query( cQuery ) // este "FOR UPDATE" hace un bloqueo y ninguna otra estacion puede accesar
// mientras se realiza la operacion de sumar uno al consecutivo y tomarlo
// en variable de memoria
nNumeroFactura:=oQuery:numero_factura+1 // Sumamos 1 al valor del contador guardado en la tabla
cQuery:=''
cQuery:="Update "+cTabla+" Set " // aqui actualizamos el valor del campo en la tabla ya incrmentado en 1
cQuery+="numero_factura:="+alltrim(str(nNumeroFactura))+"; "
_oSqlConex:Execute( cQuery )
_oSqlConex:End // al cerrar la conexcion, se libera el registro para los demas usuarios.
_oSqlConex:End // al cerrar la conexcion, se libera el registro para los demas usuarios.
armando.lagunas wrote:Estimado:
lo que yo utilizo en SQL es un campo lógico (0-1) como una bandera, terminal A: toma el registro y le cambio el estado a ese campo inmediatamente a 0 (ocupado) y cuando termino los cambios realizados en el registro le devuelvo el estado 1 (Activo), entonces en la terminal B verifica el estado de este campo antes de hacer cualquier cosa en el registro.
lo otro es realizar procedimiento almacenado en la base de datos estableciendo SET TRANSACTION ISOLATION LEVEL READ COMMITTED que es lo que permite bloquear temporalmente registros en una base de datos SQL
busca en internet como utilizarlo hay varios LEVEL para analizar y utilizar
Espero que te sirva
Saludos
VictorCasajuana wrote:armando.lagunas wrote:Estimado:
lo que yo utilizo en SQL es un campo lógico (0-1) como una bandera, terminal A: toma el registro y le cambio el estado a ese campo inmediatamente a 0 (ocupado) y cuando termino los cambios realizados en el registro le devuelvo el estado 1 (Activo), entonces en la terminal B verifica el estado de este campo antes de hacer cualquier cosa en el registro.
lo otro es realizar procedimiento almacenado en la base de datos estableciendo SET TRANSACTION ISOLATION LEVEL READ COMMITTED que es lo que permite bloquear temporalmente registros en una base de datos SQL
busca en internet como utilizarlo hay varios LEVEL para analizar y utilizar
Espero que te sirva
Saludos
Hola Armando.
Este tema siempre me ha intrigado y a veces me pongo a buscar info pero nunca llego a buen puerto. En tu caso lo tienes bien controlado ya que modificas la tabla. No me gusta mucho tener que modificar la estructura de datos para este fin pero se podría aceptar como solución. Pero me surge una duda, si el terminal A toma el registro, cambias la bandera a 1 y se cierra el programa sin pasar por el proceso de guardar la ficha, que haces? por ejemplo se puede apagar el ordenador, error de ejecución, etc...
aquí hay una buena charla que tuvimos hace meses al respecto: https://forum.modharbour.app/viewtopic.php?f=25&t=259
# include FIVEWIN.CH
Function Fnct_Prueba()
Local oQuery, cQuery, cTabla
Local nNuevoNumero
_oSqlConex:=TDolphinSrv():New( _cHost, _cUser, _cPasswordUser,,, _cDataBase,bSQLCnxErr() ) // mis variables de conexion son publicas.
// cada quien debe manejar esta parte
if _oSqlConex:lError // segun su forma de trabajar.
_oSqlConex:End()
return .f.
endif
cQuery := "SET AUTOCOMMIT=0 ; " // colocamos el AUTOCOMMIT temporalmente en 0 (desactivado)
oQuery := _oSqlConex:Execute( cQuery ) // de esta forma AUTOCOMMIT funciona solo con la sesion actual
// en caso de que no este configurado por defecto
cTabla := _cPrefijo+'_docventatemp'
cQuery := ''
cQuery := "SELECT numerotemp_documento FROM "+ cTabla +" FOR UPDATE ; " // hacemos el SELECT... FOR UPDATE para bloquear la fila de
oQuery := _oSqlConex:Query( cQuery ) // la tabla
nNuevoNumero:=oQuery:numerotemp_documento+1 // aumentamos en 1 el contador consecutivo
cQuery :=''
cQuery :="Update "+cTabla+" Set "
cQuery +="numerotemp_documento:="+alltrim(str(nNuevoNumero))+" ; " // actualizamos la tabla
_oSqlConex:Execute( cQuery )
//msginfo('Stop') // activar si se desea chequear la tabla con phpmyadmin, heidi, navicat, etc. durante el proceso.
cQuery:="commit ; " // hacemos commit para actualizar la tabla.
oQuery:= _oSqlConex:Execute( cQuery )
cQuery := "SET AUTOCOMMIT=1 ; " // Colocamos el autocommit de nuevo a su estado activo
oQuery := _oSqlConex:Execute( cQuery )
_oSqlConex:End() // cerramos la conexion
return nNuevoNumero // nNuevoNumero es el numero asignado a la nueva factura que estamos emitiendo ...
# include FIVEWIN.CH
Function Fnct_Prueba()
Local oQuery, cQuery, cTabla
Local nNuevoNumero
_oSqlConex:=TDolphinSrv():New( _cHost, _cUser, _cPasswordUser,,, _cDataBase,bSQLCnxErr() ) // mis variables de conexion son publicas.
// cada quien debe manejar esta parte
if _oSqlConex:lError // segun su forma de trabajar.
_oSqlConex:End()
return .f.
endif
_oSqlConex:BeginTransaction() // comenzamos la transaccion
cTabla := _cPrefijo+'_docventatemp'
cQuery := ''
cQuery := "SELECT numerotemp_documento FROM "+ cTabla +" FOR UPDATE ; " // hacemos el SELECT... FOR UPDATE para bloquear la fila de
oQuery := _oSqlConex:Query( cQuery ) // la tabla
nNuevoNumero:=oQuery:numerotemp_documento+1 // aumentamos en 1 el contador consecutivo
cQuery :=''
cQuery :="Update "+cTabla+" Set "
cQuery +="numerotemp_documento:="+alltrim(str(nNuevoNumero))+" ; " // actualizamos la tabla
_oSqlConex:Execute( cQuery )
//msginfo('Stop') // activar si se desea chequear durante el proceso.
_oSqlConex:CommitTransaction()
_oSqlConex:End() // cerramos la conexion
return nNuevoNumero // nNuevoNumero es el numero asignado a la nueva factura que estamos emitiendo ...
Return to FiveWin para Harbour/xHarbour
Users browsing this forum: Google [Bot] and 42 guests