7. MySQL

7. MySQL

7.1 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ž€?

๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅ ๋ฐ ์กฐ์ž‘ ํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ -> DBMS

  • RDBMS : MySQL

  • NoSQL : MongoDB

7.2 MySQL ์„ค์น˜ํ•˜๊ธฐ

๋„์ปค๋กœ ๋Œ€์ฒด

# ๋„์ปค์„ค์น˜
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce

# docker image ์ƒ์„ฑ ๋ฐ ์‹คํ–‰
$ docker run -it -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 --name mysql5.7 mysql:5.7

7.3 DB SQL ์„ค์น˜

์›Œํฌ๋ฒค์น˜ ๋Œ€์‹  Datagrip์ด๋‚˜ DBeaver(๋ฌด๋ฃŒ) ์ถ”์ฒœ ์›Œํฌ๋ฒค์น˜ ์ƒ๋žต

7.4 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฐ ํ…Œ์ด๋ธ” ์ƒ์„ฑํ•˜๊ธฐ

-- Database ์ƒ์„ฑ
CREATE DATABASE nodejs;

-- Database ์‚ฌ์šฉ
use nodejs;

-- ํ…Œ์ด๋ธ” ์„ค๋ช…
DESC users;

DROP TABLE ํ…Œ์ด๋ธ”๋ช…;
...

์ž๋ฃŒํ˜•

  • INT : ์ •์ˆ˜์˜๋ฏธ. ์†Œ์ˆ˜๊นŒ์ง€ ์ €์žฅ -> FLOAT, DOUBLE ์‚ฌ์šฉ

  • VARCHAR : ๊ฐ€๋ณ€๊ธธ์ด. ๋ช‡๋ฐฑ์ž ์ด๋‚ด

  • TINYINT : -127 ~ 128

  • TEXT : ๊ธด๊ธ€ ์ €์žฅ

  • DATETIME : ๋‚ ์งœ ๋ฐ ์‹œ๊ฐ„์—๋Œ€ ํ•œ ์ •๋ณด. ๋‚ ์งœ๋งŒ -> DATE, ์‹œ๊ฐ„ -> TIME

7.5 CRUD ์ž‘์—…ํ•˜๊ธฐ (์ƒ์„ฑ, ์ฝ๊ธฐ, ์ˆ˜์ •, ์‚ญ์ œ)

  • C : Create. ์ƒ์„ฑ

    • insert into table values (๊ฐ’,...)

  • R : Read. ์ฝ๊ธฐ

    • select * from table

  • U : Update. ์ˆ˜์ •

    • update table set field1 = x, field2 = y ..

  • D : Delete. ์‚ญ์ œ

    • delete from table where ~

7.6 ์‹œํ€„๋ผ์ด์ฆˆ ์‚ฌ์šฉํ•˜๊ธฐ

  • ORM : ๊ฐ์ฒด์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฆด๋ ˆ์ด์…˜ ๋งคํ•‘

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ตฌ๋ฌธ -> SQL๋กœ ๋ฐ”๊ฟ”์คŒ

  • ๋ชจ๋“ˆ ์„ค์น˜

    # project ์ƒ์„ฑ
    $ express learn-sequelize --view=pug
    
    # sequelize์™€ mysql2 ํŒจํ‚ค์ง€ ์„ค์น˜, cli ์ „์—ญ์„ค์น˜
    $ npm i sequelize mysql2
    $ npm i -g sequelize-cli
    $ sequelize init
  • config.json ๋‚ด์šฉ

    • operatorsAliases : ๋ณด์•ˆ์— ์ทจ์•ฝํ•œ ์—ฐ์‚ฐ์ž๋ฅผ ์‚ฌ์šฉํ• ์ง€ ์—ฌ๋ถ€ (false์ž…๋ ฅ : ์‚ฌ์šฉ์•ˆํ•จ)

    • 4๋Œ€ ์ •๋ณด : username, password, database, host ์ •๋ณด ์•Œ๋งž๊ฒŒ ์ž…๋ ฅ

      {
      "development": {
        "username": "root",
        "password": null,
        "database": "database_development",
        "host": "127.0.0.1",
        "dialect": "mysql",
        "operatorsAliases": false
      },
      "test": {
        "username": "root",
        "password": null,
        "database": "database_test",
        "host": "127.0.0.1",
        "dialect": "mysql",
        "operatorsAliases": false
      },
      "production": {
        "username": "root",
        "password": null,
        "database": "database_production",
        "host": "127.0.0.1",
        "dialect": "mysql",
        "operatorsAliases": false
      }
      }
var sequelize = require('./models/index').sequelize;
var app = express();
sequelize.sync(); // ๋ฉ”์„œ๋“œ ์—†๋Š”๋ฐ;;?
  • models/user.js

    user ์ •๋ณด

    sequlize.define ๋ฉ”์„œ๋“œ๋กœ ๋ชจ๋ธ ์ •์˜. ์‹œํ€„๋ผ์ด์ฆˆ์™€ MySQL ์ž๋ฃŒํ˜•์€ ์•ฝ๊ฐ„ ์ƒ์ด

MySQL

์‹œํ€„๋ผ์ด์ฆˆ

VARCHAR

STRING

INT

INTEGER

TINYINT

BOOLEAN

DATETIME

DATE

ํ…Œ์ด๋ธ”๋ช… ๋ณต์ˆ˜ํ˜•

๋ชจ๋ธ๋ช… ๋‹จ์ˆ˜ํ˜•

// define(๋ชจ๋ธ๋ช…, ์Šคํ‚ค๋งˆ์ •์˜, ํ…Œ์ด๋ธ”์˜ต์…˜)
// user.js
module.exports = (sequelize, DataTypes) => {
  return sequelize.define('user', {
    name: {
      type: DataTypes.STRING(20),
      allowNull: false, // -> not null ์˜ต์…˜๊ณผ ๋™์ผ
      unique: true      // -> unique ์˜ต์…˜๊ณผ ๋™์ผ
    },
    age : {
      type: DataTypes.INTEGER.UNSIGNED,
      allowNull : false
    },
    married:{
      type: DataTypes.BOOLEAN,
      allowNull: true
    },
    comment :{
      type: DataTypes.TEXT,
      allowNull:false
    },
    created_at :{
      type: DataTypes.DATE,
      allowNull : false,
      defaultValue: sequelize.literal('now()')  // -> default ์˜ต์…˜๊ณผ ๋™์ผ
    },
  }, {
    timestamps: false // true : createdAt, updatedAt ์ปฌ๋Ÿผ ์ž๋™ ์ถ”๊ฐ€ ๋ฐ ์ž๋™ ์—…๋ฐ์ดํŠธ
  });
};

// comment.js
module.exports = (sequlize, DataTypes) => {
  return sequlize.define('comment', {
    comment: {
      type: DataTypes.STRING(100),
      allowNull: false
    },
    created_at: {
      type: DataTypes.DATE,
      allowNull: true,
      defaultValue: sequlize.literal('now()')
    }
  }, {
    timestamps: false
  });
};

// index.js
// db ๊ฐ์ฒด์˜ property์™€ js์˜ ๊ฐ์ฒด ์ •๋ณด ์—ฐ๊ฒฐ
db.User = require('./user')(sequelize, Sequelize);
db.Comment = require('./comment')(sequelize, Sequelize);
  • ์œ„ ์™ธ์— ํ…Œ์ด๋ธ”์˜ต์…˜

    • paranoid : timestamps๊ฐ€ true์ธ ๊ฒฝ์šฐ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ, deletedAt ์ปฌ๋Ÿผ์ด ์ถ”๊ฐ€๋จ. ์‚ญ์ œ์‹œ ์‚ญ์ œ๋œ ๋‚ ์งœ๊ฐ€ ์ž…๋ ฅ๋จ (์‚ญ์ œํ•˜์ง„ ์•Š๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋‚จ๊ฒจ๋‘๋Š” ์ด์œ ๋Š” ๋ฐฑ์—… ๋ฐ ํžˆ์Šคํ† ๋ฆฌ ๊ด€๋ฆฌ ๋•Œ๋ฌธ)

    • underscored : createdAt, updatedAt, deleteAt ์ปฌ๋Ÿผ๊ณผ ์‹œํ€„๋ผ์ด์ฆˆ๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๊ด€๊ณ„ ์ปฌ๋Ÿผ๋“ค์˜ ์ด๋ฆ„์„ ์Šค๋„ค์ดํฌ์ผ€์ด์Šค ํ˜•์‹์œผ๋กœ ๋ณ€๊ฒฝ ํ•ด์คŒ. ์Šค๋„ค์ดํฌ์ผ€์ด์Šค๋ž€ ๋Œ€๋ฌธ์ž ๋Œ€์‹  _๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹. ex : createdAt -> created_at

    • tableName : ํ…Œ์ด๋ธ” ์ด๋ฆ„์„ ๋‹ค๋ฅธ๊ฒƒ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉ. ์‹œํ€„๋ผ์ด์ฆˆ๋Š” ์ž๋™์œผ๋กœ ์ฒซ๋ฒˆ์งธ ์ธ์ž(๋ชจ๋ธ๊ฐ’)๊ฐ’์„ ๋ณต์ˆ˜ํ˜•์œผ๋กœ ๋งŒ๋“ค์–ด ํ…Œ์ด๋ธ” ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•จ. user -> users, comment -> comments

  • 1:N ๊ด€๊ณ„ ํ‘œํ˜„ hasMany๋ฉ”์„œ๋“œ ์‚ฌ์šฉ. foreignKey ์†์„ฑ์œผ๋กœ ๊ฐ’ ์ผ์น˜. sourceKey ํ‚ค๊ฐ’(id), targetKey ํ‚ค๊ฐ’(id)

    // user๋Š” comment๋ฅผ ๋งŽ์ด ๊ฐ–์„ ์ˆ˜ ์žˆ๋‹ค
    db.User.hasMany(db.Comment, {foreignKey: 'commenter', sourceKey: 'id'});
    // commnet๋Š” user์— ์†ํ•  ์ˆ˜ ์žˆ๋‹ค
    db.Comment.belongsTo(db.User, {foreignKey: 'commenter', targetKey: 'id'});
  • 1:1 ๊ด€๊ณ„ ํ‘œํ˜„ hasOne ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ. foreignKey ์†์„ฑ์œผ๋กœ ๊ฐ’ ์ผ์น˜. sourceKey ํ‚ค๊ฐ’(id), targetKey ํ‚ค๊ฐ’(id)

    // user๋Š” info๋ฅผ ํ•˜๋‚˜ ๊ฐ–๊ณ  ์žˆ๋‹ค.
    db.User.hasOne(db.Info, {foreignKey: 'user_id', sourceKey: 'id'});
    // info๋Š” user์— ์†ํ•  ์ˆ˜ ์žˆ๋‹ค.
    db.Info.belongsTo(db.User, {foreignKey: 'user_id', targetKey: 'id'});
  • N:M ๊ด€๊ณ„ ํ‘œํ˜„ (๋‹ค๋Œ€๋‹ค) belongsToMany ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ. through ์†์„ฑ์€ ์ค‘๊ฐ„ ๊ด€๊ณ„ ํ…Œ์ด๋ธ” ์ด๋ฆ„ ์ด๋ผ๊ณ  ๋ณด๋ฉด๋ ๋“ฏ.

    // post(๊ฒŒ์‹œ๊ธ€)์€ ์—ฌ๋Ÿฌ๊ฐœ์˜ ํ•ด์‹œํƒœ๊ทธ๋ฅผ ๊ฐ–์„ ์ˆ˜ ์žˆ๋‹ค.
    db.Post.belongsToMany(db.Hashtag, {through: 'PostHashtag'});
    // hashtag(ํ•ด์‹œํƒœ๊ทธ)๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ๊ฒŒ์‹œ๊ธ€์— ๋‹ฌ๋ฆด ์ˆ˜ ์žˆ๋‹ค.
    db.Hashtag.belongsToMany(db.Post, {through: 'PostHashtag'});
  • get+๋ชจ๋ธ์ด๋ฆ„ ๋ณต์ˆ˜ํ˜•

    async (req, res, next) => {
    const tag = await Hashtag.find({where:{title:'node'}});
    const posts = await tag.getPosts();
    }

์‹œํ€„๋ผ์ด์ฆˆ ์ฟผ๋ฆฌ ์•Œ์•„๋ณด๊ธฐ

์‹œํ€„๋ผ์ด์ฆˆ๋งŒ์˜ ๋ฐฉ์‹ ๋ฐ˜ํ™˜ : ํ”„๋กœ๋ฏธ์Šค async/await ๊ฐ™์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅ

  • order : ์ •๋ ฌ๋ฐฉ์‹

  • attributes : select ์ปฌ๋Ÿผ ๋ช…์‹œ

  • ์‹œํ€„๋ผ์ด์ฆˆ์˜ OP -> ์˜คํผ๋ ˆ์ดํ„ฐ

// INSERT INTO users (name, age, married, comment) VALUES('zero', 24, 0, '์ž๊ธฐ์†Œ๊ฐœ1');
const {User} = require('../models')
User.create({
  name: 'zero',
  age: 24,
  married: false,
  comment: '์ž๊ธฐ์†Œ๊ฐœ1'
});

// select * from users;
User.findAll({});

// select * from users limit 1;
Uesr.find({});

// select name, married from users;
User.findAll({
  attributes:['name', 'married']
});

// select name, age from users where married = 1 and age > 30
const {User, Sequelize :{Op}} = require('../models');
User.findAll({
  attributes:['name', 'age'],
  where: {
    married:1,
    age: {[Op.gt]:30}
  }
})

// select id, name from users order by age desc;
User.findAll({
  attributes:['id', 'name'],
  order: [[]]
})

// select id, name from users where married = 0 OR age >30;
const {User, Sequelize: {Op}} = require('../models');
User.findAll({
  attributes: ['id', 'name'],
  where: {
    [Op.or]: [{married: 0}, {age: {[Op.gt]:30}}]
  }
})

// select id, name from users order by age desc;
User.findAll({
  attributes: ['id', 'name'],
  order: [['age', 'DESC']]
})

// select id, name, from users order by age desc limit 1 offset 1;
User.findAll({
  attributes: ['id', 'name'],
  order: ['age', 'DESC'],
  limit: 1,
  offset: 1
})

// update users set comment = '๋‚ด์šฉ' where id = 2;
User.update({
  comment: '๋‚ด์šฉ' // ์ˆ˜์ •๋‚ด์šฉ
},{
  where: {id: 2}  // ์ˆ˜์ •๋Œ€์ƒ ๋กœ์šฐ ์ฐพ๊ธฐ
})

// delete from users where id = 2
User.destroy({
  where:{id: 2}
})

Last updated