Applications and operations

Build a MySQL notes application

Build and verify a complete MySQL notes application with restricted accounts, InnoDB relations, safe queries, and a restored backup.

Let’s finish the course with one runnable project. Every lesson so far contributed one piece: accounts, grants, schema, transactions, safe queries, and backups. This lab connects them, and each step includes a check that proves it worked.

As the administrator, create the database and accounts using the commands from the privileges module. You need notes_app for row access and notes_migrator for schema changes. Then connect as notes_migrator and create the schema:

USE notes_app;

CREATE TABLE notes (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  title VARCHAR(200) NOT NULL,
  body TEXT,
  estimated_hours DECIMAL(5,2),
  remind_at DATETIME,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  INDEX notes_title_idx (title)
) ENGINE=InnoDB;

CREATE TABLE tags (
  id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) NOT NULL UNIQUE
) ENGINE=InnoDB;

CREATE TABLE note_tags (
  note_id BIGINT UNSIGNED NOT NULL,
  tag_id BIGINT UNSIGNED NOT NULL,
  PRIMARY KEY (note_id, tag_id),
  CONSTRAINT note_tags_note_fk
    FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE,
  CONSTRAINT note_tags_tag_fk
    FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
) ENGINE=InnoDB;

If CREATE TABLE returns an access-denied error here, you are connected as the wrong account. Run SELECT CURRENT_USER(); and fix the session before continuing.

Now connect as notes_app. Confirm that inserts work and schema changes fail:

INSERT INTO notes (title, estimated_hours)
VALUES ('Plan the week', 1.50);

SELECT id, title, estimated_hours, created_at
FROM notes;

ALTER TABLE notes ADD COLUMN should_fail INT;

The SELECT must return the row you just inserted. The ALTER TABLE must return an access-denied error like ERROR 1142 (42000): ALTER command denied to user 'notes_app'@'localhost'. That failure is the point: a leaked application credential cannot rewrite your schema.

Try one more deliberate failure. Insert into note_tags with a tag_id that does not exist. InnoDB rejects it with ERROR 1452, a foreign key constraint failure. The schema, not application discipline, protects the relationship.

Run the optional Node.js track with the bounded pool and a parameterized lookup:

const [rows] = await pool.execute(
  'SELECT id, title FROM notes WHERE title = ?',
  ['Plan the week']
)

console.log(rows)
await pool.end()

Inspect the lookup with EXPLAIN, then perform one expand-and-contract migration as notes_migrator.

Finally, dump notes_app, restore it into notes_restore, run CHECK TABLE, and query Plan the week from the restored database. The lab is complete only when the restricted account, application query, migration, and restore all work.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →