Skip to content

Commit 8f089eb

Browse files
expand mysql2 querying section with parameterized queries (#3127)
Co-authored-by: lunadogbot <lunadogbot@users.noreply.github.com> Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
1 parent c8aad39 commit 8f089eb

1 file changed

Lines changed: 37 additions & 25 deletions

File tree

examples/tutorials/mysql2.md

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
last_modified: 2025-03-10
2+
last_modified: 2026-05-14
33
title: "How to use MySQL2 with Deno"
44
description: "Step-by-step guide to using MySQL2 with Deno. Learn how to set up database connections, execute queries, handle transactions, and build data-driven applications using MySQL's Node.js driver."
55
url: /examples/mysql2_tutorial/
@@ -71,49 +71,61 @@ We now have all the data ready to start querying.
7171

7272
## Querying MySQL
7373

74-
We can use the same connection.query() method to write our queries. First we try
75-
and get all the data in our `dinosaurs` table:
74+
We can use the same `connection.query()` method to read data back. The
75+
`mysql2/promise` driver resolves to a `[rows, fields]` tuple, so destructure to
76+
pull out the rows directly:
7677

7778
```tsx
78-
const results = await connection.query("SELECT * FROM `dinosaurs`");
79-
console.log(results);
79+
const [rows] = await connection.query("SELECT * FROM `dinosaurs`");
80+
console.log(rows);
8081
```
8182

82-
The result from this query is all the data in our database:
83+
This prints every row in the table:
8384

8485
```tsx
8586
[
86-
[
87-
{
88-
id: 1,
89-
name: "Aardonyx",
90-
description: "An early stage in the evolution of sauropods."
91-
},
92-
{
93-
id: 2,
94-
name: "Abelisaurus",
95-
description: `Abel's lizard" has been reconstructed from a single skull.`
96-
},
97-
{ id: 3, name: "Deno", description: "The fastest dinosaur that ever lived." }
98-
],
87+
{
88+
id: 1,
89+
name: "Aardonyx",
90+
description: "An early stage in the evolution of sauropods.",
91+
},
92+
{
93+
id: 2,
94+
name: "Abelisaurus",
95+
description: "Abels lizard has been reconstructed from a single skull.",
96+
},
97+
{ id: 3, name: "Deno", description: "The fastest dinosaur that ever lived." },
98+
];
9999
```
100100

101-
If we want to just get a single element from the database, we can change our
102-
query:
101+
### Parameterized queries
102+
103+
To filter by a value, do not paste it directly into the SQL string — that's how
104+
SQL injection bugs get shipped. Use `connection.execute()` with `?`
105+
placeholders. The driver prepares the statement on the server and binds the
106+
values separately, so anything you pass in the values array is treated strictly
107+
as data, never parsed as SQL:
103108

104109
```tsx
105-
const [results, fields] = await connection.query(
106-
"SELECT * FROM `dinosaurs` WHERE `name` = 'Deno'",
110+
const name = "Deno"; // imagine this came from a user request
111+
const [rows] = await connection.execute(
112+
"SELECT * FROM `dinosaurs` WHERE `name` = ?",
113+
[name],
107114
);
108-
console.log(results);
115+
console.log(rows);
109116
```
110117

111-
Which gives us a single row result:
118+
Which gives us a single matching row:
112119

113120
```tsx
114121
[{ id: 3, name: "Deno", description: "The fastest dinosaur that ever lived." }];
115122
```
116123

124+
`?` placeholders are positional, so the values must appear in the same order as
125+
the placeholders in the SQL. The same pattern works for `INSERT`, `UPDATE`, and
126+
`DELETE`; `mysql2` also caches each prepared statement, so repeated calls with
127+
different values skip the parse step on subsequent runs.
128+
117129
Finally, we can close the connection:
118130

119131
```tsx

0 commit comments

Comments
 (0)