Couchbase Server 7.0 ahora soporta transacciones N1QL.
Intentemos escribir un programa en C que realice un conjunto de transacciones en un único nodo.
Primer paso: Primero decidimos cómo llamar al programa. Las entradas serán la URL del bucket de Couchbase contra el que deseamos ejecutar consultas, y las credenciales (nombre de usuario seguido de la contraseña).
Uso:
1 |
./n1ql couchbase://localhost/prueba Contraseña de administrador |
Con las transacciones N1QL, se devuelve un valor txid desde el comando START TRANSACTION. Este es usado con todas las subsecuentes consultas N1QL dentro de la transacción hasta el final COMMIT o ROLLBACK. Así que debemos declarar un ID de transacción en la función principal que podamos pasar a las solicitudes de consulta restantes que forman parte de la transacción.
Segundo paso: Inicializa un puntero que se utilizará para guardar el ID de transacción de la consulta BEGIN TRANSACTION. Este ID se utilizará en toda la transacción.
1 |
char *transaction_id = (char *)malloc(64 * tamaño de(char)); |
Paso 3: Inicializar el clúster
Una conexión a un cluster de Couchbase Server está representada por un lcb_INSTANCE objeto.
lcb_INSTANCE *instance;
El conjunto de operaciones permitidas depende del tipo de este objeto y de si el cubo está asociado a él. Aquí utilizamos el tipo Cluster. La forma más sencilla de crear un objeto cluster es llamar a lcb_create para crear un manejador Couchbase pasando LCB_TIPO_CLUSTER con una cadena de conexión, un nombre de usuario y una contraseña. A continuación, programamos una conexión utilizando lcb_connect(), y luego comprobamos si el bucket existe.
1 2 3 4 5 6 7 8 9 |
lcb_CREATEOPTS *crear_opciones = NULL; lcb_createopts_create(&crear_opciones, LCB_TIPO_CLUSTER); lcb_createopts_connstr(crear_opciones, argv[1], strlen(argv[1])); lcb_createopts_credentials(crear_opciones, argv[2], strlen(argv[2]), argv[3], strlen(argv[3])); consulte(lcb_create(&instancia, crear_opciones), "crear asa couchbase"); lcb_createopts_destroy(crear_opciones); consulte(lcb_connect(instancia), "programar conexión"); lcb_wait(instancia, LCB_WAIT_DEFAULT); consulte(lcb_cntl(instancia, LCB_CNTL_GET, LCB_CNTL_BUCKETNAME, &cubo), "get bucket name"); |
Paso 4: Ejecuta las consultas en query.h
Tenemos las consultas correspondientes a nuestra transacción definidas en queries.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
COMENZAR TRABAJO INSERTAR EN prueba VALORES(\"kkk1\", {\"a\":1}) SELECCIONE d.*, META(d).id DESDE prueba AS d DONDE d.a >= 0 GUARDAR PUNTO s1 ACTUALIZACIÓN prueba AS d SET d.b = 10 DONDE d.a > 0 SELECCIONE d.*, META(d).id DESDE prueba AS d DONDE d.a >= 0 GUARDAR PUNTO s2 ACTUALIZACIÓN prueba AS d SET d.b = 10, d.c = \"xyz\" DONDE d.a > 0 SELECCIONE d.*, META(d).id DESDE prueba AS d DONDE d.a >= 0 ROLLBACK TRAN A GUARDAR PUNTO s2 SELECCIONE d.*, META(d).id DESDE prueba AS d DONDE d.a >= 0 INSERTAR EN prueba VALORES(\"kkk2\", {\"a\":2}) ACTUALIZACIÓN prueba AS d SET d.b = 20, d.c = \"xyz\" DONDE d.a > 0 COMPROMETERSE TRABAJO |
Necesitamos utilizar una librería de análisis JSON en C para manejar los resultados de la consulta y extraer el ID de la transacción. Aquí podemos usar la librería json-c. Para obtener el ID de transacción de la sentencia BEGIN WORK (la primera sentencia), utilizamos la función callback txid. Para procesar y ejecutar las otras consultas, llamamos a la función row callback. Esto devolverá las filas de resultados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
para> (ii = >0>; ii < número_consultas; ii++) {> >lcb_CMDQUERY> *>cmd>; > >lcb_cmdquery_create>(&cmd);> >consulte>(lcb_cmdquery_statement(cmd, consultas[ii].consulta, strlen(consultas[ii].consulta)), >"establecer declaración QUERY">);> >printf>(>"----> \x1b[1m%s\x1b[0m\n">, consultas[ii].consulta);> >si> (ii == >0>) {> >lcb_cmdquery_callback>(cmd, txid_callback);> >lcb_wait>(instancia, LCB_WAIT_DEFAULT);> >consulte>(lcb_query(instancia, transaction_id, cmd), >"programar operación QUERY">);> >lcb_wait>(instancia, LCB_WAIT_DEFAULT); > } >si no> {> >char> buf>[100];> >sprintf>(buf,>"\">%s\>"">,transaction_id);> >lcb_cmdquery_callback>(cmd, row_callback);> >// SET rest option pretty a true y txtimeout a 3s> >check>(lcb_cmdquery_option(cmd, >"bonito">, strlen(>"bonito">), >"verdadero">, strlen(>"verdadero">)),>"configure CONSULTA "bonita opción">);> >check>(lcb_cmdquery_option(cmd, >"txtimeout">, strlen(>"txtimeout">), >"\">3s>\>"">, strlen(>"\">3s>\>"">)),>"configure CONSULTA txtimeout opción">);> check(lcb_cmdquery_option(cmd, >"txid">, >strlen>(>"txid">),buf, >strlen>(buf)),>"configure CONSULTA txtimeout opción">);> check(lcb_query(instance, >NULL>, cmd), >"horario CONSULTA operación">);> lcb_wait(instancia, LCB_WAIT_DEFAULT);> } > lcb_cmdquery_destroy(cmd);> lcb_wait(instancia, LCB_WAIT_DEFAULT);> }> |
Antes de ejecutar las consultas, establecemos tres parámetros de consulta: pretty, txtimeout (tiempo de espera de la transacción) y el txid que obtuvimos de la primera sentencia. Estos son parámetros a nivel de petición.
Ahora vamos a profundizar en las funciones callback
Txid_Callback -
Aquí tenemos que analizar la respuesta JSON de la ejecución de la sentencia BEGIN WORK para extraer el txid y pasarlo a las sentencias posteriores como parámetro de consulta utilizando la librería JSONC. Para ello utilizamos el puntero creado anteriormente y lo establecemos en el método lcb_respquery_cookie. Esto establece la cookie de la operación - lo que significa que cuando ejecutamos lcb_query, hay un argumento cookie para ello y lcb_respquery_cookie obtiene este puntero en nuestra función callback. (Creamos un puntero en la función principal y lo establecemos en la función callback)
1 2 3 4 5 6 7 8 9 10 |
/* crear puntero transaction_id y establecerlo en la llamada de retorno */ lcb_respquery_cookie(resp, (void **)&transaction_id); consulte(lcb_respquery_status(resp),"comprobar estado de respuesta"); lcb_respquery_row(resp, &fila, &nrow); si (!lcb_respquery_is_final(resp)) { parsed_json = json_tokener_parse(fila); json_object_object_get_ex(parsed_json, "txid", &txid_obj); temp = json_object_get_string(txid_obj); strcpy(transaction_id,temp); } |
Row callback - Se utiliza para analizar y recuperar las filas de resultados de la ejecución de la consulta.
1 2 3 4 5 6 7 8 9 |
lcb_STATUS rc = lcb_respquery_status(resp); lcb_respquery_row(resp, &fila, &nrow); ln2espacio(fila, nrow); fprintf(stderr, "[\x1b[%dmQUERY\x1b[0m] %s, (%d) %.*s\n", err2color(rc), lcb_strerror_short(rc), (int)nrow, (int)nrow, fila); si (lcb_respquery_is_final(resp)) { fprintf(stderr, "\n"); } } |
Aquí obtenemos la respuesta de la consulta, obtenemos las filas y la imprimimos.
Usando el ejemplo anterior, ahora podemos usar transacciones N1QL en el SDK de C. Para el código completo ver e instrucciones sobre cómo ejecutarlo ver -. https://github.com/ikandaswamy/CBSDK_N1QLExamples