开源SPL,ORM的终结者?
来源丨Java知音
SPL用统一数据结构和语法风格实现业务逻辑
A | B | C | |
1 | =db=connect@e("dbName") | /连接数据库,开启事务 | |
2 | =db.query@1("select sum(Amount) from sales where sellerID=? and year(OrderDate)=? and month(OrderDate)=?", p_SellerID,year(now()),month(now())) | /查询当月销售额 | |
3 | =if(A2>=10000 :200, A2<10000 && A2>=2000 :100, 0) | /本月累计奖金 | |
4 | =p_Amount*0.05 | /本单固定奖金 | |
5 | =BONUS=A3+A4 | /总奖金 | |
6 | =create(ORDERID,CLIENT,SELLERID,AMOUNT,BONUS,ORDERDATE) | /创建订单的数据结构 | |
7 | =A6.record([p_OrderID,p_Client,p_SellerID,p_Amount,BONUS, date(now())]) | /生成一条订单记录 | |
8 | >db.update@ik(A7,sales;ORDERID) | /尝试写入库表 | |
9 | =db.error() | /入库结果 | |
10 | if A9==0 | >A1.commit() | /成功,则提交事务 |
11 | Else | >A1.rollback() | /失败,则回滚事务 |
12 | >db.close() | /关闭数据库连接 | |
13 | return A9 | /返回入库结果 |
上面的SPL代码使用统一的数据结构、语法、函数,就可以完成整个业务逻辑的开发,包括数据库读写、事务处理、流程处理、数据计算。
…
//省略参数的获取过程
Class.forName("com.esproc.jdbc.InternalDriver");
Connection conn =DriverManager.getConnection("jdbc:esproc:local://");
CallableStatement statement = conn.prepareCall("{call InsertSales(?, ?,?,?)}");
statement.setObject(1, d_OrderID);
statement.setObject(2, d_Client);
statement.setObject(3, d_SellerID);
statement.setObject(4, d_Amount);
statement.execute();
...
JAVA调用SPL的形式与调用存储过程相同,且无须数据库管理员授权,不影响数据库安全,便于迁移,方便调试,处理能力更强,代码更简单。
结构化数据对象
内外数据交换能力
取单条记录:
取序表(记录集合):
比如,原序表为 T,经过增删改之后的序表为 NT, 将变化结果持久化到数据库:
流程控制能力
A | B | |
2 | … | |
3 | if T.AMOUNT>10000 | =T.BONUS=T.AMOUNT*0.05 |
4 | else if T.AMOUNT>=5000 && T.AMOUNT<10000 | =T.BONUS=T.AMOUNT*0.03 |
5 | else if T.AMOUNT>=2000 && T.AMOUNT<5000 | =T.BONUS=T.AMOUNT*0.02 |
循环语句:
A | B | |
1 | =db=connect("db") | |
2 | =T=db.query@x("select * from sales where SellerID=? order by OrderDate",9) | |
3 | for T | =A3.BONUS=A3.BONUS+A3.AMOUNT*0.01 |
4 | =A3.CLIENT=CONCAT(LEFT(A3.CLIENT,4), "co.,ltd.") | |
5 | … |
与Java的循环类似,SPL还可用break关键字跳出(中断)当前循环体,或用next关键字跳过(忽略)本轮循环,不展开说了。
SPL超越ORM获得更高的开发效率
更多计算函数
比如,时间类函数,日期增减:elapse("2020-02-27",5) //返回2020-03-03
星期几:day@w("2020-02-27") //返回5,即星期6
N个工作日之后的日期:workday(date("2022-01-01"),25) //返回2022-02-04
字符串类函数,判断是否全为数字:isdigit("12345") //返回true
取子串前面的字符串:substr@l("abCDcdef","cd") //返回abCD
更方便的集合运算
比如,批量修改记录:T.run(BONUS+AMOUNT*0.01: AMOUNT, concat(left(CLIENT,4), "co.,ltd."): CLIENT)
过滤:T.select(Amount>1000 && Amount<=3000)
对有序序表按二分法进行过滤:T.select@b(Amount>1000 && Amount<=3000)
分组汇总:T.groups(Client;sum(Amount))
涉及跨行的集合运算,通常都有一定的难度,比如比上期和同期比。ORM没有为跨行运算做优化,代码通常很繁琐。SPL使用"字段[相对位置]"引用跨行的数据,可显著简化代码,还可以自动处理数组越界等特殊情况。比如,追加一个计算列rate,计算每条订单的金额增长率:
A | |
1 | …//省略序表Employees的生成过程 |
2 | =Employees.group(DEPT; (a=~.avg(age(BIRTHDAY)),~.select(age(BIRTHDAY)<a)):YOUNG) |
3 | =A2.conj(YOUNG) |
计算某支股票最长的连续上涨天数:
A | |
1 | …//省略序表AAPL的生成过程 |
2 | =a=0,AAPL.max(a=if(price>price[-1],a+1,0)) |
更专业的结构化数据类型
比如,在序表T的基础上,按字段名取一列,返回简单集合:T.(AMOUNT)。
取几列,返回集合的集合:T.([CLIENT,AMOUNT])
取几列,返回新序表:T.new(CLIENT,AMOUNT)
按序号访问通常难度较大,序表天然有序,很容易处理此类问题。比如,按列号取几列,返回新序表:T.new(#2,#4)
按序号倒数取记录:T.m(-2)
按序号取某几条记录形成序表:T([3,4,5])
按范围取记录形成序表:T(to(3,5))
解释执行和热部署
更方便的数据库读写方法
A | B | |
1 | … | |
2 | =T=db.query("select * from salesR where SellerID=?",10) | /批量查询,序表 T |
3 | =NT=T.derive() | /复制出新序表 NT |
4 | =NT.field("SELLERID",9) | /批量修改 |
5 | =db.update(NT:T,sales;ORDERID) | /持久化到数据库 |
上面代码中,函数update实现批量修改,无须繁琐的循环语句。函数update经过精心设计,可以统一处理多种批量写库方法,遇到既有新增,又有修改和删除的批量写库的情况,SPL的优势更加明显。
A | B | |
1 | … | |
2 | =T=db.query("select * from salesR where SellerID=?",10) | /查出一批记录 |
3 | =NT=T.derive() | /复制出新序表 |
4 | =NT.delete(NT.select(ORDERID==209 || ORDERID==208)) | /批量删除 |
5 | =NT.field("SELLERID",9) | /批量修改 |
6 | =NT.record([220,"BTCH",9,5200,100,date("2022-01-02"), 221,"BTCH",9,4700,200,date("2022-01-03")]) | /批量追加 |
7 | =db.update(NT:T,salesR;ORDERID) | /持久化到数据库 |
与ORM相比,SPL是专业的结构化数据处理语言,数据对象更强大,语法更灵活,函数更丰富,可以更容易地进行数据库读写,可以简化复杂的流程处理和数据计算,可以真正提高业务逻辑的开发效率。
-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!
面试题
】即可获取