<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Códice | Entradas sobre «bbdd»</title><description>Feed RSS de publicaciones etiquetadas con bbdd</description><link>https://javguerra.github.io/</link><item><title>Conexiones asíncronas a MySQL en Node.js</title><link>https://javguerra.github.io/blog/mysql-connect</link><guid isPermaLink="true">https://javguerra.github.io/blog/mysql-connect</guid><description>Usando util.promisify() para convertir en promesas conexiones síncronas de BBDD</description><pubDate>Wed, 14 Sep 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/mysql.CIjIICAX_2rcnGP.webp&quot; alt=&quot;MySQL&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#código&lt;/em&gt;, &lt;em&gt;#javascript&lt;/em&gt;, &lt;em&gt;#node.js&lt;/em&gt;, &lt;em&gt;#mysql&lt;/em&gt;, &lt;em&gt;#bbdd&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;El módulo &lt;code&gt;mysql&lt;/code&gt; de Node.js lleva a cabo conexiones a la BBDD empleando &lt;em&gt;callback&lt;/em&gt; para obtener los datos de las consultas SQL y no permite, por defecto, el uso de async/await. Al abrir la conexión, el resultado de estas consultas permanecerá dentro de la función &lt;em&gt;callback&lt;/em&gt;. En este artículo mostraré cómo convertir conexiones MySQL de Node.js en promesas que permitan el uso de async/await, pudiendo así extraer de la función el resultado de la consulta.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;note&quot;&gt;&lt;strong&gt;Nota:&lt;/strong&gt; Esta entrada es un ejercicio sin un sentido práctico específico en el que se hace uso del módulo mysql de Node.js. Para producción se recomienda el uso de mysql2, que incluye soporte para promesas, o el uso de un ORM como Sequelize.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Poder obtener los datos de la consulta SQL, en el flujo de nuestro programa, nos facilita la tarea de observar buenas prácticas que permitan separar las rutas de los controladores y los servicios. Con un módulo de conexión podemos realizar las consultas desde los servicios, y estos a su vez devolver el resultado al controlador que fue llamado desde la ruta.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;txt&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── controllers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── searchControllers.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── modules&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   ├── connection.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── utils.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── routes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── searchRoutes.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── services&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;│   └── searchServices.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;├── index.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pongamos que llega una consulta a la ruta de nuestra API que es gestionada por &lt;code&gt;searchRoutes.js&lt;/code&gt;, esta emplea una función del controlador que importa de &lt;code&gt;searchControllers.js&lt;/code&gt; que procesa la consulta, y que a su vez llama a una función del servicio &lt;code&gt;searchServices.js&lt;/code&gt; que se encarga de hacer la petición SQL a la BBDD.&lt;/p&gt;
&lt;p&gt;Dado que todas las peticiones a la BBDD son análogas (abrir conexión, hacer petición, devolver resultado) he creado una función llamada &lt;code&gt;getMysqlDbList()&lt;/code&gt; que he colocado en un módulo llamado &lt;code&gt;utils.js&lt;/code&gt; que importo y uso en &lt;code&gt;searchServices.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La función &lt;code&gt;getMysqlDbList()&lt;/code&gt; se encargará de hacer la conexión a la base de datos, realizar la consulta y cerrar la conexión, apoyándose en el módulo &lt;code&gt;connection.js&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;un-ejemplo&quot;&gt;Un ejemplo&lt;/h1&gt;
&lt;p&gt;Pongamos que tenemos un frontal desde el que queremos obtener todos los productos de la BBDD. Veamos ejemplos de cada uno de los ficheros mencionados sin tener mucho en cuenta en este caso las pertinentes comprobaciones de los datos recibidos para simplificar el código.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;searchRoutes.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; express&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;express&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; router&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; express.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Router&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; getAllProducts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;../controllers/searchControllers&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;router.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, getAllProducts);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; router;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Por supuesto, este módulo será importado en &lt;code&gt;index.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;searchControllers.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; searchServices&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;../services/searchServices&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getAllProducts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;res&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; products&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; searchServices.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;getAllProducts&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    res.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(products);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; getAllProducts;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;searchServices.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;getMysqlDbList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;../modules/utils&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getAllProducts&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;SELECT * FROM products&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getMysqlDbList&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { getAllProducts };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;la-consulta&quot;&gt;La consulta&lt;/h2&gt;
&lt;p&gt;Para que esta línea &lt;code&gt;return getMysqlDbList(request);&lt;/code&gt; en &lt;code&gt;searchServices.js&lt;/code&gt; funcione, la función &lt;code&gt;getMysqlDbList()&lt;/code&gt; en &lt;code&gt;utils.js&lt;/code&gt; debe devolver el resultado de la consulta. El código debería ser algo como esto:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;utils.js&lt;/code&gt; (no lo usaremos de esta forma)&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; client&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;../modules/connection&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getMysqlDbList&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; list&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; client.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;El problema es que la consultas a mysql en Node.js no soportan async/await. Una conexión mysql entonces tendría esta forma, empleando una función &lt;em&gt;callback&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;utils.js&lt;/code&gt; (no lo usaremos de esta forma)&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; connection&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;../modules/connection&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getMysqlDbList&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    connection.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;results&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;fields&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (error) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;throw&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; error;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        results.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;result&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(result);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Como se aprecia, &lt;code&gt;results&lt;/code&gt; está dentro de la función &lt;em&gt;callback&lt;/em&gt; que obtiene los datos de la consulta y desde dentro de esta función no puedo hacer un &lt;code&gt;return&lt;/code&gt; para devolver los productos como resultado de la función &lt;code&gt;getMysqlDbList()&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;la-conexión&quot;&gt;La conexión&lt;/h2&gt;
&lt;p&gt;Una conexión típica a la BBDD, cuyo código estaría en &lt;code&gt;connection.js&lt;/code&gt;, podría ser:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;connection.js&lt;/code&gt; (no lo usaremos de esta forma)&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; mysql&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;mysql&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;production&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;dotenv&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; connection&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mysql.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;createConnection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    host : process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_HOST&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    database : process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_DATABASE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    user : process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_USERNAME&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    password : process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_PASSWORD&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    port : process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_PORT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;connection.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;connect&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;err&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Error de conexión: &apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; err.stack);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Conectado con el identificador &apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connection.threadId);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; connection;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A continuación mostraré los cambios que sufrirá este fichero.&lt;/p&gt;
&lt;h1 id=&quot;promisificación&quot;&gt;Promisificación&lt;/h1&gt;
&lt;p&gt;Node.js tiene un módulo &lt;code&gt;util&lt;/code&gt; con algunas funciones, entre ellas &lt;code&gt;promisify()&lt;/code&gt; que permite la conversión de una función que acepta un &lt;em&gt;callback&lt;/em&gt; a una función que devuelve una promesa. A este cambio se le conoce con el aparatoso y extraño nombre de &lt;code&gt;Promisificación&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Con esta función podemos convertir nuestra consulta a la base de datos basada en &lt;em&gt;callback&lt;/em&gt; a una promesa que puede usar async/await para devolver la info resultante de la consulta, pero esto no está exento de inconvenientes. Como necesito cerrar la conexión tras la consulta SQL, lo que haré es crear una función en &lt;code&gt;connection.js&lt;/code&gt; que exportaré junto con los datos de conexión para ser usados por &lt;code&gt;getMysqlDbList()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;connection.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; util&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;util&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; mysql&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;mysql&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;NODE_ENV&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; !==&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;production&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;dotenv&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    host: process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_HOST&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    database: process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_DATABASE&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    user: process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_USERNAME&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    password: process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_PASSWORD&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    port: process.env.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;DB_PORT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; makeDb&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; connection&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; mysql.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;createConnection&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        query&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;sql&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;args&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; util.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;promisify&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(connection.query)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;                .&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(connection, sql, args);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        close&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; util.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;promisify&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(connection.end).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;call&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(connection);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {config, makeDb};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Como se aprecia, importo el módulo &lt;code&gt;util&lt;/code&gt; del que utilizaré su función &lt;code&gt;promisify()&lt;/code&gt;. Nótese que este &lt;code&gt;util&lt;/code&gt; no se refiere a mi módulo &lt;code&gt;utils.js&lt;/code&gt; en la carpeta &lt;code&gt;modules&lt;/code&gt;, sino al módulo por defecto de Node.js.&lt;/p&gt;
&lt;p&gt;Defino los datos de configuración en un objeto, y creo una función &lt;code&gt;makeDb()&lt;/code&gt; que recibe como parámetro la configuración para establecer la conexión (&lt;code&gt;mysql.createConnection(config)&lt;/code&gt;) y que devuelve mediante &lt;em&gt;return&lt;/em&gt; dos funciones en un objeto: &lt;code&gt;query()&lt;/code&gt; y &lt;code&gt;close()&lt;/code&gt;. Con &lt;code&gt;.call()&lt;/code&gt; indico los parámetros de la función que va a ser convertida en promesa.&lt;/p&gt;
&lt;p&gt;Con la exportación de &lt;code&gt;config&lt;/code&gt; y &lt;code&gt;makeDb()&lt;/code&gt; tengo lo necesario para realizar una consulta a la BBDD desde &lt;code&gt;getMysqlDbList()&lt;/code&gt; en &lt;code&gt;utils.js&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;la-función-getmysqldblist&quot;&gt;La función getMysqlDbList()&lt;/h1&gt;
&lt;p&gt;{: .box-warning}
&lt;strong&gt;Advertencia:&lt;/strong&gt; En líneas generales no es buena idea conectar y desconectar a la BBDD en cada &lt;em&gt;request&lt;/em&gt; ya que se introduce esa latencia en cada solicitud, por tanto esta es una solución que puede y debe ser mejorada en el futuro.&lt;/p&gt;
&lt;p&gt;El siguiente código muestra cómo ha quedado la función &lt;code&gt;getMysqlDbList()&lt;/code&gt; dentro del fichero &lt;code&gt;utils.js&lt;/code&gt; definitivo (Obviar los anteriores ejemplos de utils.js):&lt;/p&gt;
&lt;p&gt;&lt;code&gt;utils.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;config&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;makeDb&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; require&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;./connection&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * Obtiene un listado de la BBDD MySQL mediante consulta SQL.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@param&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; {String}&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; request&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; * &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@returns&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; Object&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; getMysqlDbList&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#FFAB70&quot;&gt;request&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; db&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; makeDb&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(config);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    try&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; db.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;query&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(request);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;catch&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;        console.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;finally&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        await&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; db.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;close&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importo &lt;code&gt;config&lt;/code&gt; y &lt;code&gt;makeDb()&lt;/code&gt; para poder establecer la conexión a la BBDD mediante: &lt;code&gt;const db = makeDb(config);&lt;/code&gt;. Al llamar a &lt;code&gt;makeDb()&lt;/code&gt; pasándole el parámetro &lt;code&gt;config&lt;/code&gt; se inicia la conexión a la BBDD, y en &lt;code&gt;db&lt;/code&gt; se guarda el objeto con las funciones &lt;code&gt;query()&lt;/code&gt; y &lt;code&gt;close()&lt;/code&gt; que uso a continuación.&lt;/p&gt;
&lt;p&gt;Con &lt;code&gt;list = await db.query(request);&lt;/code&gt; realizo la consulta a la BBDD. Por supuesto &lt;code&gt;request&lt;/code&gt; es un parámetro que nos llega desde el servicio en &lt;code&gt;searchServices.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Por último, con &lt;code&gt;await db.close()&lt;/code&gt; cierro la conexión a la BBDD.&lt;/p&gt;
&lt;p&gt;Ahora, con &lt;code&gt;return list&lt;/code&gt; puedo devolver el resultado obtenido de la BBDD al servicio;&lt;/p&gt;
&lt;h1 id=&quot;resumiendo&quot;&gt;Resumiendo&lt;/h1&gt;
&lt;p&gt;Al hacer una petición a la ruta de nuestra API, esta llama a una función en el controlador encargada de procesar los datos recibidos en la petición que a su vez llama a una función en el servicio encargado de hacer la consulta a la BBDD.&lt;/p&gt;
&lt;p&gt;La función del servicio llama a una función en el fichero utils.js que se ocupa de establecer la conexión, realizar la consulta a la BBDD y cerrar la conexión. Esta función se externaliza porque, generalmente, su funcionalidad es la misma para cada consulta a la BBDD en cada servicio, cambiando sólo la consulta SQL a realizar.&lt;/p&gt;
&lt;p&gt;Para poder ejecutar esta función en el fichero utils.js se requiere del módulo de conexión que exporta tanto los datos de conexión como una función que permite realizar la conexión a la BBDD, la consulta y el cierre de la conexión, de tal forma que pueda usarse con async/await.&lt;/p&gt;
&lt;h1 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Página de la que he obtenido la pista para resolver esta cuestión &lt;a href=&quot;https://codeburst.io/node-js-mysql-and-async-await-6fb25b01b628&quot;&gt;Node.js, MySQL and async/await&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;La función util.promisify() en Node.js &lt;a href=&quot;https://nodejs.org/dist/latest-v8.x/docs/api/util.html#util_util_promisify_original&quot;&gt;util.promisify()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Usando el método .call &lt;a href=&quot;https://dev.to/imsergiobernal/para-que-sirven-los-metodos-call-y-apply-en-javascript-4bj2&quot;&gt;¿Para qué sirven los métodos .call() y .apply() en JavaScript?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Libreria alternativa que incluye promesas (Aportada por borja) &lt;a href=&quot;https://www.npmjs.com/package/mysql2&quot;&gt;Node MySQL 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ORM: &lt;a href=&quot;https://sequelize.org/&quot;&gt;Sequelize&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Ejemplo de uso de pool de conexiones mysql, aportado por Jose, de «Desarrollo útil». &lt;a href=&quot;https://github.com/bezkoder/nodejs-express-mysql&quot;&gt;Node.js Rest APIs with Express &amp;amp; MySQL example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/mysql.CIjIICAX_2rcnGP.webp"/><category>código</category><category>javascript</category><category>node.js</category><category>mysql</category><category>bbdd</category><author>JavGuerra</author></item><item><title>Docker LAMP</title><link>https://javguerra.github.io/blog/docker-lamp</link><guid isPermaLink="true">https://javguerra.github.io/blog/docker-lamp</guid><description>Linux, Apache, MySQL y PHP con Docker</description><pubDate>Wed, 11 Sep 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/docker-lamp.BGQIH6q5_9u8Ft.webp&quot; alt=&quot;Logos de Docker y LAMP&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#bbdd&lt;/em&gt;, &lt;em&gt;#mysql&lt;/em&gt;, &lt;em&gt;#php&lt;/em&gt;, &lt;em&gt;#docker&lt;/em&gt;, &lt;em&gt;#servidor&lt;/em&gt;, &lt;em&gt;#apache&lt;/em&gt;, &lt;em&gt;#programación&lt;/em&gt;, &lt;em&gt;#internet&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Entre las herramientas de desarrollo web más comunes no falta el entorno de ejecución. Se hace lento desplegar los cambios al servidor con cada modificación del código que queremos probar. Para evitar esto se creó &lt;a href=&quot;https://es.wikipedia.org/wiki/LAMP&quot;&gt;LAMP&lt;/a&gt;, que es una combinación de Linux, Apache, MySQL (o MariaDB) y PHP que permite que se puedan ejecutar aplicaciones web en local. Este artículo pretende mostrar cómo se puede instalar y ejecutar este entorno de desarrollo web en un sistema Linux usando Docker.&lt;/p&gt;
&lt;p&gt;La principal ventaja de usar Docker es la de poder contar en el desarrollo con una infraestructura análoga a la del despliegue, con el mismo versionado y configuraciones de los servicios.&lt;/p&gt;
&lt;p&gt;Los contenedores son unidades ligeras y portátiles que empaquetan el código y todas sus dependencias para ejecutarse de forma independiente en cualquier sistema que soporte Docker.&lt;/p&gt;
&lt;p&gt;El lector debe conocer Docker para seguir correctamente este artículo, no obstante, siguiendo los pasos indicados aquí se podrá levantar un entorno de desarrollo web LAMP en un sistema Linux sin mayor inconveniente.&lt;/p&gt;
&lt;h1 id=&quot;instalación-de-docker-y-docker-compose&quot;&gt;Instalación de Docker y Docker Compose&lt;/h1&gt;
&lt;p&gt;Será necesario tener instalado &lt;a href=&quot;https://es.wikipedia.org/wiki/Docker&quot;&gt;Docker&lt;/a&gt; en el sistema para poder ejecutar el entorno de desarrollo web.&lt;/p&gt;
&lt;p&gt;Junto con Docker, vamos a instalar &lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose&lt;/a&gt;, una herramienta que permite ejecutar varios servicios de Docker a la vez.&lt;/p&gt;
&lt;p&gt;Una vez tengamos ambos instalados, necesitaremos crear un fichero de configuración llamado &lt;code&gt;docker-compose.yml&lt;/code&gt; que contendrá la configuración de los servicios que se va a desplegar, y accesoriamente, un fichero &lt;code&gt;Dockerfile&lt;/code&gt; que contendrá las configuraciones comple,entarias necesarias.&lt;/p&gt;
&lt;p&gt;Por último, veremos como ejecutar y parar el entorno de desarrollo web.&lt;/p&gt;
&lt;h2 id=&quot;docker&quot;&gt;Docker&lt;/h2&gt;
&lt;p&gt;Para instalar Docker, necesitaremos cumplir con algunas dependencias:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt-transport-https&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ca-certificates&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; curl&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; gnupg&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; lsb-release&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; software-properties-common&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Podemos seguir la &lt;a href=&quot;https://docs.docker.com/engine/install/&quot;&gt;documentación oficial&lt;/a&gt; o usar el meta-paquete docker-ce, la última versión de Docker:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt-get&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; docker-io&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Posteriormente se añade nuestro usuario al grupo docker. Esto nos permitirá ejecutar comandos de Docker sin necesidad de tener permisos de superusuario:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; usermod&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -aG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; docker&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; $USER&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Una vez instalado, se puede comprobar que se está ejecutando Docker usando el siguiente comando:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;docker-compose&quot;&gt;Docker Compose&lt;/h2&gt;
&lt;p&gt;Para instalar Docker Compose se puede usar el siguiente comando:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; docker-compose&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Luego se puede comprobar que se está ejecutando Docker Compose usando el siguiente comando:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;docker-compose&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --version&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ya tenemos todo lo necesario para instalar el entorno de desarrollo web LAMP.&lt;/p&gt;
&lt;h1 id=&quot;stack-lamp-con-docker&quot;&gt;Stack LAMP con Docker&lt;/h1&gt;
&lt;p&gt;Para facilitar su despliegue, uso un fichero llamado &lt;code&gt;docker-compose.yml&lt;/code&gt; que contiene la configuración de los servicios que se va a desplegar.&lt;/p&gt;
&lt;h2 id=&quot;contenido-del-fichero-docker-composeyml&quot;&gt;Contenido del fichero docker-compose.yml&lt;/h2&gt;
&lt;p&gt;Mediante el siguiente fichero se configuran y lanzan los diferentes contenedores, volúmenes y redes del entorno para tres servicios: &lt;code&gt;www&lt;/code&gt;, &lt;code&gt;db&lt;/code&gt; y &lt;code&gt;phpmyadmin&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;3.1&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;services&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    www&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        ports&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;8081:80&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        volumes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;www:/var/www/html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        depends_on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        networks&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    db&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        image&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;mysql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        ports&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;3306:3306&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        command&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;--default-authentication-plugin=mysql_native_password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        environment&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;            MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;example&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        volumes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;./dump:/docker-entrypoint-initdb.d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;./conf:/etc/mysql/conf.d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;persistent:/var/lib/mysql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        networks&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    phpmyadmin&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        image&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;phpmyadmin/phpmyadmin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        depends_on&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;db&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;        ports&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;            - &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;8080:80&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;volumes&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;    persistent&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Este fichero está escrito en formato &lt;a href=&quot;https://es.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt;, que es un lenguaje de marcado de datos, que permite definir la estructura de un fichero de configuración de forma legible y fácil de entender. Como en Python, los espacios son importantes aquí.&lt;/p&gt;
&lt;p&gt;El contenedor &lt;code&gt;www&lt;/code&gt; será el encargado de gestionar el servidor web, y PHP. Por su parte, el contenedor &lt;code&gt;db&lt;/code&gt; se ocupará de la base de datos MySQL y &lt;code&gt;phpmyadmin&lt;/code&gt; lo hará del entorno de administración de la BBDD.&lt;/p&gt;
&lt;p&gt;Por cada servicio, se detallan algunos valores de configuración, como los puertos o las claves de acceso. En el caso de &lt;code&gt;www&lt;/code&gt; es destacable que se hace uso de un fichero dockerfile externo con:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#85E89D&quot;&gt;build&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;El volumen (&lt;em&gt;volumes&lt;/em&gt;) almacena y gestiona datos persistentes generados por los contenedores, permitiendo que los datos cruciales de la aplicación no se pierdan durante operaciones rutinarias, estando disponibles aunque los contenedores dejen de estar operativos, compartiendo los datos entre uno o varios contenedores.&lt;/p&gt;
&lt;p&gt;Las redes (&lt;em&gt;networks&lt;/em&gt;) permiten la comunicación entre contenedores y con el mundo exterior, facilitando la conexión entre contenedores en la misma red o con servicios externos, y proporcionando un entorno aislado para la red de contenedores.&lt;/p&gt;
&lt;h2 id=&quot;contenido-del-fichero-dockerfile&quot;&gt;Contenido del fichero Dockerfile&lt;/h2&gt;
&lt;p&gt;Para su completo despliegue, el servicio &lt;code&gt;www&lt;/code&gt; hace uso de un fichero Dockerfile que añade las configuraciones necesarias para obtener PHP, MySQL y varios compresores:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;FROM&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; php:8.0.0-apache&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ARG&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; DEBIAN_FRONTEND=noninteractive&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; docker-php-ext-install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; mysqli&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; apt-get&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; update&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; libzip-dev&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;apt-get&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -y&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; zlib1g-dev&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;rm&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -rf&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /var/lib/apt/lists/&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;docker-php-ext-install&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; zip&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;RUN&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; a2enmod&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; rewrite&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Lo guardo con el nombre &lt;code&gt;Dockerfile&lt;/code&gt;. Tanto el fichero &lt;code&gt;docker-compose.yml&lt;/code&gt; como el &lt;code&gt;Dockerfile&lt;/code&gt; han de estar en la misma ruta.&lt;/p&gt;
&lt;h2 id=&quot;ejecución-del-entorno-de-desarrollo-web&quot;&gt;Ejecución del entorno de desarrollo web&lt;/h2&gt;
&lt;p&gt;Para poder probar su correcto funcionamiento uso:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;docker-compose&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; up&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Esto levantará los contenedores. Si todo ha ido bien, se habrán descargado las imágenes correspondientes y lanzado los contenedores necesarios para disponer del entorno. Se puede obtener un listado de los contenedores levantados con:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;docker-compose&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; ps&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Para probar su correcto funcionamiento, podemos copiar aquello que deseemos mostrar en el navegador a la carpeta &lt;code&gt;www&lt;/code&gt; en la carpeta actual donde están los dos scripts, o bien podemos crear un fichero &lt;code&gt;index.php&lt;/code&gt; con sólo el código siguiente:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;php&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;php&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; phpinfo&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;( ); &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ahora debemos acceder al contenido mediante el navegador con la ruta:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;localhost 8001&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;8001 es el puerto descrito en el fichero &lt;code&gt;docker-compose.yml&lt;/code&gt; para el servidor web, pero podemos cambiarlo en el mismo fichero.&lt;/p&gt;
&lt;p&gt;Una vez ejecutado, si podemos ver la información en el navegador, es que Apache y PHP están funcionando adecuadamente.&lt;/p&gt;
&lt;p&gt;Para comprobar si MySQL y PHPMyAdmin están activos, accedemos a la misma dirección localhost pero por el puerto 8080:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;localhost:8080&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Para acceder podemos usar &lt;code&gt;root&lt;/code&gt; como usuario y &lt;code&gt;example&lt;/code&gt; como contraseña.&lt;/p&gt;
&lt;p&gt;Cuando terminemos, podemos detener los contenedores mediante:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;docker-compose&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; stop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;usando-docker-lamp-en-nuestros-desarrollos&quot;&gt;Usando Docker LAMP en nuestros desarrollos&lt;/h2&gt;
&lt;p&gt;Ahora podemos levantar y detener los contenedores mediante simples comandos y ubicar estos script y el contenido que estemos desarrollando en la carpeta &lt;code&gt;www&lt;/code&gt; de la misma manera que lo hicimos antes, y podemos mover toda esta estructura de ficheros a donde nos resulte más conveniente, o configurar el fichero &lt;code&gt;docker-compose.yml&lt;/code&gt; para que sepa encontrar la carpeta &lt;code&gt;www&lt;/code&gt; allá donde se ubique.&lt;/p&gt;
&lt;h1 id=&quot;bonus-portainer&quot;&gt;BONUS: Portainer&lt;/h1&gt;
&lt;p&gt;Para una gestión más cómoda de los contenedores y su monitorización, se puede usar &lt;a href=&quot;https://www.portainer.io/&quot;&gt;Portainer&lt;/a&gt;, un front end web local que se levanta como un contenedor más mediante:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; docker&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -itd&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; 9443:9443&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --name=portainer&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; --restart=always&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; -v&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; /docker/portainer:/data&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; portainer/portainer-ce&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Es posible acceder a él mediante la dirección localhost y el puerto 9443:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;localhost:9443&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Portainer&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;@/assets/img/portainer.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Mediante este entorno se puede hacer una gestión de los contenedores y su monitorización, como se ve en la imagen.&lt;/p&gt;
&lt;h1 id=&quot;saber-más&quot;&gt;Saber más&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://es.wikipedia.org/wiki/LAMP&quot;&gt;LAMP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://es.wikipedia.org/wiki/Docker&quot;&gt;Docker&lt;/a&gt; y &lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://es.wikipedia.org/wiki/YAML&quot;&gt;YAML&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://es.wikipedia.org/wiki/MySQL&quot;&gt;MySQL&lt;/a&gt;, &lt;a href=&quot;https://es.wikipedia.org/wiki/PHP&quot;&gt;PHP&lt;/a&gt; y &lt;a href=&quot;https://es.wikipedia.org/wiki/Apache_HTTP_Server&quot;&gt;Apache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://es.wikipedia.org/wiki/XAMPP&quot;&gt;XAMPP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.portainer.io/&quot;&gt;Portainer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/docker-lamp.BGQIH6q5_9u8Ft.webp"/><category>bbdd</category><category>mysql</category><category>php</category><category>docker</category><category>servidor</category><category>apache</category><category>programación</category><category>internet</category><author>JavGuerra</author></item><item><title>Acceder a BBDD Oracle con DBeaver</title><link>https://javguerra.github.io/blog/oracle-dbeaver</link><guid isPermaLink="true">https://javguerra.github.io/blog/oracle-dbeaver</guid><description>Configuración de la aplicación con los drivers originales</description><pubDate>Wed, 10 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/oracle-dbeaver.S-D27cKr_Z2a51YS.webp&quot; alt=&quot;Pantalla de ordenador con DBeaver conectado a BBDD Oracle&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#herramienta&lt;/em&gt;, &lt;em&gt;#servidor&lt;/em&gt;, &lt;em&gt;#bbdd&lt;/em&gt;, &lt;em&gt;#software libre&lt;/em&gt;, &lt;em&gt;#oracle&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;&lt;a href=&quot;https://dbeaver.io/&quot;&gt;DBeaver&lt;/a&gt; es una herramienta de gestión de bases de datos multiplataforma y de código abierto que permite conectarse y trabajar con distintos sistemas como Oracle, MySQL, PostgreSQL o SQL Server desde una única interfaz. Ofrece funcionalidades como ejecución de consultas SQL, exploración de estructuras, edición de datos y administración de conexiones, destacando por su flexibilidad y compatibilidad con múltiples drivers. En esta te explico cómo instalar los drivers originales de Oracle en DBeaver.&lt;/p&gt;
&lt;h2 id=&quot;descargando-dbeaver&quot;&gt;Descargando DBeaver&lt;/h2&gt;
&lt;p&gt;Puedes descargar la última versión de la aplicación desde:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://dbeaver.io/download/&quot;&gt;Download DBeaver Community&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hay disponibles versiones para Windows, macOS y Linux.&lt;/p&gt;
&lt;p&gt;Si vas a descargar la versión de Windows, dispones también de un fichero &lt;code&gt;.zip&lt;/code&gt; que no requiere instalación en el sistema. Tan sólo descomprimes la carpeta en el lugar que decidas y la aplicación estará lista para usarse.&lt;/p&gt;
&lt;h2 id=&quot;el-problema&quot;&gt;El problema&lt;/h2&gt;
&lt;p&gt;Elegí esta herramienta porque, como otras, me permite acceder a la BBDD desde mi entorno local, pero empleando los drivers originales de Oracle, con lo que consigo la máxima compatibilidad, con un software versátil y abierto. Pero al seguir los pasos para descargar automáticamente los drivers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Abrir DBeaver.&lt;/li&gt;
&lt;li&gt;Ir a &lt;code&gt;Database&lt;/code&gt; → &lt;code&gt;Driver Manager&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Buscar &lt;code&gt;Oracle&lt;/code&gt; en la lista y seleccionarlo.&lt;/li&gt;
&lt;li&gt;Pulsar &lt;code&gt;Edit&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ir a la pestaña &lt;code&gt;Libraries&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Y pulsar &lt;code&gt;Download/Update&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Obtuve un error. Ocurre que Oracle no permite la descarga automática directa en muchos casos, así que DBeaver falla.&lt;/p&gt;
&lt;h2 id=&quot;la-alternativa&quot;&gt;La alternativa&lt;/h2&gt;
&lt;p&gt;Descargar los drivers directamente desde la página de Oracle:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html&quot;&gt;Oracle Database JDBC driver and Companion Jars Downloads&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Deberás seleccionar los drivers adecuados. En mi caso decidí descargar el fichero &lt;code&gt;ojdbc11-full.tar.gz&lt;/code&gt; bajo el título &lt;code&gt;Zipped JDBC driver (ojdbc11.jar) and Companion Jars&lt;/code&gt; que viene con todos los ficheros necesarios y está certificado para las versiones JDK 11 de Java (en mi caso) y versiones superiores.&lt;/p&gt;
&lt;p&gt;Una vea descargado, hay que descomprimir el contenido en la carpeta que desees. También puedes descomprimirlo en la carpeta &lt;code&gt;pluggins&lt;/code&gt; dentro de la carpeta de DBeaver.&lt;/p&gt;
&lt;h2 id=&quot;instalando-los-drivers&quot;&gt;Instalando los drivers&lt;/h2&gt;
&lt;p&gt;El siguiente paso es instalar los drivers en la aplicación. Por defecto, DBeaver carga cuatro de ellos.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ojdbc11.jar&lt;/code&gt; (la versión para mi JDK.) Obligatorio. El driver JDBC principal de Oracle que permite la conexión a BBDD.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;orai18n.jar&lt;/code&gt; Recomendado. Es el soporte de internacionalización (i18n) que permite manejar caracteres especiales, codificaciones (UTF-8, etc.) y distintos idiomas correctamente.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xdb.jar&lt;/code&gt; Opcional. Librería para XML DB de Oracle si se trabaja con XML almacenado en la base de datos y se requieren funcionalidades avanzadas tipo XMLType.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xmlparserv2.jar&lt;/code&gt; Opcional. Parser XML de Oracle para procesar XML internamente y dar soporte a funcionalidades de xdb.jar.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Para ello debes estar en la pestaña &lt;code&gt;libraries&lt;/code&gt; del driver Oracle en la en la opción &lt;code&gt;Driver manager&lt;/code&gt; del menú &lt;code&gt;Database&lt;/code&gt;. Ver pasos para llegar más arriba. Y una vez allí:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pulsamos &lt;code&gt;Add File&lt;/code&gt;, seleccionamos cada fichero mencionado, y le damos a &lt;code&gt;Open&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Repetimos la opción por cada fichero.&lt;/li&gt;
&lt;li&gt;Una vez tenemos todos los drivers abiertos, ya no necesitamos los drivers que aparecen por defecto. Los quitamos con &lt;code&gt;Delete&lt;/code&gt; para que no den problemas.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;conectar-a-la-bbdd&quot;&gt;Conectar a la BBDD&lt;/h2&gt;
&lt;p&gt;Ahora ya podemos ver si todo ha ido bien.&lt;/p&gt;
&lt;p&gt;En el menú &lt;code&gt;Database&lt;/code&gt;, hacemos clic en la opción &lt;code&gt;New connection&lt;/code&gt; e introducimos los datos de la conexión. La nueva conexión a BBDD aparecerá en el espacio de conexiones de la izquierda.&lt;/p&gt;
&lt;h2 id=&quot;tips&quot;&gt;TIPs&lt;/h2&gt;
&lt;p&gt;Podemos arrastrar el nombre de la BBDD a &lt;code&gt;Bookmarks&lt;/code&gt; (Favoritos) en la lista de abajo, a la izquierda, para poder acceder de forma fácil a ella.&lt;/p&gt;
&lt;p&gt;También podemos poner DBeaver en español. Para esto iremos a &lt;code&gt;Windows&lt;/code&gt;, luego &lt;code&gt;Preferences&lt;/code&gt;, y en la opción &lt;code&gt;User Interface&lt;/code&gt; elegiremos el idioma español.&lt;/p&gt;
&lt;p&gt;Para más información sobre el uso de DBeaver, puedes consultar la documentación en el Wiki:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dbeaver/dbeaver/wiki&quot;&gt;About DBeaver&lt;/a&gt;&lt;/p&gt;
&lt;h1 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dbeaver.io/&quot;&gt;DBeaver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/dbeaver/dbeaver/wiki&quot;&gt;About DBeaver&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dbeaver.io/download/&quot;&gt;Download DBeaver Community&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html&quot;&gt;Oracle Database JDBC driver and Companion Jars Downloads&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/oracle-dbeaver.S-D27cKr_Z2a51YS.webp"/><category>herramienta</category><category>servidor</category><category>bbdd</category><category>software libre</category><category>oracle</category><author>JavGuerra</author></item><item><title>Oracle SQL Literal Converter</title><link>https://javguerra.github.io/blog/osqlc</link><guid isPermaLink="true">https://javguerra.github.io/blog/osqlc</guid><description>Sanitizando SQL para Oracle via web local o por línea de comandos</description><pubDate>Wed, 09 Sep 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/osqlc.e18iygQz_1cPFJ7.webp&quot; alt=&quot;Captura de pantalla de Oracle SQL Literal Converter&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#herramienta&lt;/em&gt;, &lt;em&gt;#sql&lt;/em&gt;, &lt;em&gt;#oracle&lt;/em&gt;, &lt;em&gt;#html&lt;/em&gt;, &lt;em&gt;#css&lt;/em&gt;, &lt;em&gt;#javascript&lt;/em&gt;, &lt;em&gt;#node.js&lt;/em&gt;, &lt;em&gt;#responsive&lt;/em&gt;, &lt;em&gt;#web&lt;/em&gt;, &lt;em&gt;#bbdd&lt;/em&gt;, &lt;em&gt;#código&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Cuando trabajas con bases de datos Oracle a través de herramientas de administración como SQL*Plus, SQL Developer, Toad o PL/SQL Developer, es casi inevitable chocarse antes o después con el mismo obstáculo frustrante: la gestión de literales de texto con caracteres especiales.&lt;/p&gt;
&lt;p&gt;Quien haya ejecutado alguna vez un INSERT o UPDATE con un texto como “Ibáñez &amp;amp; Asociados” sabrá exactamente de qué hablo. Por un lado, el símbolo del ampersand (&amp;amp;) hace que SQL*Plus se detenga pidiendo interactiva y molestamente el valor para una “variable de sustitución” &amp;amp;Asociados. Por otro lado, los caracteres con acentos, la ñ, los signos de apertura (¿, ¡) o los símbolos de moneda suelen corromperse si el cliente SQL y la base de datos no comparten exactamente la misma configuración NLS o codificación de caracteres.&lt;/p&gt;
&lt;p&gt;Para solucionar este dolor de cabeza, he desarrollado OSQLC (Oracle SQL Literal Converter).&lt;/p&gt;
&lt;p&gt;Puedes descargar el script o acceder a la página web desde el: &lt;a href=&quot;https://github.com/JavGuerra/oracle-sql-literal-converter&quot;&gt;&lt;button&gt;Repositorio del conversor&lt;/button&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;También puedes acceder directamente al conversor web desde: &lt;a href=&quot;https://javguerra.github.io/oracle-sql-literal-converter/&quot;&gt;Oracle SQL Literal Converter&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;cómo-funciona-la-sanitización&quot;&gt;¿Cómo funciona la sanitización?&lt;/h2&gt;
&lt;p&gt;La solución técnica más limpia en Oracle consiste en aislar los caracteres problemáticos y reemplazarlos por su función nativa chr(N) equivalente (basada en el juego de caracteres ISO-8859-1 / Latin-1), concatenándolos con el resto de la cadena.&lt;/p&gt;
&lt;p&gt;OSQLC analiza el script SQL y realiza esta transformación de forma transparente. Por ejemplo, convierte esta sentencia propensa a errores:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;INSERT INTO&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; clientes (nombre, direccion) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;VALUES&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Ibáñez &amp;amp; Asociados&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;C/ Ramón y Cajal, nº 45&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;En este otro código, seguro y portátil para cualquier entorno Oracle:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sql&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;INSERT INTO&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; clientes (nombre, direccion) &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;VALUES&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Ib&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chr(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;225&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chr(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;241&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;ez &apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chr(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;38&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos; Asociados&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;C/ Ram&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chr(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;243&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos;n y Cajal, n&apos;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ||&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; chr(&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;186&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;||&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; &apos; 45&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Además, el motor de procesado de OSQLC incluye características avanzadas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Respeto estricto de comentarios: Preserva intactos los comentarios de línea (–) y de bloque (/* … */) sin alterar su contenido.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Soporte para Cita Alternativa (q’…’): Procesa correctamente la sintaxis Alternative Quoting Mechanism de Oracle.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Control de saltos de línea: Convierte los retornos de carro (\n y \r) en chr(10) y chr(13), evitando que se rompa la sintaxis en literales multilínea.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;dos-versiones-para-cada-tipo-de-flujo-de-trabajo&quot;&gt;Dos versiones para cada tipo de flujo de trabajo&lt;/h2&gt;
&lt;p&gt;Para hacer la herramienta lo más versátil posible, la he estructurado en dos modalidades complementarias:&lt;/p&gt;
&lt;h3 id=&quot;1-versión-cli-nodejs&quot;&gt;1. Versión CLI (Node.js)&lt;/h3&gt;
&lt;p&gt;Pensada para desarrolladores, automatizaciones o integración en canalizaciones CI/CD y scripts de despliegue. Te permite procesar archivos .sql directamente desde la terminal con un comando sencillo:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; osqlc.js&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; mi_script.sql&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt; script_sanitizado.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;2-versión-web-htmljs-standalone&quot;&gt;2. Versión Web (HTML/JS Standalone)&lt;/h3&gt;
&lt;p&gt;Diseñada para un uso diario, rápido y visual desde cualquier navegador. Se trata de una interfaz web con estilo oscuro que funciona de forma 100% local (client-side).&lt;/p&gt;
&lt;p&gt;No requiere servidores, no instala nada y garantiza la privacidad total, ya que el código SQL jamás sale de tu navegador.&lt;/p&gt;
&lt;p&gt;Entre sus características destacan:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Drag &amp;amp; Drop: Arrastra directamente tus archivos .sql a la zona de carga.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Validación inteligente: Verifica que la extensión sea .sql o .txt y analiza el contenido en busca de palabras clave de SQL (como INSERT, SELECT, UPDATE), lanzando avisos si detecta un archivo incorrecto por error.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edición y descarga directa: Puedes pegar código a mano o descargar el archivo convertido con un solo clic.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;ventajas&quot;&gt;Ventajas&lt;/h2&gt;
&lt;p&gt;Con OSQLC, lo que antes requería reemplazar caracteres a mano de forma tediosa o lidiar con parámetros de sesión como SET DEFINE OFF, ahora se resuelve en un instante. Ya sea automatizando despliegues en la consola o arrastrando un archivo en la web, la sanitización queda cubierta de punta a punta.&lt;/p&gt;
&lt;p&gt;¿Te has encontrado con este problema en Oracle alguna vez? ¡Espero que la herramienta te sea tan útil en tu día a día como a mí!&lt;/p&gt;
&lt;h2 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h2&gt;
&lt;p&gt;Conoce todas las características de OSQLC:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JavGuerra/oracle-sql-literal-converter&quot;&gt;Repositorio del conversor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://javguerra.github.io/oracle-sql-literal-converter/&quot;&gt;Web de Oracle SQL Literal Converter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/osqlc.e18iygQz_1cPFJ7.webp"/><category>herramienta</category><category>sql</category><category>oracle</category><category>html</category><category>css</category><category>javascript</category><category>node.js</category><category>responsive</category><category>web</category><category>bbdd</category><category>código</category><author>JavGuerra</author></item><item><title>Apuntes TIC</title><link>https://javguerra.github.io/blog/apuntes</link><guid isPermaLink="true">https://javguerra.github.io/blog/apuntes</guid><description>Materiales de estudio sobre TIC y formaciones impartidas</description><pubDate>Thu, 12 Jan 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/apuntes.DFb5--bH_Z19gvuH.webp&quot; alt=&quot;Apuntes&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#código&lt;/em&gt;, &lt;em&gt;#php&lt;/em&gt;, &lt;em&gt;#java&lt;/em&gt;, &lt;em&gt;#bbdd&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Incluyo en este repositorio mis apuntes sobre mis materias de estudio tanto de DAW como autodidactas. También incluyo materiales realizados para formaciones impartidas.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;note&quot;&gt;&lt;strong&gt;Nota&lt;/strong&gt;: Esta entrada se actualizará cuando se produzcan novedades.&lt;/span&gt;&lt;/p&gt;
&lt;h2 id=&quot;apuntes&quot;&gt;Apuntes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;BBDD
&lt;ul&gt;
&lt;li&gt;relacional&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Infraestructura
&lt;ul&gt;
&lt;li&gt;servidores (varios)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Programación
&lt;ul&gt;
&lt;li&gt;JAVA&lt;/li&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;varios&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;repositorio&quot;&gt;Repositorio&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JavGuerra/apuntes-tic&quot;&gt;Apuntes TIC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/apuntes.DFb5--bH_Z19gvuH.webp"/><category>código</category><category>php</category><category>java</category><category>bbdd</category><author>JavGuerra</author></item></channel></rss>