# 常用方法

# 模型方法

# 基本方法

    // 排序
        order() // 多个排序用逗号隔开DESC,ASC
    // 分页
        page() // 页码,每页条数
    // 字段返回限制
        field() // 多个字段用逗号隔开
    //条件查询
        where() 
// 传入查询条件,推荐对象方式,可配合find(),select(),countSelect()...,查询符合条件的数据
    // 多表查询
        join() // 推荐关联查询不超过三张,业务特殊除外
    // 单表查询
        find() // 限制查询一条符合结果的数据
    // 多条查询
        select() // 不限制条数查询
    // 多条查询
        countSelect() // 分页查询,结果包含: 总记录数,当前页,每页多少条
    // 别名操作
        alias() // 指定别名
		// 新增操作
		add()
		// 修改操作
		update()
		// 删除操作 使用自定义基类为(逻辑删除)
		delete()
		// 删除操作 仅支持自定义基类 真实删除)
		destory()
	

# 下面是一些使用案例

1.新增数据

// 新增操作
	 let result = await this.add({ username: 'admin2', nickname: '超管二号' });

2.修改数据

// 修改操作
	 let result = await this.where({id: 1 })
	 .update({ username: 'admin2', nickname: '超管二号' });
	

3.删除数据

// 删除操作 使用自定义基类为(逻辑删除),使用原生基类则为真实删除,需注意!!
//默认情况下我们使用逻辑删除,删除数据
	let result = await this.where({ id: 1}).delete();	
	
	// 删除操作 仅支持自定义基类 真实删除)
	let results = await this.where({ id: 1}).destory();

4.查询数据

	
	// 1. 单表操作 find() 查询username = "admin" 的数据,并且只返回一条数据,
 let result = await this.field('id,username,nickname,password')
 .where({username: 'admin'}).find();
	
	// 2. 单表操作 select() 查询username = "admin" 的并返回多条数据,
	//不分页,并且根据创建时间倒叙,更新时间倒叙
	let result = await this.where({username: 'admin'})
	.order('create_at desc,update_at desc').select();
	
	// 3. 单表操作 select() 分页 查询第一页,并且每页十条
	let result = await this.page(1, 10).countSelect();
	
	// 4. 多表操作 countSelect() 分页 分页查询一页十条,内连接查询,有多张表在join后继续添加join
	let result =	await this.join({
	        join: 'inner',
	        table: 'entity_branch',
	        as: 'entity_branch',
	        on: {
	            'auth_user.id_entity_branch': 'entity_branch."id"',
	            'entity_branch.is_rec': false
	        }
	    })
	    .page(1,10)
	    .alias('auth_user')
	    .countSelect();
		
	// 5.模糊查询
    let where = {
	    username: ['like', `%你好%`]
	}
	let result = await this.where(where).order('create_at desc').select();
	
	// 6.in查询 反之改成 id: ['not in',[1,2,3,4]]
	let where = {
	    id: ['in',[1,2,3,4]]
	}
	let result = await this.where(where).order('create_at desc').select();
	
	// 7.or查询 或查询
	let where = {
	    'username|nickname': 'admin'
	}
	let result = await this.where(where).order('create_at desc').select();

# 事务处理

在进行多表操作,如同时对多表进行添加时需要使用事务进行数据添加,避免出现错误,错误的添加数据。

# 自动控制

  • 优点:使用简单,不容易犯错,就感觉事务不存在的样子。
  • 缺点:整个事务要么成功,要么失败,无法做细粒度控制。
module.exports = class extends think.Controller {
    async indexAction() {
		 let models=think.modelPro()
		 const data = await models.transaction(async () => { 
			 let data1 = await  think.modelPro('device').db(models.db()) //复用实例,不可少
			 .add({id_device_type: '测试添加2'})
			 
			  let datas = await think.modelPro('entity_branch')
			  .db(models.db()).add({id_entity: "测试添加"})
			  
			  return true;
			})
          return this.success(data);
    }
};

# 手动控制

  • 优点:startTrans, commit 或 rollback 都由开发者来完全控制,可以做到非常细粒度的控制。
  • 缺点:手写代码比较多,不是每个人都能写好。忘记了捕获异常和 cleanup 都会导致严重 bug。
module.exports = class extends think.Controller {
    async indexAction() {
		 let models=think.modelPro() //创建实例
		 try{
			 await models.startTrans(); //开启事务
			 
			 let data = await think.modelPro('device').db(models.db()) //复用实例,不可少
			 .add({id_device_type: '测试添加2'})
			 
			let datas = await think.modelPro('entity_branch')
			.db(models.db()).add({id_entity: "测试添加"})
			
			 await models.commit(); //提交事务
			 
          return this.success(datas);
		  }catch(e){
		await models.rollback()  // 一定记得捕获异常后回滚事务!!
		   }
    }
};

以上两种方式都可以进行事务操作,可以根据实际情况选择合适的方式。

注意事项

1.由于操作事务过程需要实例化多个模型操作,那么需要让模型之间复用同一个数据库连接,具体见 model.db (opens new window)

  1. 事务操作过程要尽量小,因为等待的时候,事务并未结束,可能锁定了很多资源,所以建议处理好数据在执行事务操作。

# 手动Sql

在进行比较复杂的操作,使用模型自带的方法显然难以实现我们想要的功能,这时候我们需要执行原生sql来实现功能,但是这样很容易引起 sql 注入!!, 所以下面主要讲解如何在使用原生sql的时候尽可能的避免风险。

1.下面是一个比较简单的使用场景,在使用原生sql请不要使用字符串拼接的方式将数据拼接到sql语句在。我们应该使用占位符进行拼接, 这样可以很好的避免被注入风险。


 const query = `SELECT * FROM zee_account_user WHERE id_auth_role = $(list.name) 
 and id_entity in ($(password:value))`;
 
 		let datas={list:{name:3},password:[1,2,3]}
		
 let data =await	think.modelPro().queryPro(query,datas)
 
 //在上面的语句中 $(list.name)表示获取对象在list.name的值,
 //$(password:value)则表示获取password并将数组内的值取出来
 
 /**
  * 可传入值
   * @param {String}  sql sql语句
   * @param {obj}  perch 占位符
  */

2.下面是一个比较常见的使用场景,当我们不确定某个值是不是一定会传入时,则需要拼接sql,下面是一个拼接案例。


		let datas={
		name:'name'
			password:[1,2,3]
		}
		const query = "SELECT * FROM zee_account_user WHERE 1=1";
		
		if(datas.name){
			query+='and  id_auth_role like $(name)'
			datas.name= `%${datas.name}%` 
		}
		if(datas.password){
			query+='and id_entity in ($(password:value))'
		}
	 let data =await	think.modelPro().queryPro(query,datas)	
 
 /**
  * 可传入值
   * @param {String}  sql sql语句
   * @param {obj}  perch 占位符
  */

注意事项

1.使用sql语句不能将数据直接拼接到sql中,这是不安全的!!!

2.简单的sql应该使用model自带的方法进行查询,而不是使用直接使用sql。

# 通用方法

# 框架常用方法

# 是否数字,且大于0

 // 验证返回是否为数字,且数字大于0,是则为true
 think.isCorrect()

# 是否数组

  // 判断输入是否是数组,是则为true
  think.isArray(arr)

# 否为对象

 // 判断是否为对象,是则为true
 think.isObject()

# 是否真正为空

  // 判断是否是真正为空,undefined、null、''、NaN,是则为true
  think.isTrueEmpty(boolean)

# 对象是否为空

 // 判断对象是否为空, undefined, null ,'', NaN, [], {}, 0, false,是则为true
 think.isEmpty(arr)

# md5加密

 // md5加密
 think.md5(name)

# 格式化日期

 // 格式化日期
 think.datetime(date, 'YYYY-MM-DD HH:mm:ss' )

# uuid

 // 生成 uuid 字符串 支持v1|v4
 think.uuid()

# 数据格式化为二维存库

 // 数据格式化为二维存库
 think.formattingKeep()

# 自定义方法

# 加密/解密token

 //加密token
 think.Utils.signteToken(data)
 // 解密token,是则为false
 think.Utils.verifyToken(token)	

# http请求

  think.Utils.request()
  
  /**
   * 可传入值
    * @param {String}  url 请求地址
    * @param {deploy}  deploy 配置参数
   */
  
  /**
   * 常用参数 deploy
    * @param {string} method 请求类型,默认为post
    * @param {obj} data  post请求数据
	* @param {obj} headers 请求头,默认为 "content-type": "application/json"
	*  @param {obj} params get请求参数,也可拼接到url
   */

# 用户信息

// 获取用户信息
  let user= think.User
  
  //设置用户信息
  think.User= await {id:1111}
  

# 数据缓存

    //设置缓存
	// 默认时间为2天
    think.cache('AccessToken', access_token, { timeout: 1.5 * 60 * 60 * 1000 })

   // 获取缓存
     think.cache('AccessToken')
	
	//清除缓存
	 think.cache('AccessToken', mull)
	

# 导出exel

   const columns = [
   		  {
   		    label: '姓名',
   		    value: 'name',
   		  },
   		  {
   		    label: '年龄',
   		    value: 'age',
   		  }
   		]
   		const data = [
   		  {
   		    name: 'lucy',
   		    age: 24
   		  },
   		  {
   		    name: 'bob',
   		    age: 26
   		  }
   		]
      	const sheetOptions = {'!cols': [{wch: 20}, {wch: 15}, {wch: 15}, {wch: 25}]};// 配置列宽
   let result = await  think.Utils.JsonToExcel([{name:'测试',columns:columns,data:data}],{sheetOptions})
   // 输出流数据
   
   ////配置参数返回前端
   this.ctx.set({
        'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'Content-Disposition': 'attachment; filename=test.xlsx'
      });
   this.ctx.body = result;
   
   /**
    * 可传入值
     * @param {String}  data 数据列表
     * @param {deploy}  deploy 配置参数如sheetOptions
    */
   /**
    * data
     * @param {string} name 工作谱名称
     * @param {obj} columns 列表头
   	* @param {obj} data 导出数据
   	* 
    */
    
   ///注,如果一个文件想要导出多个工作谱则data配置多个对象即可