Node.js SQL数据库操作 (下)(ORM框架、Sequelize模块及案例展示)

ORM框架

ORM(Object Relational Mapping,对象关系映射),是一种为了 解决面向对象与关系数据库存在的互不匹配的现象 的技术,通过描述对象和数据库之间映射的 元数据,把程序中的对象自动持久化到关系数据库中。它的作用是在关系型数据库和对象之间作一个映射,这样,在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了 。

持久(Persistence)化,即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。

  • ORM就是把 业务实体中的对象关系数据库中的关系数据 关联起来,对数据库进行高层封装
  • 对象-关系映射(ORM)系统一般以中间件的形式存在
  • 不足之处主要是会牺牲程序的执行效率

ORM技术特点:

  1. 提高了开发效率。ORM可以自动对Entity对象与数据库中的Table进行字段与属性的映射,所以我们实际可能已经不需要一个专用的、庞大的数据访问层。
  2. ORM提供了对数据库的映射,不用sql直接编码,能够像操作对象一样从数据库获取数据。

Sequelize模块

  • Sequelize 是一款基于Promise的支持异步操作的Node.js ORM框架,能够用在Node.JS环境中,易于使用,支持多SQL方言(dialect)
  • 支持Postgres、MySQL、SQLite和Microsoft SQL Server等多种数据库,具有强大的事务支持、关联关系、读取和复制等功能
  • 很适合作为Node.js后端数据库的存储接口,有助于提高Node.js应用程序的开发效率

特点:

  • 强大的模型定义,支持虚拟类型
  • 支持完善的数据验证,减轻前后端的验证压力
  • Sequelize的查询非常全面和灵活

Sequelize的基本使用

安装sequelize库:npm install --save sequelize

基本用法:

1、建立连接:

  • 第1种方式:单独传递参数(多数)
const Sequelize = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
  host: 'localhost',
  dialect: /*可以是'mysql'、'mariadb'、'postgres'或'mssql'中任何一个 */
});
  • 第2种方式:传递连接URL
const Sequelize = require('sequelize');
const sequelize = new Sequelize('postgres://user:pass@example.com:5432/dbname');

示例:

const Sequelize = require('sequelize');
const sequelize = new Sequelize('testmydb', 'root', 'abc123', {
 	//连接选项
 	host: 'localhost', // 数据库地址
  	dialect: 'mysql', // 指定连接的数据库类型
  	pool: {
	    max: 5, // 连接池的最大连接数量
	    min: 0, // 连接池的最小连接数量
	    idle: 10000 // 如果一个线程10秒钟内没有被使用,那么就释放线程
  }
});
//测试连接
sequelize
  .authenticate()
  .then(() => {
    console.log('成功建立连接');
  })
  .catch(err => {
    console.error('未能连接到数据库:', err);
  });

2、定义模型:

  • ① 使用 Sequelize.Model.init(attributes, options)函数
const Model = Sequelize.Model;
class User extends Model {}
User.init({
  // 属性设置
  name: {
    type: Sequelize.STRING,
    allowNull: false
  },
  email: {
    type: Sequelize.STRING
    // allowNull(允许空值)默认为true
  }
}, {
  sequelize,
  modelName: 'user'   //此处定义模型名
  // 选项
});
  • ② 使用 sequelize.define(‘name’, {attributes}, {options})
const User = sequelize.define('user', {  // user为模型名
  // 属性
  name: {
    type: Sequelize.STRING,
    allowNull: false
  },
  email: {
    type: Sequelize.STRING
  }
}, {  // 选项
});

3、将模型与数据库同步(可选)

User.sync({ force: true }).then(() => {
  // 数据库中的表与模型定义一致
  return User.create({
    name: '小莉',
    email: 'xiaoli@abc.com'
  });
});
  • 选项 force: true 表示如果表已经存在,在新建前会删除原表

4、增加操作:

// 创建新的用户
User.create({ name: "小彤", email: "xiaotong@abc.com" }).then(() => {
  console.log("已添加");
});

5、删除操作:

// 删除名为小红的用户
User.destroy({
  where: {
    name: "小红"
  }
}).then(() => {
  console.log("已删除");
});

6、更改操作:

// 将没有邮箱的用户的邮箱改为it@abc.com
User.update({ eamil: "it@abc.com" }, {
  where: {
    email: null
  }
}).then(() => {
  console.log("已改完");
});

7、查找操作:

// 查找所有用户
User.findAll().then(users => {
  console.log("所有用户:", JSON.stringify(users, null, 4));
});

Promises和async/await

  • Sequelize使用Promise来控制异步操作流程,增查改删操作都可使用then()方法。
  • 如果Node.js版本支持,可以使用ES2017 async/await语法来编写Sequelize所用的异步调用代码。
  • Sequelize的所有Promise对象也是Bluebird的Promise对象,也可以使用Bluebird API来操作。
  • Sequelize返回的Promise对象也可以通过co模块来操作。

Sequelize的多表关联

源和目标:

const User = sequelize.define('user',{
  name: Sequelize.STRING,
  email: Sequelize.STRING
});
const Project = sequelize.define('project',{
  name: Sequelize.STRING
});
User.hasOne(Project);

外键:

  • Sequelize创建模型之间的关联时,将自动创建带有约束的外键引用
  • 创建Task和User模型之间的关系会在tasks表中插入外键userId,并将该外键作为对users表的引用
const Task = sequelize.define('task', {
	title: Sequelize.STRING 
});
const User = sequelize.define('user', {
	username: Sequelize.STRING
});
User.hasMany(Task); // 自动将userId添加到Task模型
Task.belongsTo(User); //也会自动将userId添加到Task模型

一对一关联:

  • belongsTo关联
  • belongsTo关联在源模型上存在一对一关系的外键

示例:Player通过players表的外键teamId作为Team的一部分

const Player = sequelize('player',{
	/* 属性定义 */
});
const Team = sequelize('team', {
	/* 属性定义 */
});
Player.belongsTo(Team); // 向Team模型添加teamId属性以保存Team的主键值

一对一关联:

  • hasOne关联
  • hasOne关联是在目标模型上存在的一对一关系的外键的关联

示例:向User模型添加projectId属性

const User = sequelize.define('user', {
	/* ... */
});
const Project = sequelize.define('project',{
	/* ... */
});
Project.hasOne(User)   // 单向关联

hasOne和belongsTo之间的区别:

  • hasOne在目标模型中插入关联键
  • belongsTo在源模型中插入关联键

示例:

const Player = sequelize.define('player', {/* 属性定义 */});
const Coach = sequelize.define('coach', {/* 属性定义 */});
const Team  = sequelize.define('team', {/* 属性定义 */});
  • 当有关关联的信息存在于源模型中时,可以使用belongsTo关联。例中Player适用于belongsTo关联,因为它具有teamId列。
Player.belongsTo(Team) // teamId 将被添加到源模型Player中
  • 当有关关联的信息存在于目标模型中时,可以使用hasOne关联。例中Coach适用于hasOne关联,因为Team模型将其Coach的信息存储为coachId列。
Coach.hasOne(Team) // coachId将被添加到目标模型Team中

一对多关联:

  • 一对多关联将一个源与多个目标连接起来,多个目标连接到同一个特定的源:
const User = sequelize.define('user', {/* ... */})
const Project = sequelize.define('project', {/* ... */})
Project.hasMany(User, {as: 'Workers'})
  • hasMany() 用于定义一对多关联
  • 要在不同的列上关联记录,可以使用sourceKey选项指定源键:
const City = sequelize.define('city', { countryCode: Sequelize.STRING });
const Country = sequelize.define('country', { isoCode: Sequelize.STRING });
// 可以根据国家代码连接国家和城市
Country.hasMany(City, {foreignKey: 'countryCode', sourceKey: 'isoCode'});
City.belongsTo(Country, {foreignKey: 'countryCode', targetKey: 'isoCode'});

多对多关联:

  • 多对多关联用于将源与多个目标相连接,目标也可以连接到多个源:
Project.belongsToMany(User, {through: 'UserProject'});
User.belongsToMany(Project, {through: 'UserProject'});

图书借阅管理案例

此案例用于记录图书的借阅信息,为简化实验过程,只有两个表 books(图书)和 readers(读者),它们之间是一对多的关系,一种图书可以对应多个读者,使用自动建立表结构的方案。在实际的应用程序开发中,往往将数据部分独立出来,作为模型部分,这样有利于各模块的解耦和扩展。

1、定义图书数据模型:

const Sequelize = require('sequelize'); 
module.exports = (sequelize) => {
    var Book = sequelize.define('book', {
        isbn: { type: Sequelize.STRING },
        name: { type: Sequelize.STRING },
        author: { type: Sequelize.STRING },
        press: { type: Sequelize.STRING },
        price: { type: Sequelize.DECIMAL(10, 2) },
        pubdate: { type: Sequelize.DATEONLY }
    });      
    return Book;
};

2、定义读者数据模型:

const Sequelize = require('sequelize'); 
module.exports = (sequelize) => {
    var Reader = sequelize.define('reader', {
        name: { type: Sequelize.STRING },
        mobile: { type: Sequelize.STRING },
        email: { type: Sequelize.STRING }
    });
    return Reader;
};

3、同步数据模型:

const Sequelize = require('sequelize');
const sequelize = new Sequelize('testmydb', 'root', 'abc123', {
  //连接选项
  host: 'localhost', // 数据库地址
  dialect: 'mysql', // 指定连接的数据库类型
  define: {
    'charset':'utf8'     //解决中文输入问题
  },
  pool: {    // 建立连接池
    max: 5, // 连接池的最大连接数量
    min: 0, // 连接池的最小连接数量
    idle: 20000 // 如果一个线程在20秒内没有被使用过,那么释放线程
  }
});
const Book = require('./book_model')(sequelize);//导入Book模型
const Reader = require('./reader_model')(sequelize);//导入Reader模型
Book.hasMany(Reader);   //一种图书有多个读者
Reader.belongsTo(Book);  //一个读者对应一种图书
sequelize.sync();    //自动同步所有的模型,使用关联时要使用。首次添加数据之后可将其注释掉
exports.Book = Book;
exports.Reader = Reader; 

4、添加数据:

const Book  = require('./mydb').Book;
const Reader  = require('./mydb').Reader;
async function addBook() {
  const result = await Book.create(
    {              
      isbn:"9787115474582",
      //(此处略)
  },
    { include: [Reader] } //指定关联关系,读者数据自动插入到读者表
  );  
  return result;  
}
addBook().then(data => {
  console.log("添加的数据:", JSON.stringify(data, null, 4)); // 获取返回的内容
}).catch(error => {
  console.log(error);   // 捕获错误
});

5、获取数据:

const Book  = require('./mydb').Book;
const Reader  = require('./mydb').Reader;
async function getBook() {
  const result = await Book.findAll();  
  return result;  
}
getBook().then(data => {
  console.log("查询的数据:", JSON.stringify(data, null, 4)); // 获取返回的内容
}).catch(error => {
  console.log(error);   // 捕获错误
});

6、更改数据:

const Book  = require('./mydb').Book;
const Reader  = require('./mydb').Reader;
async function updateBook() {
  const result = await Book.update(
    { price:98.00 },
    { where: { id: 1 } }    
  );  
  return result;  
}
updateBook().then(data => {
  console.log("修改数据的ID:", JSON.stringify(data, null, 4)); // 获取返回的内容
}).catch(error => {
  console.log(error);   // 捕获错误
});

7、删除数据:

const Book  = require('./mydb').Book;
const Reader  = require('./mydb').Reader;
async function delBook() {
  const result = await Book.destroy(
    { where: { id: 1 } }    
  );  
  return result;  
}
delBook().then(data => {
  console.log("删除数据的ID:", JSON.stringify(data, null, 4)); // 获取返回的内容
}).catch(error => {
  console.log(error);   // 捕获错误

学习文章:Node.js SQL数据库操作 (上)(操作MySQL数据库及 数据库连接池)

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值