掌握执行服务器过程

事件响应设置面板中可以设置执行服务器过程来完成对数据的持久化操作。绝大多数情况下,只需写 SQL 即可完成业务逻辑。

1. 执行 SQL

1.1 SQL 设置方法

执行单条 SQL

直接书写带变量的 SQL,取用前端和后端提供的变量数据做持久化操作,如:

  1. INSERT INTO TAB_A(F1, F2, F3, ...) VALUES(@11-VAR1@, @11-VAR2@, @VAR3@)
一次执行多条 SQL

可以使用 $0, $1, $2, … 标识符依次来表示引用第 1 条, 第 2 条, 第 3 条 SQL… 执行的结果。如:

  1. SELECT * FROM tab_a WHERE id = @12-USER_ID@ AND master = @USER_ID@; -- 一定要分号分隔
  2. INSERT INTO tab_b(F1, F2, F3, ...) VALUES($0.rows[0]["field1"] , @11-VAR2@, @VAR3@);
  3. -- ^^^^^^^ 即第 1 SELECT 查询结果集合。
  4. UPDATE tab_b SET f1 = @12-VAR1@, f2 = @VAR2@ WHERE id = $1.insertId; --<-- 2 SQL 执行的结果。

【说明 1】$n 标识符代表的第 n+1 条 SQL 执行结果,本身是一个 JSON 对象,结构如下:

  1. {
  2. rows: [{...}, {...}, {...} ...], // 执行 SELECT 语句才有该字段,表示查询结果。
  3. insertId: 12889, // 执行 INSERT 语句才有该字段,表示插入后获得的自增长 ID,仅适用于 mysql。
  4. affectedRows: 3, // 执行 INSERT, UPDATE, DELETE 才有该字段,表示影响行数。
  5. }

【说明 2】执行多条 SQL 时,解释器会根据上下文依赖,决定是否并发执行还是串行执行;同时,如果包含两条以上的更新语句(INSERT、UPDATE、DELETE),则会采用事务方式执行,如果有错误会自动回滚,开发者无需关心。

SQL 中嵌入 JavaScript 脚本

可以使用 # JavaScript 脚本 # 嵌入 SQL 中对变量进行加工处理,如:

  1. INSERT INTO tab_a(F1, F2, F3) VALUES(
  2. -- 字段 F1
  3. #@11-VAR1@ + '-' + @11-VAR2@#,
  4. -- 字段 F2
  5. #@12-NAMES@.split(',').map(function(s) {
  6. return s.replace(/\s/g, '');
  7. }).join(':')#,
  8. -- 字段 F3
  9. #@12-VAR@ + b#
  10. );

1.2 添加错误码对照提示

对于一些需要明确提示给用户的 SQL 错误,可以设置SQL 错误码对应的错误提示信息,以增加交互的友好性。比如给常见的主键重复错误码ER_DUP_KEY添加对照提示您添加的学号已经存在!

1.3 执行提交前前端脚本(可选,执行在前端)

设置提交前前端脚本的设置可以满足以下需求:

  • 如果您想在过程提交到后台执行前,做一些条件判断,来决定是否要提交,则直接在脚本中返回 false 即可阻止本次提交,如:
  1. if (/** 条件不满足 **/) {
  2. return false;
  3. }
  • 如果想改变提交的参数变量的值,可以直接返回包含新变量值的 JSON,对即将提交到后台的变量值做覆盖,如:
  1. var amount = @11-amount@ + @11-total@ + 3;
  2. var rows = @11-rows@.map(function(s) {
  3. return s.split('-')[0];
  4. });
  5. return {
  6. "11-amount": amount,
  7. "11-rows": rows,
  8. "12-other": "something"
  9. };

1.4 执行 SQL 执行前后台脚本(可选,执行在服务器端)

设置此脚本可以满足以下需求:

  • SQL 执行前需要对参数做后台校验。
  • SQL 执行前需要改变或者新增参数。
    例:
  1. if (!@11-PHONE@) {
  2. // 校验不合法则调用 done 方法,并设置 success 参数为 false。
  3. done(null, {
  4. success: false,
  5. message: '电话号码必填'
  6. });
  7. return;
  8. }
  9. /* 可以根据情况再做一次 IO 来深度校验某些参数,然后调用 done() 方法。*/
  10. // var dbService = Enhancer.getDatabaseService();
  11. // ...
  12. /* 如果希望覆盖或者新增变量参数,则增加第三个参数传递,作为新增变量列表。*/
  13. // done(null, null, {
  14. // "11-PHONE": 9872129,
  15. // "11-NEW_VAR": "Hello" <-- SQL 中可使用 @11-NEW_VAR@
  16. // });
  17. /* 一定要调用 done 方法,这样才能继续执行后续程序。*/
  18. done();

注意:一定要调用 done 方法,程序才能继续执行

1.5 执行 SQL 执行后后台脚本(可选,执行在服务器端)

设置此脚本可以满足以下需求:

  • SQL 执行后需要对执行结果做进一步处理。可以直接在脚本中使用 @SQL_RESULT@ 变量,获取 SQL 执行结果。
  • 需要通过脚本发起短信,邮件通知等。
    例:
  1. var r0 = @SQL_RESULT@.results[0];
  2. if (!r0.affectedRows) {
  3. done(null, {
  4. success: false,
  5. other: '其他数据',
  6. message: '未更新到记录' // <-- 可以再次指定提示消息,覆盖提示配置美容。
  7. });
  8. } else {
  9. done(); // <-- 不传递参数,则默认正常返回。前端 @2-LAST_PROCEDURE_RESULT@ 变量拿到的数据即 SQL 执行结果。
  10. }

注意:一定要调用 done 方法,程序才能继续执行

1.6 同步执行(可勾选)

  • 如果勾选,则前端后续动作需要等待此后台过程完成之后才能执行,并且要求后台过程执行正确。如果后台执行发生错误,则前端的后续动作不会执行。
  • 如果不勾选,则前端的后续动作不会受后台过程执行影响,彼此独立进行。

2 执行 JavaScript 过程【选修】

如果编写通用 SQL 的方式不能满足您的特殊业务需求,那么可以编写原生后台 JavaScript 过程,控制整个执行过程。后台可供使用的 API 参考API-Server.md

  • 通用示例
  1. var sql = `UPDATE student SET name = ?
  2. , birthday = ?, birth_place = ?
  3. , gender = ?, phone = ?
  4. , nation = ?, entry_year = ?
  5. , ssn = ?, family_address = ?
  6. , political_status = ?, school_year_length = ?
  7. WHERE student_no = ?`;
  8. // 直接 @变量@ 从页面取用本次过程执行需要的数据。
  9. //【注意】要把@变量@单独放在 params 数组中传递,不要拼接 SQL 字符串,以防止 SQL 注入攻击。
  10. var params = [
  11. @12-NAME@, @12-BIRTHDAY@, @12-BIRTH_PLACE@
  12. , @12-GENDER@, @12-PHONE@, @12-NATION@, @12-ENTRY_YEAR@
  13. , @12-SSN@, @12-FAMILY_ADDRESS@, @12-POLITICAL_STATUS@
  14. , @12-SCHOOL_YEAR_LENGTH@, @12-STUDENT_NO@
  15. ];
  16. // Enhancer 是全局对象,直接使用。
  17. var databaseService = Enhancer.getDatabaseService();
  18. // 执行 SQL
  19. databaseService.execute(sql, params, function(err, result) {
  20. if (err) {
  21. // 不论结果执行成功失败,需要调用 done 方法表示本次过程结束。
  22. // done 方法的第一个参数传递系统级 err,第二个参数传递常规结
  23. // 果对象(包含 success 和 message 字段)。
  24. done(null, {
  25. success: false,
  26. message: '操作失败操作失败。' + err.message
  27. });
  28. return;
  29. }
  30. done(null, {
  31. success: true,
  32. message: '修改成功!'
  33. });
  34. });
  35. // 注意:执行 SQL 的数据库连接的获取和释放由内部统一控制,用户无需关心。
  36. // 如果需要做事务,可以调用 databaseService.beginTransaction 方法,
  37. // 请参考: https://assets.enhancer.io/enhancer/tutorials/0.3.0/zh-cn/api-server.html

【附】服务器端编程 API

注意:一定要调用 done 方法,程序才能继续执行

注意:不要自己拼接 SQL 字符串中的参数, 而要用 ? 来占位,然后把对应的参数值存放在 params 对象中。这样预声明处理,可以避免 SQL 注入攻击。

使用 Enhancer 后台执行程序,结合 Enhancer 变量体系,可以使得业务逻辑的开发变得更直观和高效。

Demo