当前位置: 首页 > 后端技术 > Node.js

sequelize总结

时间:2023-04-03 13:00:53 Node.js

什么是SequelizeSequelize是一个基于promise的Node.jsORM,目前支持Postgres、MySQL、MariaDB、SQLite和MicrosoftSQLServer。具有强大的事务支持、关联、预读和延迟加载、读取Copy等功能。简单的说就是nodejs的ORM库,满足大部分SQL数据库。安装npmisequelize#安装数据库驱动npmipgpg-hstore#PostgreSQLnpmimysql2#MySQLnpmisqlite3#SQLitenpmitedious#MicrosoftSQLServernpmiibm_db#DB2连接数据库const{Sequelize}=require("sequelize")//Option1:传递连接URIconstsequelize=newSequelize('mysql://root:123456@loc??alhost:3306/test')//方案2:单独传递参数constsequelize=newSequelize({dialect:'mysql',//指定连接主机的数据库类型:'localhost',用户名:'root',密码:'123456',})参数请参考API测试连接try{awaitsequelize.authenticate();console.log("Connectionsucceeded")}catch(error){console.error('Connectionfailed:',error);}关闭连接通常sequelize一旦启用就会保持连接,但是很容易造成SQL负载,所以sequelize也提供了关闭连接的方法,sequelize.close()数据库编程的一般流程:建库建表,配置数据库连接信息,建立数据库连接或数据库连接池,获取数据库连接,然后开启一个事务,执行与数据库操作相关的代码(如:selectxxx),提交一个事务,关闭一个数据库连接或者将数据库连接返回到数据库连接池支持引擎引擎最低支持版本Postgre9.5MySQL5.7MariaDB10.1MicrosoftSQL?SQLite3.0使用V6时注意数据库版本,否则可能报错:(node:119744)[SEQUELIZE0006]DeprecationWarning:不支持此数据库引擎版本,请更新您的数据库服务器。更多信息https://github.com/sequelize/...日志默认情况下,Sequelize会打印它执行的每个SQL查询,您可以通过向option.log属性添加自定义函数来更改打印日志的行为。它的默认值为console.log,默认只显示日志功能的第一个参数。constsequelize=newSequelize('sqlite::memory:',{//选择一个日志记录选项logging:console.log,//默认,显示日志函数调用的第一个参数logging:(...msg)=>console.log(msg),//显示所有日志函数调用参数logging:false,//禁用日志记录logging:msg=>logger.debug(msg),//使用自定义记录器(例如Winston或Bunyan),显示第一个参数logging:logger.debug.bind(logger)//使用自定义记录器的替代方式,显示所有消息});getters,setters&virtualfieldgetters是为模型定义中的列定义的getters()函数:constUser=sequelize.define('user',{//假设我们希望看到每个用户名都是大写的,//即使他们在数据库本身中不一定是大写的setter是一个set()函数。它接收要设置的值:constUser=sequelize.define('user',{username:DataTypes.STRING,password:{type:DataTypes.STRING,set(value){//在数据库中以明文形式存储密码是不好的。//使用适当的哈希函数加密哈希值更好。这个.setDataValue('密码',hash(value));}}});虚拟字段虚拟字段是Sequelize在幕后填充的字段,但它们实际上并不存在于数据库中。例如,假设我们有一个用户的firstName`和lastName`属性。如果有一种简单的方法可以直接获取全名,那就太好了!我们可以将getter的概念与Sequelize为这种情况提供的特殊数据类型一起使用:DataTypes.VIRTUAL:const{DataTypes}=require("sequelize");constUser=sequelize.define('user',{firstName:DataTypes.TEXT,lastName:DataTypes.TEXT,fullName:{type:DataTypes.VIRTUAL,get(){return`${this.firstName}${this.lastName}`;},set(value){thrownewError('唐'ttrytosetthevalueof`fullName`!');}}});AssociationSequelize支持标准关联关系:一对一、一对多和多对多。为此,Sequelize提供了四种类型的关联,并将它们组合起来创建一个关联:HasOne关联类型BelongsTo关联类型HasMany关联类型BelongsToMany关联类型一对一关系//Sequelize知道必须添加fooId列到Bar.Foo.hasOne(Bar);Bar.belongsTo(Foo);可以通过生成sql来理解://BbelongsToA//whereB.foreignKey=A.primaryKey//AhasOneB//whereA.primaryKey=B.foreignKey两者必须同时配置才能互相调用查询自定义外键//Method1Foo.hasOne(Bar,{foreignKey:'myFooId',type:DataTypes.UUID});Bar.belongsTo(Foo,{foreignKey:'myFooId',type:DataTypes.UUID//optional});强制和可选关联很少用到,了解一下即可Foo.hasOne(Bar,{foreignKey:{allowNull:false}});一对多关系Team有Players,每个Player属于一个Team.Team.hasMany(Player);Player.belongsTo(团队);其余的指的是一对多对多的关系,多对多的关系通常是通过连接表来实现的。constMovie=sequelize.define('Movie',{name:DataTypes.STRING});constActor=sequelize.define('Actor',{name:DataTypes.STRING});Movie.belongsToMany(Actor,{through:'ActorMovies'});Actor.belongsToMany(电影,{通过:'ActorMovies'});除了字符串之外,还支持直接传递模型,在这种情况下,给定的模型将用作连接模型(并且不会自动创建任何模型)。例如:constMovie=sequelize.define('Movie',{name:DataTypes.STRING});constActor=sequelize.define('Actor',{name:DataTypes.STRING});constActorMovies=sequelize.define('ActorMovies',{MovieId:{type:DataTypes.INTEGER,references:{model:Movie,//'Movies'也可以使用key:'id'}},ActorId:{type:DataTypes.INTEGER,references:{model:Actor,//'Actors'也可以使用key:'id'}}});Movie.belongsToMany(Actor,{through:ActorMovies});Actor.belongsToMany(Movie,{through:演员电影});连接池业务服务器预先与数据库建立连接,并一直保持这些连接。业务来了,直接用这些连接来处理业务。这种技术称为连接池技术。使用连接池可以减少资源对象的创建次数,提高程序的响应性能,尤其是在高并发下。比如在mysql连接池中,可以尽量避免三向握手、四向挥手等非业务流程造成的丢失。池化技术本质上是资源重用。如果你想从单个进程连接到数据库,你应该只创建一个Sequelize实例。Sequelize会在初始化时建立一个连接池。这个连接池可以通过构造函数的options参数来配置(使用options.pool),如下例所示:constsequelize=newSequelize(/*...*/,{//...pool:{最大值:5,最小值:0,获取:30000,空闲:10000}});如果要从多个进程连接到数据库,则必须为每个进程创建一个实例,但每个实例的最大连接池大小应达到最大总大小。例如,如果您希望最大连接池大小为90,并且您有三个进程,则每个进程的ThemaximumconnectionpoolsizeforaSequelizeinstanceshouldbe30.原始查询由于通常有一种简单的方法来执行原始/准备SQL查询,可以使用sequelize.query方法。默认情况下,该函数将返回两个参数——一个结果数组,以及一个包含元数据(例如受影响的行数等)的对象。请注意,由于这是一个原始查询,因此元数据都是特定于方言的。一些方言返回结果对象“内”的元数据(作为数组的属性)。然而,总是会返回两个参数,但对于MSSQL和MySQL,它将是对同一对象的两个引用。const[results,metadata]=awaitsequelize.query("UPDATEusersSETy=42WHEREx=12");//结果将是一个空数组,元数据将包含受影响的行数。在不需要访问元数据的情况下,您可以传递一个查询类型来告诉后续如何格式化Result。例如,对于一个简单的选择查询,您可以这样做:const{QueryTypes}=require('sequelize');constusers=awaitsequelize.query("SELECT*FROM`users`",{type:QueryTypes.SELECT});//我们不需要在这里分解结果-结果直接通过替换返回(sql反注入)查询中的替换可以通过两种不同的方式完成:使用命名参数(以:开头),或者经过?表示未命名的参数。替换在选项对象中传递。如果传递一个数组,?将按照它们在数组中出现的顺序被替换。如果传递了一个对象,:key将替换为该对象的键。如果对象包含在查询中,如果找不到键,将抛出异常,反之亦然。const{QueryTypes}=require('sequelize');awaitsequelize.query('SELECT*FROMprojectsWHEREstatus=?',{replacements:['active'],type:QueryTypes.SELECT});awaitsequelize.query('SELECT*FROMprojectsWHEREstatus=:status',{replacements:{status:'active'},type:QueryTypes.SELECT});防止sql注入如何格式化日期类型值Sequelize有2个日期相关类型:DATEONLY--相当于SQL的DATEDATE--相当于SQL的DATETIME这2个类型使用ISO标准格式化它们从SQL数据库发送和接收的值让我们通过例子来看看这两种类型。假设你的数据库中有一张发票表,列定义如下:+------------+----------+------+-----+---------+-------------+|字段|类型|空|键|默认|额外|+------------+----------+-----+-----+---------+--------------+|编号|整数|否|优先级|空|自动递增||发票日期|日期|是||空|||付款日期|日期时间|是||空|||金额|整数|是||空||+------------+----------+-----+-----+--------+--------------+这张表只有一行数据,如下图:+----+--------------+--------------------+--------+|编号|发票日期|付款日期|金额|+----+------------+--------------------+-------+|1|2022-01-17|2022-01-1704:33:12|300|+----+------------+-------------------+--------+我们使用Sequelize来定义这个表:constInvoice=sequelize.define("Invoice",{invoiceDate:{type:Sequelize.DATEONLY,},paymentDate:{type:Sequelize.DATE,},amount:{type:Sequelize.INTEGER,},},{timestamps:false,});然后你可以简单地查询这个数据constinvoice=awaitInvoice。findByPk(1);console.log(invoice.toJSON());查询结果如下:{id:1,invoiceDate:'2022-01-17',paymentDate:2022-01-17T04:33:12.000Z,amount:300}注:paymentDate值返回为JavaScriptDate对象,使用ISO格式YYYY-MM-DDTHH:MM:SSZ当需要改变返回值的格式时,可以使用以下2种方法:使用sequelize.fn()方法调用数据库原生日期格式函数使用attributes.column.get()方法在JavaScript中格式化日期。sequelize.fn()方法用于调用本机数据库函数以修改查询的工作方式。constinvoices=awaitInvoice.findAll({attributes:{include:["id","invoiceDate",[sequelize.fn("DATE_FORMAT",sequelize.col("paymentDate"),"%d-%m-%Y%H:%i:%s"),"paymentDate",],"金额",],},});console.log(发票[0].toJSON());每个带有get()和set()方法的Sequelize模型属性允许您为列提供自定义的getter和setter。一般推荐这种方式,因为不需要考虑数据库迁移问题。constInvoice=sequelize.define("Invoice",{invoiceDate:{type:Sequelize.DATEONLY,},paymentDate:{type:Sequelize.DATE,get:function(){//或使用get(){}返回这个。getDataValue('paymentDate').toLocaleString('en-GB',{timeZone:'UTC'});}},amount:{type:Sequelize.INTEGER,},},{timestamps:false,});此外,您可以使用任何JavaScript日期库来格式化返回的时间。参考文章解决sequelize中嵌套太深的问题。对使用Sequelize进行数据库连接/释放感到困惑