mirror of
https://github.com/php/doc-es.git
synced 2026-03-26 08:22:08 +01:00
git-svn-id: https://svn.php.net/repository/phpdoc/es/trunk@337301 c90b9560-bf6c-de11-be94-00142212c4b1
1814 lines
62 KiB
XML
1814 lines
62 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- $Revision$ -->
|
||
<!-- EN-Revision: 220e2c2d26f47e536bf3cc53ac38547a6ad86c38 Maintainer: seros Status: ready -->
|
||
<!-- Reviewed: no Maintainer: seros -->
|
||
<chapter xml:id="mysqli.quickstart" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||
<title>Guía rápida</title>
|
||
<para>
|
||
Esta guía rápida le ayudará a elegir y obtener familiaridad
|
||
con la API MySQL de PHP.
|
||
</para>
|
||
<para>
|
||
Esta guía rápida ofrece información general sobre la extensión mysqli. Se proporcionan
|
||
ejemplos de código para los aspectos más importantes de la API. Los conceptos de la base de datos se explican
|
||
con el grado necesario para presentar conceptos específicos de MySQL.
|
||
</para>
|
||
<para>
|
||
Se requiere: Familiaridad con el lenguaje de programación PHP, con el lenguaje SQL,
|
||
y conociemientos básicos del servidor MySQL.
|
||
</para>
|
||
<section xml:id="mysqli.quickstart.dual-interface">
|
||
<title>Interfaz dual: procedimental y orientada a objetos</title>
|
||
<para>
|
||
La extensión mysqli ofrece una interfaz dual. Soporta el paradigme de programación
|
||
procedimental y el orientado a objetos.
|
||
</para>
|
||
<para>
|
||
Los usuarios que migren desde la extensión mysql antigua pueden preferir la interfaz
|
||
procedimental. Esta interfaz es similar a la de la extensión antigua de
|
||
mysql. En la mayoría de los casos, los nombres de funciones difieren únicamente por el prefijo.
|
||
Algunas funciones de mysqli toman como primer argumento un gestor de conexión,
|
||
mientras que las funciones similares de la antigua interfaz de mysql lo
|
||
toman como el último argumento opcional.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Migración sencilla desde la antigua extensión mysql</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = mysqli_connect("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
$resultado = mysqli_query($mysqli, "SELECT 'Por favor, no use ' AS _msg FROM DUAL");
|
||
$fila = mysqli_fetch_assoc($resultado);
|
||
echo $fila['_msg'];
|
||
|
||
$mysql = mysql_connect("ejemplo.com", "usuario", "contraseña");
|
||
mysql_select_db("test");
|
||
$resultado = mysql_query("SELECT 'la extensión mysql para nuevos desarrollos.' AS _msg FROM DUAL", $mysql);
|
||
$fila = mysql_fetch_assoc($resultado);
|
||
echo $fila['_msg'];
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Por favor, no use la extensión mysql para nuevos desarrollos.
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">La interfaz orientada a objetos</emphasis>
|
||
</para>
|
||
<para>
|
||
Además de la clásica interfaz procedimental, los usuarios pueden optar por usar
|
||
la interfaz orientada a objetos. La documentación está organizada según
|
||
la interfaz orientada a objetos. Esta interfaz muestra las funciones
|
||
agrupadas por su propósito, haciendo más fácil los comienzos. La sección de referencia
|
||
proporciona ejemplos para ambas variantes de sintaxis.
|
||
</para>
|
||
<para>
|
||
No existen diferencias significativas de rendimiento entre las dos interfaces.
|
||
Los usuarios puede basar su elección en sus preferencias personales.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Interfaz orientada a objetos y procedimental</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = mysqli_connect("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if (mysqli_connect_errno($mysqli)) {
|
||
echo "Fallo al conectar a MySQL: " . mysqli_connect_error();
|
||
}
|
||
|
||
$resultado = mysqli_query($mysqli, "SELECT 'Un mundo lleno de ' AS _msg FROM DUAL");
|
||
$fila = mysqli_fetch_assoc($resultado);
|
||
echo $fila['_msg'];
|
||
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Fallo al conectar a MySQL: " . $mysqli->connect_error;
|
||
}
|
||
|
||
$resultado = $mysqli->query("SELECT 'elecciones para complacer a todos.' AS _msg FROM DUAL");
|
||
$fila = $resultado->fetch_assoc();
|
||
echo $fila['_msg'];
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Un mundo lleno de elecciones para complacer a todos.
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Se usa la interfaz orientada a objetos en el inicio rápido porque la
|
||
sección de referencia está organizada de esta manera.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Mezclar estilos</emphasis>
|
||
</para>
|
||
<para>
|
||
Es posible cambiar entre los estilos en cualquier momento. No se recomienda mezclar
|
||
los dos estilos por razones de claridad y estilo de código.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Estilo de codificación malo</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Fallo al conectar a MySQL: " . $mysqli->connect_error;
|
||
}
|
||
|
||
$resultado = mysqli_query($mysqli, "SELECT 'Estilo malo pero posible.' AS _msg FROM DUAL");
|
||
if (!$resultado) {
|
||
echo "Fallo al ejecutar la consulta: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if ($fila = $resultado->fetch_assoc()) {
|
||
echo $fila['_msg'];
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Estilo malo pero posible.
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Véase también</emphasis>
|
||
</para>
|
||
<para>
|
||
<simplelist>
|
||
<member><methodname>mysqli::__construct</methodname></member>
|
||
<member><methodname>mysqli::query</methodname></member>
|
||
<member><methodname>mysqli_result::fetch_assoc</methodname></member>
|
||
<member><link linkend="mysqli.connect-errno">$mysqli::connect_errno</link></member>
|
||
<member><link linkend="mysqli.connect-error">$mysqli::connect_error</link></member>
|
||
<member><link linkend="mysqli.errno">$mysqli::errno</link></member>
|
||
<member><link linkend="mysqli.error">$mysqli::error</link></member>
|
||
<member><link linkend="mysqli.summary">El resumen de funciones de la extensión MySQLi</link></member>
|
||
</simplelist>
|
||
</para>
|
||
</section>
|
||
|
||
<section xml:id="mysqli.quickstart.connections">
|
||
<title>Conexiones</title>
|
||
<para>
|
||
El servidor MySQL soporta el uso de diferentes capas de
|
||
transporte para conexiones. Las conexiones usan TCP/IP, sockets de dominio Unix o
|
||
tuberías con nombre de Windows.
|
||
</para>
|
||
<para>
|
||
El nombre del host <literal>localhost</literal> tiene un significado especial.
|
||
Está vinculado al uso de sockets de dominio Unix. No es posible
|
||
abrir una conexión TCP/IP usando como nombre de host <literal>localhost</literal>,
|
||
se debe usar <literal>127.0.0.1</literal> en su lugar.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Significado especia de localhost</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("localhost", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Fallo al conectar a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
echo $mysqli->host_info . "\n";
|
||
|
||
$mysqli = new mysqli("127.0.0.1", "usuario", "contraseña", "basedatos", 3306);
|
||
if ($mysqli->connect_errno) {
|
||
echo "Fallo al conectar a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
echo $mysqli->host_info . "\n";
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Localhost via UNIX socket
|
||
127.0.0.1 via TCP/IP
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Valores predeterminados de los parámetros de conexión</emphasis>
|
||
</para>
|
||
<para>
|
||
Dependiendo de la función de conexión usada se pueden omitir
|
||
varios parámetros. Si no se proporciona un parámetro, la extensión intentará
|
||
usar los valores predeterminados que están establecidos en el fichero de configuración de PHP.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Configuración predeterminada</title>
|
||
<programlisting role="ini">
|
||
<![CDATA[
|
||
mysqli.default_host=192.168.2.27
|
||
mysqli.default_user=root
|
||
mysqli.default_pw=""
|
||
mysqli.default_port=3306
|
||
mysqli.default_socket=/tmp/mysql.sock
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Los valores resultantes de los parámetros son pasados a la biblioteca cliente
|
||
que esté usando esta extensión. Si la biblioteca cliente detecta parámetros vacíos o no
|
||
establecidos, puede usar los valores internos predeterminados de la biblioteca.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Valores predeterminados internos de conexión de la biblioteca</emphasis>
|
||
</para>
|
||
<para>
|
||
Si el valor del host no está establecido o está vacío, la biblioteca cliente
|
||
usará una conexión de socket Unix sobre <literal>localhost</literal>.
|
||
Si el socket no está establecido o está vacío, y es solicitada una conexión de socket Unix,
|
||
se intentará una conexiónal socket predeterminado de
|
||
<literal>/tmp/mysql.sock</literal>.
|
||
</para>
|
||
<para>
|
||
En sistemas Windows, el nombre de host <literal>.</literal> es interpretado
|
||
por la biblioteca cliente como un intento de abrir una conexión basada en una tubería con nombre
|
||
de Windows. En este caso el parámetro del socket se interpreta como el nombre de la
|
||
tubería. Si no se proporciona o está vacío, se usará como socket (nombre de la tubería)
|
||
<literal>\\.\pipe\MySQL</literal>.
|
||
</para>
|
||
<para>
|
||
Si no está establecida una conexión basada en un socket de dominio Unix ni en una
|
||
tubería con nombre de Windows y el valor del parámetro del puerto no está establecido, la biblioteca
|
||
usuará como puerto predeterminado el <literal>3306</literal>.
|
||
</para>
|
||
<para>
|
||
La biblioteca <link linkend="mysqlnd.overview">mysqlnd</link> y la
|
||
Biblioteca Cliente de MySQL (libmysqlclient) implementan la misma lógica para determinados valores predeterminados.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Opciones de conexión</emphasis>
|
||
</para>
|
||
<para>
|
||
Las opciones de conexión están disponibles para, por ejemplo, establecer
|
||
comando iniciales que son ejecutados sobre la conexión, o para solicitar el uso de
|
||
ciertos conjuntos de caracteres. Las opciones de conexión deben ser establecidas antes de que se
|
||
establezcla una conexión de red.
|
||
</para>
|
||
<para>
|
||
Para configurar una opción de conexión, la operación de conexión ha de ser
|
||
realizada en tres pasos: crear un gestor de conexión con
|
||
<function>mysqli_init</function>, establecer las opciones solicitadas usando
|
||
<function>mysqli_options</function>, y establecer la conexión de red
|
||
con <function>mysqli_real_connect</function>.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Caché de conexiones</emphasis>
|
||
</para>
|
||
<para>
|
||
La extensión mysqli soporta conexiones persistentes a bases de datos, las cuales
|
||
son un tipo especial de conexiones almacenadas en caché. Por defecto, cada conexión
|
||
a una base de datos abierta por un script es cerrada explícitamente por el usuario durante
|
||
el tiempo de ejecución o liberada automáticamente al finalizar el script. Una conexión
|
||
persistente no. En su lugar, se coloca en una caché para su reutilización posterior, si
|
||
una conexión es abierta al mismo servidor usando el mismo nombre de usuario, contraseña, socket, puerto
|
||
y base de datos predeterminada. La reutilización ahorra gastos de conexioń.
|
||
</para>
|
||
<para>
|
||
Cada procesos de PHP utiliza su propia caché de conexiones mysqli.
|
||
Dependiendo de modelo de distribución del servidor web, un proceso PHP puede servir
|
||
una o múltiples peticiones. Por lo tanto, una conexión almacenada en caché puede ser
|
||
utilizada posteriormente por uno o más scripts.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Conexiones persistentes</emphasis>
|
||
</para>
|
||
<para>
|
||
Si una conexión persistente no usada con una combiación dada de host, nombre de usuario,
|
||
contraseña, socket, puerto y base de datos predeterminada no se puede encontrar en la caché de conexiones,
|
||
mysqli abrirá una nueva conexión. El uso de conexiones persistentes se puede
|
||
habilitar y deshabilitar usando la directiva de PHP <link linkend="ini.mysqli.allow-persistent">mysqli.allow_persistent</link>.
|
||
El número total de conexiones abiertas por un script puede ser limitado con
|
||
<link linkend="ini.mysqli.max-links">mysqli.max_links</link>. El número máximo de conexiones persistentes
|
||
por proceso de PHP puede restringirse con <link linkend="ini.mysqli.max-persistent">mysqli.max_persistent</link>.
|
||
Observe que el servidor web puede engendrar muchos procesos de PHP.
|
||
</para>
|
||
<para>
|
||
Una queja común sobre las conexiones persistentes qes que su estado no
|
||
es reiniciado antes de su uso. Por ejemplo, las transacciones abiertas y no finalizadas no son
|
||
automéáticamente reanudadas. También, los cambios de autorización que ocurran
|
||
durante la colocación de la conexión en la caché y su reutilización
|
||
no están reflejados. Esto puede verse como un efecto secundario no deseado. Al contrario,
|
||
el nombre <literal>persistente</literal> puede entenderse como una promesa
|
||
de que el estado persiste.
|
||
</para>
|
||
<para>
|
||
La extensión mysqli soporta ambas interpretaciones de una conexión persistente:
|
||
el estado persiste, y el estado se reinicia antes de la reutilización. Lo predeterminado es la reiniciación.
|
||
Antes de que una conexión sea reutilizada, la extensión llama
|
||
implicitamente a <function>mysqli_change_user</function> para reiniciar el estado. La
|
||
conexión persistente aparece al usuario como si estuviera recién abierta. No
|
||
son visibles ningún artefacto de los usos previos.
|
||
</para>
|
||
<para>
|
||
La función <function>mysqli_change_user</function> es una operación cara.
|
||
Para un mejor rendimiento, los usuarios pueden recompilar la extensión con la
|
||
bandera de compilación <constant>MYSQLI_NO_CHANGE_USER_ON_PCONNECT</constant> establecida.
|
||
</para>
|
||
<para>
|
||
Corresponde al usuario elegir entre comportamiento seguro o mejor rendimiento.
|
||
Ambas son metas de optimización válidas. Para facilitar el uso, el comportamiento seguro
|
||
es el predeterminado a expensas de un rendimiento máximo.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">See also</emphasis>
|
||
</para>
|
||
<para>
|
||
<simplelist>
|
||
<member><methodname>mysqli::__construct</methodname></member>
|
||
<member><methodname>mysqli::init</methodname></member>
|
||
<member><methodname>mysqli::options</methodname></member>
|
||
<member><methodname>mysqli::real_connect</methodname></member>
|
||
<member><methodname>mysqli::change_user</methodname></member>
|
||
<member><link linkend="mysqli.get-host-info">$mysqli::host_info</link></member>
|
||
<member><link linkend="mysqli.configuration">Opciones de configuración de MySQLi</link></member>
|
||
<member><link linkend="features.persistent-connections">Conexiones persistentes a bases de datos</link></member>
|
||
</simplelist>
|
||
</para>
|
||
</section>
|
||
|
||
<section xml:id="mysqli.quickstart.statements">
|
||
<title>Ejecutar sentencias</title>
|
||
<para>
|
||
Las sentencias se pueden ejecutar con las funciones
|
||
<function>mysqli_query</function>, <function>mysqli_real_query</function>
|
||
y <function>mysqli_multi_query</function>.
|
||
La función <function>mysqli_query</function> es la más
|
||
común, y combina la sentencia de ejecucución con su
|
||
conjunto de resultados obtenido de un buffer, si lo hubiera, en una llamada.
|
||
Llamar a <function>mysqli_query</function> es idéntico que
|
||
llamar a <function>mysqli_real_query</function>
|
||
seguido de <function>mysqli_store_result</function>.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Conectando a MySQL</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión con MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT)") ||
|
||
!$mysqli->query("INSERT INTO test(id) VALUES (1)")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Conjuntos de resultados almacenados en buffer</emphasis>
|
||
</para>
|
||
<para>
|
||
Después de la ejecución de sentencias, los resultados pueden recuperarse de una sola vez para que sean almacenados en buffer
|
||
por el cliente o leyendo fila a fila. El almacenamieno en buffer de conjuntos de resultados en el lado del cliente
|
||
permite al servidor liberar recursos asociados con los resultados de la
|
||
sentencia tan pronto como sea posible. Generalmente hablando, los clientes son lentos
|
||
consumiendo conjuntos de resultados. Por lo tanto, se recomienda usar conjuntos de resultados
|
||
almacenados en buffer. <function>mysqli_query</function> combina la ejecución de
|
||
sentencias y el almacenamiento en buffer de conjuntos de resultados.
|
||
</para>
|
||
<para>
|
||
Las aplicaciones de PHP pueden navegar libremente a través de resultados almacenados en buffer.
|
||
La navegación es más rápida debido a que los conjuntos de resultados se mantienen en la memoria del cliente.
|
||
Tenga en cuenta que a menudo es más fácil procesar datos en el cliente que
|
||
hacerlo el servidor.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Navegación a través de resultados almacenados en buffer</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT)") ||
|
||
!$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
$resultado = $mysqli->query("SELECT id FROM test ORDER BY id ASC");
|
||
|
||
echo "Orden inverso...\n";
|
||
for ($num_fila = $resultado->num_rows - 1; $num_fila >= 0; $num_fila--) {
|
||
$resultado->data_seek($num_fila);
|
||
$fila = $resultado->fetch_assoc();
|
||
echo " id = " . $fila['id'] . "\n";
|
||
}
|
||
|
||
echo "Orden del conjunto de resultados...\n";
|
||
$resultado->data_seek(0);
|
||
while ($fila = $resultado->fetch_assoc()) {
|
||
echo " id = " . $fila['id'] . "\n";
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Orden inverso...
|
||
id = 3
|
||
id = 2
|
||
id = 1
|
||
Orden del conjunto de resultados...
|
||
id = 1
|
||
id = 2
|
||
id = 3
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Conjuntos de resultados no almacenados en buffer</emphasis>
|
||
</para>
|
||
<para>
|
||
Si la memoria del cliente es un recurso escaso y no es necesaria la liberación de recursos
|
||
del servidor tan pronto como sea posible para mantener la carga del servidor baja,
|
||
se pueden usar conjuntos de resultados no almacenados en buffer. Recorrer resultados no almacenados en buffer
|
||
no es posible antes de que todas las filas hayan sido leídas.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Navegación a través de resultados no almacenados en buffer</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli->real_query("SELECT id FROM test ORDER BY id ASC");
|
||
$resultado = $mysqli->use_result();
|
||
|
||
echo "Orden del conjunto de resultados...\n";
|
||
while ($fila = $resultado->fetch_assoc()) {
|
||
echo " id = " . $fila['id'] . "\n";
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Tipos de datos de los valores del conjunto de resultados</emphasis>
|
||
</para>
|
||
<para>
|
||
Las funciones <function>mysqli_query</function>, <function>mysqli_real_query</function>
|
||
y <function>mysqli_multi_query</function> se usan para ejecutar
|
||
sentencias no preparadas. Al nivel del Protocolo Cliente Servidor de MySQL,
|
||
el comando <literal>COM_QUERY</literal> y el protocolo de texto se usan
|
||
para la ejecución de sentencias. Con el protocolo texto, el servidor MySQL convierte
|
||
todos los datos de los conjuntos de resultados en cadenas antes de enviarlos. Esta conversión se realiza
|
||
sin considerar el tipo de datos de las columnas del conjunto de resultados SQL. Las bibliotecas cliente de mysql
|
||
reciben todos los valores de las columnas como cadenas. No se realiza ninguna conversión del lado del cliente
|
||
pava volver a convertir las columnas a susu tipos nativos. En su lugar, todos los valores son
|
||
proporcionados como cadenas de PHP.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>El protocolo de texto devuelve cadenas de manera predeterminado</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT, etiqueta CHAR(1))") ||
|
||
!$mysqli->query("INSERT INTO test(id, etiqueta) VALUES (1, 'a')")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
$resultado = $mysqli->query("SELECT id, etiqueta FROM test WHERE id = 1");
|
||
$fila = $resultado->fetch_assoc();
|
||
|
||
printf("id = %s (%s)\n", $fila['id'], gettype($fila['id']));
|
||
printf("etiqueta = %s (%s)\n", $fila['etiqueta'], gettype($fila['etiqueta']));
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
id = 1 (string)
|
||
etiqueta = a (string)
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Es posible convertir valores de columnas de tipo integer y float a números de PHP estableciendo la
|
||
opción de conexión <constant>MYSQLI_OPT_INT_AND_FLOAT_NATIVE</constant>,
|
||
si se esta´utilizando la biblioteca mysqlnd. Si se establece, la biblioteca mysqlnd
|
||
comprobará los tipos de columna de los metadatos del conjunto de resultados y convertirá las columnas númerocas de SQL
|
||
a números de PHP, si el rango de valores del tipo de datos de PHP lo permite.
|
||
De esta forma, por ejemplo, las columnas INT de SQL son devueltas como enteros.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Tipos de datos nativos con mysqlnd y la opción de conexión</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = mysqli_init();
|
||
$mysqli->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, 1);
|
||
$mysqli->real_connect("ejemplo.com", "user", "contraseña", "basedatos");
|
||
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT, etiqueta CHAR(1))") ||
|
||
!$mysqli->query("INSERT INTO test(id, etiqueta) VALUES (1, 'a')")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
$resultado = $mysqli->query("SELECT id, etiqueta FROM test WHERE id = 1");
|
||
$fila = $resultado->fetch_assoc();
|
||
|
||
printf("id = %s (%s)\n", $fila['id'], gettype($fila['id']));
|
||
printf("etiqueta = %s (%s)\n", $fila['etiqueta'], gettype($fila['etiqueta']));
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
id = 1 (integer)
|
||
etiqueta = a (string)
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Véase también</emphasis>
|
||
</para>
|
||
<para>
|
||
<simplelist>
|
||
<member><methodname>mysqli::__construct</methodname></member>
|
||
<member><methodname>mysqli::init</methodname></member>
|
||
<member><methodname>mysqli::options</methodname></member>
|
||
<member><methodname>mysqli::real_connect</methodname></member>
|
||
<member><methodname>mysqli::query</methodname></member>
|
||
<member><methodname>mysqli::multi_query</methodname></member>
|
||
<member><methodname>mysqli::use_result</methodname></member>
|
||
<member><methodname>mysqli::store_result</methodname></member>
|
||
<member><methodname>mysqli_result::free</methodname></member>
|
||
</simplelist>
|
||
</para>
|
||
</section>
|
||
|
||
<section xml:id="mysqli.quickstart.prepared-statements">
|
||
<title>Sentencias Preparadas</title>
|
||
<para>
|
||
Las bases de datos MySQL soportan sentencias preparadas. Una sentencia preparada
|
||
o una sentencia parametrizada se usa para ejecutar la misma sentencia
|
||
repetidamente con gran eficiencia.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Flujo de trabajo básico</emphasis>
|
||
</para>
|
||
<para>
|
||
La ejecución de sentencias preparadas consiste en dos etapas:
|
||
la preparación y la ejecución. En la etapa de preparación se envía una plantilla de sentencia
|
||
al servidor de bases de datos. El servidor realiza una comprobación de sintaxis e inicializa
|
||
los recursos internos del servidor para su uso posterior.
|
||
</para>
|
||
<para>
|
||
El servidor de MySQL soporta el uso de parámetros de sustitución posicionales anónimos
|
||
con <literal>?</literal>.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Primera etapa: prepación</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
/* Sentencia no preparada */
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") || !$mysqli->query("CREATE TABLE test(id INT)")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
/* Sentencia preparada, etapa 1: preparación */
|
||
if (!($sentencia = $mysqli->prepare("INSERT INTO test(id) VALUES (?)"))) {
|
||
echo "Falló la preparación: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
La preparación es seguida de la ejecución. Durante la ejecución el cliente vincula
|
||
los valores de los parámetros y los envía al servidor. El servidor crea una
|
||
sentencia desde la plantilla de la sentencia y los valores vinculados para
|
||
ejecutarla usando los recursos internos previamente creados.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Segunda etapa: vincular y ejecutar</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
/* Sentencia preparada, etapa 2: vincular y ejecutar */
|
||
$id = 1;
|
||
if (!$sentencia->bind_param("i", $id)) {
|
||
echo "Falló la vinculación de parámetros: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
if (!$sentencia->execute()) {
|
||
echo "Falló la ejecución: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Ejecución repetida</emphasis>
|
||
</para>
|
||
<para>
|
||
Una sentencia preparada se puede ejecutar repetidamente. En cada ejecución
|
||
el valor actual de la variable vinculada se evalúa y se envía al servidor.
|
||
La sentencia no se analiza de nuevo. La plantilla de la sentencia no
|
||
es transferida otra vez al servidor.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>INSERT preparada una vez, ejecutada múltiples veces</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
/* Sentencia no preparada */
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") || !$mysqli->query("CREATE TABLE test(id INT)")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
/* Sentencia preparada, etapa 1: preparación */
|
||
if (!($sentencia = $mysqli->prepare("INSERT INTO test(id) VALUES (?)"))) {
|
||
echo "Falló la preparación: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
/* Sentencia preparada, etapa 2: vinculación y ejecución */
|
||
$id = 1;
|
||
if (!$sentencia->bind_param("i", $id)) {
|
||
echo "Falló la vinculación de parámetros: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
if (!$sentencia->execute()) {
|
||
echo "Falló la ejecución: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
/* Sentencia preparada: ejecución repetida, sólo datos transferidos desde el cliente al servidor */
|
||
for ($id = 2; $id < 5; $id++) {
|
||
if (!$sentencia->execute()) {
|
||
echo "Falló la ejecución: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
}
|
||
|
||
/* se recomienda el cierre explícito */
|
||
$sentencia->close();
|
||
|
||
/* Sentencia no preparada */
|
||
$resultado = $mysqli->query("SELECT id FROM test");
|
||
var_dump($resultado->fetch_all());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
array(4) {
|
||
[0]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "1"
|
||
}
|
||
[1]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "2"
|
||
}
|
||
[2]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "3"
|
||
}
|
||
[3]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "4"
|
||
}
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Cada sentencia preparada ocupa recursos del servidor.
|
||
Las sentencias deberían cerrarse explícitamente inmediatamente después de su uso.
|
||
Si no se realiza explícitamente, la sentencia será cerrada cuando
|
||
el gestor de la sentencia sea liberado por PHP.
|
||
</para>
|
||
<para>
|
||
Usar una sentencia preparada no es siempre la manera más
|
||
eficiente de ejecutar una sentencia. Una sentencia preparada ejecutada una sola
|
||
vez causa más viajes de ida y vuelta desde el cliente al servidor que una sentencia no preparada.
|
||
Es por esta razón por lo que <literal>SELECT</literal> no se ejecuta arriba como
|
||
una sentencia preparada.
|
||
</para>
|
||
<para>
|
||
También se ha de considerar el uso de la sintaxis SQL multi-INSERT de MySQL para sentencias INSERT.
|
||
Por ejemplo, multi-INSERT requiere menos viajes de ida y vuelta entre
|
||
el servidor y el cliente que la sentencia preparada mostrada arriba.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Menos viajes de ida y vuelta usando SQL multi-INSERT</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
if (!$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3), (4)")) {
|
||
echo "Falló multi-INSERT: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Tipos de datos de los valores del conjunto de resultados</emphasis>
|
||
</para>
|
||
<para>
|
||
El Protocolo Cliente Servidor de MySQL define un protocolo de transporte de datos diferente
|
||
para sentencias preparadas y no preparadas. Las sentencias preparadas
|
||
usan el llamado protocolo binario. El servidor de MySQL envía los datos
|
||
del conjunto de resultados "tal cual" en formato binario. Los resultados no son serializados en
|
||
cadenas antes del envío. Las bibliotecas cliente no reciben cadenas solamente.
|
||
En su lugar, recibirán datos binarios e intentarán convertir los valores a
|
||
los tipos de datos de PHP apropiados. Por ejemplo, los resultados de una columna
|
||
de SQL <literal>INT</literal> serán proporcionados como variables de tipo integer de PHP.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Tipos de datos nativos</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT, etiqueta CHAR(1))") ||
|
||
!$mysqli->query("INSERT INTO test(id, etiqueta) VALUES (1, 'a')")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
$sentencia = $mysqli->prepare("SELECT id, etiqueta FROM test WHERE id = 1");
|
||
$sentencia->execute();
|
||
$resultado = $sentencia->get_result();
|
||
$fila = $resultado->fetch_assoc();
|
||
|
||
printf("id = %s (%s)\n", $fila['id'], gettype($fila['id']));
|
||
printf("etiqueta = %s (%s)\n", $fila['etiqueta'], gettype($fila['etiqueta']));
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
id = 1 (integer)
|
||
etiqueta = a (string)
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Este comportamiento difiere de las sentencias no preparadas. Por defecto,
|
||
las sentencias no preparadas devolverán todos los resultados como cadenas.
|
||
Este comportamiento predeterminado se puede cambiar usand una opción de conexión.
|
||
Si se utiliza la opción de conexión no existirán diferencias.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Obtener resultados usando variables vinculadas</emphasis>
|
||
</para>
|
||
<para>
|
||
Los resultados de las sentencias preparadas pueden ser recuperados mediante
|
||
varibles de salida vinculadas, o por la petición de un objeto <classname>mysqli_result</classname>.
|
||
</para>
|
||
<para>
|
||
Las variables de salida deben ser vinculadas después de la ejecución de la sentencia.
|
||
Una variable debe estar vinculada para cada columna del conjunto de resultados de las sentencias.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Vinculación de variables de salida</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT, etiqueta CHAR(1))") ||
|
||
!$mysqli->query("INSERT INTO test(id, etiqueta) VALUES (1, 'a')")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!($sentencia = $mysqli->prepare("SELECT id, etiqueta FROM test"))) {
|
||
echo "Falló la preparación: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$sentencia->execute()) {
|
||
echo "Falló la ejecución: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
$id_salida = NULL;
|
||
$etiqueta_salida = NULL;
|
||
if (!$sentencia->bind_result($id_salida, $etiqueta_salida)) {
|
||
echo "Falló la vinculación de los parámetros de salida: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
while ($sentencia->fetch()) {
|
||
printf("id = %s (%s), etiqueta = %s (%s)\n", $id_salida, gettype($id_salida), $etiqueta_salida, gettype($etiqueta_salida));
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
id = 1 (integer), etiqueta = a (string)
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Las sentencias preparadas devuelven de manera predeterminada conjuntos de resultados no almacenados en buffer.
|
||
Los resultados de la sentencia no son obtenidas y transferidas implícitamente
|
||
desde el servidor al cliente para el almacenamiento en buffer de lado del cliente. El conjunto de resultados
|
||
toma recursos del servidor hasta que todos los resultados hayan sido obtenidos por el cliente.
|
||
Por lo que se recomienda consumir resultados cuando sea oportuno. Si un cliente falla al obtener todos
|
||
los resultados o el cliente cierra la consulta antes de haber obtenido todos los datos,
|
||
los datos han de ser obtenidos implícitamente por <literal>mysqli</literal>.
|
||
</para>
|
||
<para>
|
||
También es posible almacenar en buffer los resutados de una sentencia preparada
|
||
usando <function>mysqli_stmt_store_result</function>.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Obtener los resultados usando la interfaz mysqli_result</emphasis>
|
||
</para>
|
||
<para>
|
||
En lugar de usar resultados vinculados, los resultados también se pueden recuperar a través de la
|
||
interfaz mysqli_result. <function>mysqli_stmt_get_result</function>
|
||
devuelve un conjunto de resultados almacenado en buffer.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Usar mysqli_result para obtener los resultados</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT, etiqueta CHAR(1))") ||
|
||
!$mysqli->query("INSERT INTO test(id, etiqueta) VALUES (1, 'a')")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!($sentencia = $mysqli->prepare("SELECT id, etiqueta FROM test ORDER BY id ASC"))) {
|
||
echo "Falló la preparación: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$sentencia->execute()) {
|
||
echo "Falló la ejecución: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
if (!($resultado = $sentencia->get_result())) {
|
||
echo "Falló la obtención del conjunto de resultados: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
var_dump($resultado->fetch_all());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
array(1) {
|
||
[0]=>
|
||
array(2) {
|
||
[0]=>
|
||
int(1)
|
||
[1]=>
|
||
string(1) "a"
|
||
}
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Usar la <classname>interfaz mysqli_result</classname> ofrece el beneficio adicional de
|
||
la navegación flexible del conjunto de resultados en el lado del cliente.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Conjunto de resultados almacenado en buffer para la lectura flexible</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT, etiqueta CHAR(1))") ||
|
||
!$mysqli->query("INSERT INTO test(id, etiqueta) VALUES (1, 'a'), (2, 'b'), (3, 'c')")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!($sentencia = $mysqli->prepare("SELECT id, etiqueta FROM test"))) {
|
||
echo "Falló la preparación: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$sentencia->execute()) {
|
||
echo "Falló la ejecución: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
if (!($resultado = $sentencia->get_result())) {
|
||
echo "Falló la obtención del conjunto de resultados: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
for ($num_fila = ($resultado->num_rows - 1); $num_fila >= 0; $num_fila--) {
|
||
$resultado->data_seek($num_fila);
|
||
var_dump($resultado->fetch_assoc());
|
||
}
|
||
$resultado->close();
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
array(2) {
|
||
["id"]=>
|
||
int(3)
|
||
["etiqueta"]=>
|
||
string(1) "c"
|
||
}
|
||
array(2) {
|
||
["id"]=>
|
||
int(2)
|
||
["etiqueta"]=>
|
||
string(1) "b"
|
||
}
|
||
array(2) {
|
||
["id"]=>
|
||
int(1)
|
||
["etiqueta"]=>
|
||
string(1) "a"
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Escape de valores e inyección SQL</emphasis>
|
||
</para>
|
||
<para>
|
||
Las variables vinculadas son enviadas desde la consulta al servidor por separado, por lo que
|
||
no se puede interferir. El servidor usa estos valores directamente en el momento
|
||
de la ejecución, después de haber analizado la plantilla de la sentencia. Los parámetros vinculados no
|
||
necesitan ser escapados porque nunca son sustituidos directamente dentro del string de
|
||
consulta. Se puede proporcionar una sugerencia al servidor para el tipo de variable
|
||
vinculada, para crear una conversión apropiada.
|
||
Véase la función <function>mysqli_stmt_bind_param</function> para más
|
||
información.
|
||
</para>
|
||
<para>
|
||
A veces, tal separación es considerada como la única característica de seguridad para
|
||
evitar inyecciones SQL, pero se puede alcanzar el mismo grado de seguridad con
|
||
sentencias no preparadas, si todos los valores están formateados correctamente. Debería
|
||
observarse que el formateo correcto no es lo mismo que usar escapes, y que involucra
|
||
más lógica que simplemente usar escapes. Por lo tanto, las sentencias preparadas son sencillamente una
|
||
estrategia más conveniente y menos propensa a errores para este elemetno de seguridad de bases de datos.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Emulación de sentencias preparadas en el lado del cliente</emphasis>
|
||
</para>
|
||
<para>
|
||
La API no inclye la emulación para sentencias preparadas en el lado del cliente.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Comparación entre sentencias preparadas y no preparadas</emphasis>
|
||
</para>
|
||
<para>
|
||
La tabla de abajo compara las sentencias preparadas y no preparadas del lado del servidor.
|
||
</para>
|
||
<table>
|
||
<title>Comparación entre sentencias preparadas y no preparadas</title>
|
||
<tgroup cols="3">
|
||
<thead>
|
||
<row>
|
||
<entry></entry>
|
||
<entry>Sentencia preparada</entry>
|
||
<entry>Sentencia no preparada</entry>
|
||
</row>
|
||
</thead>
|
||
<tbody>
|
||
<row>
|
||
<entry>Viajes de ida y vuelta desde el cliente al servidor, SELECT, ejecución única</entry>
|
||
<entry>2</entry>
|
||
<entry>1</entry>
|
||
</row>
|
||
<row>
|
||
<entry>Cadenas de sentencias tranferidas desde el cliente al servidor</entry>
|
||
<entry>1</entry>
|
||
<entry>1</entry>
|
||
</row>
|
||
<row>
|
||
<entry>Viajes de ida y vuelta desde el cliente al servidor, SELECT, ejecución repetida (n)</entry>
|
||
<entry>1 + n</entry>
|
||
<entry>n</entry>
|
||
</row>
|
||
<row>
|
||
<entry>Cadenas de sentencias tranferidas desde el cliente al servidor</entry>
|
||
<entry>1 plantilla, n veces parametro vinculado, si existe</entry>
|
||
<entry>n veces junto con el parámetro, si existe</entry>
|
||
</row>
|
||
<row>
|
||
<entry>API de vinculación de parámetros de entrada</entry>
|
||
<entry>Sí, escape de entradas automático</entry>
|
||
<entry>No, escape de entradas manual</entry>
|
||
</row>
|
||
<row>
|
||
<entry>API de vinculación de variables de salida</entry>
|
||
<entry>Sí</entry>
|
||
<entry>No</entry>
|
||
</row>
|
||
<row>
|
||
<entry>Soporte para el uso de la API mysqli_result</entry>
|
||
<entry>Sí, use <function>mysqli_stmt_get_result</function></entry>
|
||
<entry>Sí</entry>
|
||
</row>
|
||
<row>
|
||
<entry>Conjuntos de resultados almacenados en buffer</entry>
|
||
<entry>
|
||
Sí, use <function>mysqli_stmt_get_result</function> o
|
||
la vinculación con <function>mysqli_stmt_store_result</function>
|
||
</entry>
|
||
<entry>Sí, lo predeterminado de <function>mysqli_query</function></entry>
|
||
</row>
|
||
<row>
|
||
<entry>Conjuntos de resultados no almacenados en buffer</entry>
|
||
<entry>Sí, use la API de vinculación de salida</entry>
|
||
<entry>
|
||
Sí, use <function>mysqli_real_query</function> con
|
||
<function>mysqli_use_result</function>
|
||
</entry>
|
||
</row>
|
||
<row>
|
||
<entry>"Sabor" de la transferencia de datos del protocolo Cliente Servidor de MySQL</entry>
|
||
<entry>Protocolo binario</entry>
|
||
<entry>Protocolo de texto</entry>
|
||
</row>
|
||
<row>
|
||
<entry>Tipos de datos SQL de los valores del conjunto de resultados</entry>
|
||
<entry>Preservados al obtenerlos</entry>
|
||
<entry>Convertidos a cadena o preservados al obetenerlos</entry>
|
||
</row>
|
||
<row>
|
||
<entry>Soporta todas las sentencia SQL</entry>
|
||
<entry>Versiones reciente de MySQL soportan muchas pero no todas</entry>
|
||
<entry>Sí</entry>
|
||
</row>
|
||
</tbody>
|
||
</tgroup>
|
||
</table>
|
||
<para>
|
||
<emphasis role="bold">Véase también</emphasis>
|
||
</para>
|
||
<para>
|
||
<simplelist>
|
||
<member><methodname>mysqli::__construct</methodname></member>
|
||
<member><methodname>mysqli::query</methodname></member>
|
||
<member><methodname>mysqli::prepare</methodname></member>
|
||
<member><methodname>mysqli_stmt::prepare</methodname></member>
|
||
<member><methodname>mysqli_stmt::execute</methodname></member>
|
||
<member><methodname>mysqli_stmt::bind_param</methodname></member>
|
||
<member><methodname>mysqli_stmt::bind_result</methodname></member>
|
||
</simplelist>
|
||
</para>
|
||
</section>
|
||
|
||
<section xml:id="mysqli.quickstart.stored-procedures">
|
||
<title>Procedimientos almacenados</title>
|
||
<para>
|
||
Las bases de datos de MySQL soportan procedimientos almacenados. Un procedimiento almacenado es una
|
||
subrutina almacenada en el catálogo de la base de datos. Las aplicaciones pueden llamar y
|
||
ejecutar el procedimiento almacenado. La sentencia de SQL <literal>CALL</literal>
|
||
se usa para ejecutar un procedimiento almacenado.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Parámetros</emphasis>
|
||
</para>
|
||
<para>
|
||
Los procedimientos almacenados pueden tener parámetros <literal>IN</literal>,
|
||
<literal>INOUT</literal> y <literal>OUT</literal>,
|
||
dependiendo de la versión de MySQL. La interfaz mysqli no tiene una noción
|
||
especial de los diferentes tipos de parámetros.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Parámetro IN</emphasis>
|
||
</para>
|
||
<para>
|
||
Los parámetros de entrada son proporcionados con la sentencia <literal>CALL</literal>.
|
||
Asegúrese de que los valores están escapados correctamente.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Llamar a un procedimiento almacenado</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") || !$mysqli->query("CREATE TABLE test(id INT)")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP PROCEDURE IF EXISTS p") ||
|
||
!$mysqli->query("CREATE PROCEDURE p(IN id_val INT) BEGIN INSERT INTO test(id) VALUES(id_val); END;")) {
|
||
echo "Falló la creación del procedimiento almacenado: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$mysqli->query("CALL p(1)")) {
|
||
echo "Falló CALL: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!($resultado = $mysqli->query("SELECT id FROM test"))) {
|
||
echo "Falló SELECT: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
var_dump($resultado->fetch_assoc());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
array(1) {
|
||
["id"]=>
|
||
string(1) "1"
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Parámetro INOUT/OUT</emphasis>
|
||
</para>
|
||
<para>
|
||
A los valores de los parámetros <literal>INOUT</literal>/<literal>OUT</literal>
|
||
se acceden usando variables de sesión.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Usar variables de sesión</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP PROCEDURE IF EXISTS p") ||
|
||
!$mysqli->query('CREATE PROCEDURE p(OUT msg VARCHAR(50)) BEGIN SELECT "¡Hola!" INTO msg; END;')) {
|
||
echo "Falló la creación del procedimiento almacenado: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
|
||
if (!$mysqli->query("SET @msg = ''") || !$mysqli->query("CALL p(@msg)")) {
|
||
echo "Falló CALL: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!($resultado = $mysqli->query("SELECT @msg as _p_out"))) {
|
||
echo "Falló la obtención: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
$fila = $resultado->fetch_assoc();
|
||
echo $fila['_p_out'];
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
¡Hola!
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Los desarrolladores de aplicaciones y framework pueden proporcionar una API más
|
||
conveniente usando una mezcla de variables de sesiones e inspección del catálogo de la base de datos.
|
||
Sin embargo, observe el posible impacto de rendimiento de una solución
|
||
personalizada basada en la inspección del catálogo.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Manejar conjuntos de resultados</emphasis>
|
||
</para>
|
||
<para>
|
||
Los procedimientos almacenados pueden devolver conjuntos de resultados. Los conjuntos de resultados devueltos desde
|
||
un procedimiento almacenado no se pueden obtener correctgamente usando <function>mysqli_query</function>.
|
||
La función <function>mysqli_query</function> combina la ejecución de la sentencia
|
||
y la obtención del primer conjunto de resultados dentro de un conjunto de resultados almacenado en buffer, si existe.
|
||
Sin embargo, existen unos conjuntos de resultados del procedimiento almacenado ocultos
|
||
para el usuario que hacen que <function>mysqli_query</function> falle
|
||
al devolver los conjuntos de resultados esperados por el usuario.
|
||
</para>
|
||
<para>
|
||
Los conjuntos de resultados devueltos desde un procedimiento almacenado son obtenidos usando
|
||
<function>mysqli_real_query</function> o <function>mysqli_multi_query</function>.
|
||
Ambas funciones permiten la obtención de cualquier número de conjuntos de resultados devueltos
|
||
por una sentencia, como <literal>CALL</literal>. El fallo de la obtención de todos
|
||
los conjuntos de resultados devueltos por un procedimiento almacenado causa un error.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Obtener los resultados de procedimientos almacenados</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT)") ||
|
||
!$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP PROCEDURE IF EXISTS p") ||
|
||
!$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test; SELECT id + 1 FROM test; END;')) {
|
||
echo "Falló la creación del procedimiento almacenado: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$mysqli->multi_query("CALL p()")) {
|
||
echo "Falló CALL: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
do {
|
||
if ($resultado = $mysqli->store_result()) {
|
||
printf("---\n");
|
||
var_dump($resultado->fetch_all());
|
||
$resultado->free();
|
||
} else {
|
||
if ($mysqli->errno) {
|
||
echo "Store failed: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
}
|
||
} while ($mysqli->more_results() && $mysqli->next_result());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
---
|
||
array(3) {
|
||
[0]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "1"
|
||
}
|
||
[1]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "2"
|
||
}
|
||
[2]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "3"
|
||
}
|
||
}
|
||
---
|
||
array(3) {
|
||
[0]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "2"
|
||
}
|
||
[1]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "3"
|
||
}
|
||
[2]=>
|
||
array(1) {
|
||
[0]=>
|
||
string(1) "4"
|
||
}
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Uso de sentencias preparadas</emphasis>
|
||
</para>
|
||
<para>
|
||
No es necesario un trato especial al usar la interfaz de sentencias
|
||
preparadas para obtener los resultados del mismo procedimiento almacenado de arriba.
|
||
Las interfaces de sentencias preparadas y no preparadas son similares.
|
||
Obserque que no todas las versioines del servidor de MYSQL pueden soportar
|
||
la preparación de la sentencia SQL <literal>CALL</literal>.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Procedimientos Almacenados y Sentencias Preparadas</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") ||
|
||
!$mysqli->query("CREATE TABLE test(id INT)") ||
|
||
!$mysqli->query("INSERT INTO test(id) VALUES (1), (2), (3)")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP PROCEDURE IF EXISTS p") ||
|
||
!$mysqli->query('CREATE PROCEDURE p() READS SQL DATA BEGIN SELECT id FROM test; SELECT id + 1 FROM test; END;')) {
|
||
echo "Falló la creación del procedimiento almacenado: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!($sentencia = $mysqli->prepare("CALL p()"))) {
|
||
echo "Falló la preparación: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$sentencia->execute()) {
|
||
echo "Falló la ejecución: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
do {
|
||
if ($resultado = $sentencia->get_result()) {
|
||
printf("---\n");
|
||
var_dump(mysqli_fetch_all($resultado));
|
||
mysqli_free_result($resultado);
|
||
} else {
|
||
if ($sentencia->errno) {
|
||
echo "Store failed: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
}
|
||
} while ($sentencia->more_results() && $sentencia->next_result());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Por supuesto, tamibién está soportado el uso de la API de vinculación para la obtención.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Procedimientos Almacenados y Sentencias Preparadas usando la API de vinculación</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
if (!($sentencia = $mysqli->prepare("CALL p()"))) {
|
||
echo "Falló la preparación: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
if (!$sentencia->execute()) {
|
||
echo "Falló la ejecución: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
do {
|
||
|
||
$id_out = NULL;
|
||
if (!$sentencia->bind_result($id_out)) {
|
||
echo "Falló la vinculiación: (" . $sentencia->errno . ") " . $sentencia->error;
|
||
}
|
||
|
||
while ($sentencia->fetch()) {
|
||
echo "id = $id_out\n";
|
||
}
|
||
} while ($sentencia->more_results() && $sentencia->next_result());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Véase también</emphasis>
|
||
</para>
|
||
<para>
|
||
<simplelist>
|
||
<member><methodname>mysqli::query</methodname></member>
|
||
<member><methodname>mysqli::multi_query</methodname></member>
|
||
<member><methodname>mysqli_result::next-result</methodname></member>
|
||
<member><methodname>mysqli_result::more-results</methodname></member>
|
||
</simplelist>
|
||
</para>
|
||
</section>
|
||
|
||
<section xml:id="mysqli.quickstart.multiple-statement">
|
||
<title>Sentencias Múltiples</title>
|
||
<para>
|
||
MySQL permite opcionalmente tener múltiples sentencias en una cadena de sentencias.
|
||
El envío de múltiples sentencias de una sola vez reduce los viajes de ida y vuelta desde
|
||
el cliente al servidor, pero requiere un manejo especial.
|
||
</para>
|
||
<para>
|
||
Las sentencias múltiples o multiconsultas deben ser ejecutadas
|
||
con <function>mysqli_multi_query</function>. Las sentencias individuales
|
||
de la cadena de sentencias están serparadas por un punto y coma.
|
||
Entonces, todos los conjuntos de resultados devueltos por las sentencias ejecutadas deben ser obtenidos.
|
||
</para>
|
||
<para>
|
||
El servidor MySQL permite tener sentencias que devuelven conjuntos de resultados y
|
||
sentencias que no devuelve conjuntos de resultados en una sentencia múltiple.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Sentencias múltiples</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
if (!$mysqli->query("DROP TABLE IF EXISTS test") || !$mysqli->query("CREATE TABLE test(id INT)")) {
|
||
echo "Falló la creación de la tabla: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
$sql = "SELECT COUNT(*) AS _num FROM test; ";
|
||
$sql.= "INSERT INTO test(id) VALUES (1); ";
|
||
$sql.= "SELECT COUNT(*) AS _num FROM test; ";
|
||
|
||
if (!$mysqli->multi_query($sql)) {
|
||
echo "Falló la multiconsulta: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
|
||
do {
|
||
if ($resultado = $mysqli->store_result()) {
|
||
var_dump($resultado->fetch_all(MYSQLI_ASSOC));
|
||
$resultado->free();
|
||
}
|
||
} while ($mysqli->more_results() && $mysqli->next_result());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
array(1) {
|
||
[0]=>
|
||
array(1) {
|
||
["_num"]=>
|
||
string(1) "0"
|
||
}
|
||
}
|
||
array(1) {
|
||
[0]=>
|
||
array(1) {
|
||
["_num"]=>
|
||
string(1) "1"
|
||
}
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Consideraciones de seguridad</emphasis>
|
||
</para>
|
||
<para>
|
||
Las funciones de la API <function>mysqli_query</function> y
|
||
<function>mysqli_real_query</function> no establecen una bandera de conexión necesaria
|
||
para activar las multiconsultas en el servidor. Se usa una llamada extra a la API para
|
||
las sentencias múltiples para reducir la verosimilitud de los ataques de inyecciones SQL
|
||
accidentales. Un atacante puede intentar añadir sentencias como
|
||
<literal>; DROP DATABASE mysql</literal> o <literal>; SELECT SLEEP(999)</literal>.
|
||
Si el atacante tiene éxito al añadir SQL a la cadena de sentencias pero
|
||
no se usa <literal>mysqli_multi_query</literal>, el servidor no
|
||
ejecutará la segunda sentencia SQL inyectada y maliciosa.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Inyección SQL</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
$resultado = $mysqli->query("SELECT 1; DROP TABLE mysql.user");
|
||
if (!$resultado) {
|
||
echo "Error al ejecutar la consulta: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
Error al ejecutar la consulta: (1064) You have an error in your SQL syntax;
|
||
check the manual that corresponds to your MySQL server version for the right syntax
|
||
to use near 'DROP TABLE mysql.user' at line 1
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Sentencias preparadas</emphasis>
|
||
</para>
|
||
<para>
|
||
El uso de sentencias múltiples con sentencias preparadas no está soportado.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">See also</emphasis>
|
||
</para>
|
||
<para>
|
||
<simplelist>
|
||
<member><methodname>mysqli::query</methodname></member>
|
||
<member><methodname>mysqli::multi_query</methodname></member>
|
||
<member><methodname>mysqli_result::next-result</methodname></member>
|
||
<member><methodname>mysqli_result::more-results</methodname></member>
|
||
</simplelist>
|
||
</para>
|
||
</section>
|
||
|
||
<section xml:id="mysqli.quickstart.transactions">
|
||
<title>Soporte de la API para transacciones</title>
|
||
<para>
|
||
El servidor MySQL soporta transacciones dependiendo de del motor de almacenamiento usado.
|
||
Desde MySQL 5.5, el motor de almacenamiento predeterminado es InnoDB.
|
||
InnoDB tiene soporte completo para transacciones ACID.
|
||
</para>
|
||
<para>
|
||
Las transacciones se pueden controlar usando SQL o llamadas a la API.
|
||
Se recomienda usar llamadas a la API para habilitar y deshabilitar el
|
||
modo de autoconsignación (auto commit) y para consignar y reiniciar transacciones.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Establecer el modo de autoconsignación con SQL y a través de la API</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
/* Recomendado: usar la API para cotrolar las configuraciones transaccionales */
|
||
$mysqli->autocommit(false);
|
||
|
||
/* No serán monitorizadas y reconocidas por la aplicación y el complemento de balance de carga */
|
||
if (!$mysqli->query('SET AUTOCOMMIT = 0')) {
|
||
echo "Falló la consulta: (" . $mysqli->errno . ") " . $mysqli->error;
|
||
}
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Los paquetes de características opcionales, como los comlementos de replicación y el de balance de carga,
|
||
pueden fácilmente monitorizar llamadas a la API. El complemento de replicación transacciones
|
||
conscientes del balance de carga, si las transacciones están controladas con llamadas a la API.
|
||
Las transacciones conscientes del balance de carga no están disponibles si las sentencias SQL se
|
||
usan para establecer el modo de autoconsignación, consignación y reinicio de una transacción.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Consignación y reinicio</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
$mysqli->autocommit(false);
|
||
|
||
$mysqli->query("INSERT INTO test(id) VALUES (1)");
|
||
$mysqli->rollback();
|
||
|
||
$mysqli->query("INSERT INTO test(id) VALUES (2)");
|
||
$mysqli->commit();
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
Observe que el servidor MySQL no puede reiniciar todas las sentencias.
|
||
Algunoas sentencias causan una consignación implícia.
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Véase también</emphasis>
|
||
</para>
|
||
<para>
|
||
<simplelist>
|
||
<member><methodname>mysqli::autocommit</methodname></member>
|
||
<member><methodname>mysqli_result::commit</methodname></member>
|
||
<member><methodname>mysqli_result::rollback</methodname></member>
|
||
</simplelist>
|
||
</para>
|
||
</section>
|
||
|
||
<section xml:id="mysqli.quickstart.metadata">
|
||
<title>Metadatos</title>
|
||
<para>
|
||
Un conjunto de resultados de MySQL contiene metadatos. Los metadatos describen las columnas
|
||
encontradas en el conjunto de resultados. Todos los metadatos enviados por MySQL son accesibles
|
||
a travbés de la interfaz de <literal>mysqli</literal>.
|
||
La extensión realiza cambios insignificantes o no realiza ninguno a la
|
||
información que recibe.
|
||
La diferencias entre versiones del servidor MySQL no están alineadas.
|
||
</para>
|
||
<para>
|
||
A los metadatos se puede acceder a través de la interfaz <classname>mysqli_result</classname>.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Acceder a los metadatos de un conjunto de resultados</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$mysqli = new mysqli("ejemplo.com", "usuario", "contraseña", "basedatos");
|
||
if ($mysqli->connect_errno) {
|
||
echo "Falló la conexión a MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
|
||
}
|
||
|
||
$resultado = $mysqli->query("SELECT 1 AS _one, 'Hello' AS _two FROM DUAL");
|
||
var_dump($resultado->fetch_fields());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
&example.outputs;
|
||
<screen>
|
||
<![CDATA[
|
||
array(2) {
|
||
[0]=>
|
||
object(stdClass)#3 (13) {
|
||
["name"]=>
|
||
string(4) "_one"
|
||
["orgname"]=>
|
||
string(0) ""
|
||
["table"]=>
|
||
string(0) ""
|
||
["orgtable"]=>
|
||
string(0) ""
|
||
["def"]=>
|
||
string(0) ""
|
||
["db"]=>
|
||
string(0) ""
|
||
["catalog"]=>
|
||
string(3) "def"
|
||
["max_length"]=>
|
||
int(1)
|
||
["length"]=>
|
||
int(1)
|
||
["charsetnr"]=>
|
||
int(63)
|
||
["flags"]=>
|
||
int(32897)
|
||
["type"]=>
|
||
int(8)
|
||
["decimals"]=>
|
||
int(0)
|
||
}
|
||
[1]=>
|
||
object(stdClass)#4 (13) {
|
||
["name"]=>
|
||
string(4) "_two"
|
||
["orgname"]=>
|
||
string(0) ""
|
||
["table"]=>
|
||
string(0) ""
|
||
["orgtable"]=>
|
||
string(0) ""
|
||
["def"]=>
|
||
string(0) ""
|
||
["db"]=>
|
||
string(0) ""
|
||
["catalog"]=>
|
||
string(3) "def"
|
||
["max_length"]=>
|
||
int(5)
|
||
["length"]=>
|
||
int(5)
|
||
["charsetnr"]=>
|
||
int(8)
|
||
["flags"]=>
|
||
int(1)
|
||
["type"]=>
|
||
int(253)
|
||
["decimals"]=>
|
||
int(31)
|
||
}
|
||
}
|
||
]]>
|
||
</screen>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Sentencias preparadas</emphasis>
|
||
</para>
|
||
<para>
|
||
A los metadatos de un conjunto de resultados creado usando sentencias preparadas se accede
|
||
de la misma manera. Un gestor de <classname>mysqli_result</classname> apropiado es
|
||
devuelto por <function>mysqli_stmt_result_metadata</function>.
|
||
</para>
|
||
<para>
|
||
<example>
|
||
<title>Metadatos de sentencias preparadas</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
$sentencia = $mysqli->prepare("SELECT 1 AS _one, 'Hello' AS _two FROM DUAL");
|
||
$sentencia->execute();
|
||
$resultado = $sentencia->result_metadata();
|
||
var_dump($resultado->fetch_fields());
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
<para>
|
||
<emphasis role="bold">Véase también</emphasis>
|
||
</para>
|
||
<para>
|
||
<simplelist>
|
||
<member><methodname>mysqli::query</methodname></member>
|
||
<member><methodname>mysqli_result::fetch_fields</methodname></member>
|
||
</simplelist>
|
||
</para>
|
||
</section>
|
||
</chapter>
|