2018/04/13

PHP, Python, Node.js CRUD On MySQL

紀錄一下這三個語言對 MySQL 做 CRUD 的方法當作筆記用,不會使用 ORM 或者其他功能強大複雜的套件,畢竟如果有使用 framework 通常都有附,這邊使用最簡潔的方法完成。

MySQL

先建立表單來做 CRUD 使用。

CREATE TABLE `examples` (
	`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(50) NOT NULL,
	`created_at` DATETIME NOT NULL,
	PRIMARY KEY (`id`)
)
COLLATE='utf8mb4_unicode_ci';

PHP - PDO

PHP 現在一定是使用 PDO,實做方式如下。

<?php

$username = 'root';
$password = 123456;

try {
    $name = 'Chan';
    $createdAt = date('Y-m-d H:i:s');

    // 設定
    $dbh = new \PDO('mysql:host=localhost;dbname=demo;charset=utf8', $username, $password);

    // 寫入
    $sql = "INSERT INTO `examples` (`name`, `created_at`) VALUES (:name, :created_at)";
    $sth = $dbh->prepare($sql);
    $sth->bindParam(':name', $name, \PDO::PARAM_STR);
    $sth->bindParam(':created_at', $createdAt, \PDO::PARAM_STR);
    $sth->execute();

    // 提取多筆
    $sql = "SELECT * FROM `examples`";
    $sth = $dbh->prepare($sql);
    $sth->execute();
    $rows = $sth->fetchAll(\PDO::FETCH_ASSOC);
    var_dump($sth->rowCount());   
    var_dump($rows);

    // 提取單筆
    $sql = "SELECT * FROM `examples`";
    $sth = $dbh->prepare($sql);
    $sth->execute();
    $rows = $sth->fetch(\PDO::FETCH_ASSOC);
    var_dump($rows);
} catch (Exception $e) {
    var_dump($e-getMessage());
} finally {
    $sth = null;
    $dbh = null;
}

其中 PDO::PARAM_STR 的部份是讓你確定傳入文字的型別,可以有效防止 SQL Injection,常使用的有:

  1. PDO::PARAM_STR
  2. PDO::PARAM_INT
  3. PDO::PARAM_BOOL

其他可以使用的部份可以看這邊,更新跟刪除的部份就是把 INSERT 的內容改成 UPDATEDELETE,就不多寫範例了。

Python - MySQLdb

Python 我們使用 MySQLdb 來操作,怎麼安裝網路上有很多教學,這邊也不示範了。

# -*- coding: utf-8 -*-

import MySQLdb
import datetime

username = 'root'
password = '123456'

try:
    # 設定
    db = MySQLdb.connect(host='localhost', db='demo', user=username, passwd=password)
    cursor = db.cursor()

    # 寫入
    values = (
        'Chan',
        datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    )
    sql = "INSERT INTO `examples` (`name`, `created_at`) VALUES (%s, %s)"
    cursor.execute(sql, values)
    db.commit()

    # 提取多筆
    sql = "SELECT * FROM `examples`"
    cursor.execute(sql)
    rows = cursor.fetchall()
    print(cursor.rowcount)
    print(rows)

    # 提取單筆
    sql = "SELECT * FROM `examples`"
    cursor.execute(sql)
    row = cursor.fetchone()
    print(row)
except Exception as e:
    print(str(e))
finally:
    db.close()
這個套件沒有回傳 key name,所以如果你想要對應欄位名稱的話可能要這樣使用

# 提取多筆
sql = "SELECT * FROM `examples`"
cursor.execute(sql)
rows = cursor.fetchall()

for row in rows:
    pk, name, date = row
    print(pk)
    print(name)
    print(date)

此套件傳遞參數的方法很多,可以參考 Python best practice and securest to connect to MySQL and execute queries 這篇。

Node.js - mysql2

node.js 部份我選用了 mysql2,他語法基本上跟 mysql 一樣,多了些功能跟據說效能有提昇,我是沒實測,但就用最新的。

const mysql = require('mysql2');
const datetime = require('node-datetime');

try {
    // 設定
    const connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: '123456',
        database: 'demo'
    });

    // 寫入
    const name = 'Chan';
    const dt = datetime.create();
    const createdAt = dt.format('Y-m-d H:M:S');
    let sql = 'INSERT INTO `examples` (`name`, `created_at`) VALUES (?, ?)';
    connection.execute(sql, [name, createdAt], (err, rows, fields) => {
        if (err) {
            console.log(err);
        }
    });

    // 讀取
    sql = 'SELECT * FROM `examples`';
    connection.execute(sql, (err, rows, fields) => {
        console.log(rows);
    });

    connection.end();
} catch (e) {
    console.log(e.message);
}

這個套件沒有封裝多筆或單筆的功能,要取單筆就是拿取陣列第一筆資料,上面的程式碼是 sync 模式執行的,所以其實是有機會讀到沒寫入的資料,除非你使用 callback 或 promise,示範一下 promise 的作法。

const mysql = require('mysql2/promise');
const datetime = require('node-datetime');

async function main() {
    try {
        const connection = await mysql.createConnection({
            host: 'localhost',
            user: 'root',
            password: '123456',
            database: 'demo'
        });

        // 寫入
        const name = 'Chan';
        const dt = datetime.create();
        const createdAt = dt.format('Y-m-d H:M:S');
        let sql = 'INSERT INTO `examples` (`name`, `created_at`) VALUES (?, ?)';
        await connection.execute(sql, [name, createdAt]);

        // 讀取
        sql = 'SELECT * FROM `examples`';
        const [rows] = await connection.execute(sql);
        console.log(rows);

        connection.end();
    } catch (e) {
        console.log(e.message);
    }
}

main();

沒有留言: