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

4.2数据库表-SequelizeMysql-blog后台Api-NodeJs+Express+Mysql实战

时间:2023-04-03 19:03:36 Node.js

整理完功能,我们就可以开始数据库表的设计了:数据库表图:首先打开NavicatPremium创建数据库博客的配置如下:课前学习:1.Sequelize中文API文档【强烈推荐】2.Sequelize与MySQL的比较3.使用Sequelize4,SequelizeAPI5,关于“时间”的探索首先在blogNodejs/下新建一个mysql.jsmodels配置mysql连接(基于Sequelize)varconfig=require('config-lite');//引入灵活的配置文件varSequelize=require('sequelize');.//引入SequelizevarMysql=newSequelize(config.mysql.database,config.mysql.user,config.mysql.password,{host:config.mysql.host,//数据库服务器ipdialect:'mysql',//数据库使用mysqlport:3306,//数据库服务器端口池:{最大:5,最小:0,空闲:10000},});module.exports=Mysql;然后根据数据库图,一一创建对应的Model这里以user.js为例单独说一下:/***User用户表*/varSequelize=require('sequelize');//引入sequelizevarmysql=require('./mysql');//引入mysql实例化//定义User用户表varUser=Mysql.define('user',{uuid:{//使用uuid代替type:Sequelize.UUID,//settypeallowNull:false,//是否允许空primaryKey:true,//主键defaultValue:Sequelize.UUIDV1,//默认值},//uuidemail:{//Emailtype:Sequelize.STRING,allowNull:false,unique:true,//Uniquevalidate:{//SetvalidationConditionisEmail:true,//检测邮件格式(foo@bar.com)},},password:{//Passwordtype:Sequelize.STRING,allowNull:false,},state:{//状态0不激活email,1激活邮箱类型:Sequelize.STRING(2),//限制字符数defaultValue:"0",//默认值},},{freezeTableName:true,//启用自定义表名tableName:'User',//表名timestamps:true,//添加时间戳属性(updatedAt,createdAt)createdAt:'createDate',//重命名createdAt字段为updatedAt:'updateDate',//重命名updatedAt字段为indexes:[{//Indextype:'UNIQUE',//UNIQUE,FULLTEXTorSPATIALmethod:'BTREE',//BTREEorHASHunique:true,//Unique//设置索引是否唯一,自动触发设置UNIQUE设置后//true:索引列的所有值只能出现一次,即必须是唯一字段:['uuid'],//用于索引的字段数组每个字段可以是一个字段名,一个sequelize对象(比如sequelize.fn),或者一组字段包含:attribute(字段名),length(创建前缀的字符数),order(列排序方向),collat??e(比较字段集(Sort))}],comment:"UserTable",//数据库表说明});module.exports=User;//导出表写好后,新建index.js***建立数据库表关系*/varMysql=require('./mysql');//tablevarAdminUser=require('./adminUser');//administratortablevarUser=require('./user');//用户表varUserInfo=require('./userInfo');//用户信息表varArticle=require('./article');//文章表varCategory=require('./category');//文章分类表varAttachment=require('./attachment');//文章附件表/***关系建立*///用户-用户简介User.hasOne(UserInfo);//1:1//User-articleUser.hasMany(//N:NCategory.belongsToMany(Article,{through:'ArticleCategory'});//N:N//根据sequelize自动建表//【!!注意第一次执行后请注释掉这一段代码!!】Mysql.sync({force:true,//是否清空数据库表}).then(function(){console.log('ok');});module.exports={AdminUser:AdminUser,User:用户,UserInfo:用户信息,Article:文章,Category:分类,Attachment:附件,};好这里,我们打开blogNodejs/app.js,写入如下代码//网络框架varlogger=require('morgan');//在开发模式下logvarbodyParser=require('body-parser');//jsonvarpath=require('path');//路径varconfig=require('config-lite');//读取配置文件varwinston=require('winston');//日志varexpressWinston=require('express-winston');//中间的logforexpressbasedonwinstonItemvarmodels=require('./models');//临时添加生成数据库表,稍后写入Controllers//实例化expressvarapp=express();//设置模板目录app.set('views',path.join(__dirname,'views'));//设置模板引擎为ejsapp.set('viewengine','ejs');//logapp.use(logger('dev'));//设置json//格式化JSON输出app.set('jsonspaces',2);//解析application/x-www-form-urlencodedapp.use(bodyParser.urlencoded({extended:false}));//解析application/jsonapp.use(bodyParser.json());//设置静态文件目录app.use(express.static(path.join(__dirname,'public')));//注意:中间件的加载顺序很重要。比如上面设置静态文件目录的中间件应该在routes(app)之前加载,这样对于静态文件的请求就不会落到业务逻辑的route中;//错误请求日志.log'})]}));//错误处理程序use(function(err,req,res,next){//设置局部变量,只在开发中提供错误res.locals.message=err.message;res.locals.error=req.app.get('env')==='development'?err:{};//渲染错误页面res.status(err.status||500);res.render('error');});//appmodule.exports=app;执行去npmrundev去mysql看看是否创建成功(右击“表”-刷新)这里,我们的数据库没问题,我们来学习一些业务逻辑写法//字段类型//STRING//CHAR//TEXT//INTEGER:32位整数。//BIGINT:64位整数。//FLOAT//REAL//DOUBLE//DECIMAL//BOOLEAN//TIME//DATE//BLOB//其中$and:{a:5}//AND(a=5)$or:[{a:5},{a:6}]//(a=5ORa=6)$gt:6,//>6$GT:6,//>=6$lt:10,//<10$lte:10,//<=10$ne:20,//!=20$not:true,//ISNOTTRUE$between:[6,10],//介于6和10$notBetween:[11,15],//不介于11和15$in:[1,2],//IN[1,2]$notIn:[1,2],//不在[1,2]$like:'%hat',//喜欢'%hat'$notLike:'%hat'//不喜欢'%hat'$iLike:'%hat'//喜欢'%hat'(不区分大小写)(仅限PG)$notILike:'%hat'//不喜欢'%hat'(仅限PG)$like:{$any:['cat','hat']}//LIKEANYARRAY['cat','hat']-也适用于iLike和notLike$overlap:[1,2]//&&[1,2](PG数组重叠运算符)$contains:[1,2]//@>[1,2](PG数组包含运算符)$contained:[1,2]//<@[1,2](PG数组包含运算符)$any:[2,3]//ANYARRAY[2,3]::INTEGER(仅限PG)$col:'user.organization_id'//="user"."organization_id",with方言特定列标识符,本例中为PG{rank:{$or:{$lt:1000,$eq:null}}}//rank<1000ORrankISNULL{createdAt:{$lt:newDate(),$gt:新日期(新日期()-24*60*60*1000)}}//createdAt<[timestamp]ANDcreatedAt>[timestamp]{$or:[{title:{$like:'Boat%'}},{description:{$like:'%boat%'}}]}//标题像'Boat%'或描述像'%boat%'CURDcreateresult.dataValues;=========================updateresult[1];==========================find-找一个result从数据库指定元素-findById按已知id查找-findOne按属性查找result.dataValues=========================findOrCreate-查找指定的elementfromthedatabase如果不存在则创建一条记录=========================findAndCountAll-从数据库中查找多个元素,返回数据并总记录数count-integer,match总记录数rows-对象数据,limit和offset匹配的当前页数据{count:0,rows:[]}findAndCountAll也支持使用include。使用include时,只有当required设置为true时才会加入countSection:User.findAndCountAll({include:[{model:Profile,要求:true}],限制:3});使用include时,两个模型之间应该有主/外键关系。如果不存在,则应在include中手动建立连接。上面的例子中设置了ProfileRequired,所以查询的时候会使用INNERJOIN。=========================findAll-从数据库中查找多个元素//查询时使用字符串替换Project.findAll({where:["id>",25]}).then(function(projects){//projects是一个包含Project实例的数组,每个实例的id都大于25})========================count-统计数据库中的元素个数max-查找指定表中的最大值min-查找指定表中的最小值sum-对指定属性求和=========================Destroyresult项目实战(提前知道,后面学习controller层的时候可以看代码学习使用)添加constuserResult=yieldUser.create({email:email,password:md5(password),state:"1",//默认先激活状态//状态0为未激活邮箱,1为激活邮箱});updateconstuserResult=yieldUser.update(user,{//fields:['trueName','birth','sex','city','address'],//设置允许更新的字段白名单where:{uuid:userUuid,},});yieldUser.update({password:md5(newPwd),},{//fields:['password'],//设置允许更新的字段白名单where:{uuid:userUuid,},});查询单个constuserResult=yieldUser。findOne({其中:{uuid:userUuid,},});查询所有模糊查询、分页、排序varcondition={};如果(电子邮件){condition.email={'$like':'%'+email+'%',};}if(trueName){condition.trueName={'$like':'%'+trueName+'%',};}if(role){condition.role=role;}//分页varpage={currPage:utils.handleCurrPage(params.currPage),//获取当前页面pageSize:utils.handlePageSize(params.pageSize),//每页个数};constresult=yieldUser.findAndCountAll({where:condition,attributes:{exclude:['password'],},limit:page.pageSize,//每页多少条目offset:page.pageSize*(page.currPage-1),//要跳过多少条目order:[//Sort['createDate','DESC'],]});扩展:事务场景:A表数据入库成功后,再执行与B表建立关联关系;此时,如果其中一个环节出现问题,则整个操作无效,而不是执行一半,造成脏数据;//事务处理returnMysql.transaction(function(t){//先执行存储returnTableA.create(ajaxData,{transaction:t}).then(function(TableAResult){//如果存储成功后TableB数据存在if(TableBResult){//建立TableA和TableB的关系returnTableAResult.setTableBs(TableBResult,{transaction:t});}});})。then(function(){//交易提交的结果是promise链返回给事务回调的结果//successutils.handleJson({response:res,result:"ok",});}).catch(function(err){console.log(err);utils.handleError({response:res,error:'Failed',});});