简介
DREAM(https://github.com/moxa-lzf/dream)是一款基于翻译的以技术为中心,辐射业务持久层框架
特性
跨平台:解析手写sql为抽象树,进而在不同数据库下翻译,并提供接口满足开发者自定义跨平台
函数化:一切sql皆函数,可以用函数代替复杂的sql,根据业务私有化定制函数,极大简化sql写法
缓存机制:一切数据皆可缓存,基于表的缓存,保证读到的数据与数据库一致
插件机制:接口代理,高扩展
监听机制:内置监听器输出sql信息,用于debug开发;提供阻断执行,数据修改功能
简便性:提供了简便的jpa操作,满足简单的sql操作,嵌套高级映射0配置
性能高:从调用开始到拿到结果直线执行,消灭无用的if判断
扩展强:核心功能全部接口工厂实现,可以重写任意接口自主实现功能
开箱即用:多数据源,数据权限,多租户,默认值注入,逻辑删除
优势
精简SQL
查询条件复杂情况
如果当查询条件非常复杂时,这些要查询的字段依旧必须要写,最简单的做法
代码语言:javascript复制select * from ...
没有谁建议这样写,而且查询所有字段,效率太低啦,dream提供了极其简单的写法,可改写成
代码语言:javascript复制select @all() from ...
引入了@all(),意思是查询所有可以映射成Java属性的字段,而不是数据库所有字段,会随着Java类属性的变化,自动调整查询字段,性能等价于查询具体字段。
查询条件简单情况
简单的查询,如果再继续使用@all()也是不够精简的,因为完全可以将SQL屏蔽,列如采用jpa或者lambda SQL写法,dream也提供了简单的写法,基于注解生成where条件。
为什么基于注解,而不是基于lambda SQL;并非dream不想支持,而是不能支持!
一条简单的SQL在其他orm框架眼里可以说一文不值,即便每次SQL操作重复解析,也没什么大不了影响不到性能,但dream不一样,一条SQL的解析是非常复杂的,而且极度耗时,每一条SQL处理的结果必须保存起来,基于lambda SQL必然的要重复解析SQL
基于注解的生成where条件,虽不易阅读,换来了在前端传入数据给后台时,查询条件间接生成。只需要在Java对象属性字段标记对应注解即可,列如:where条件
代码语言:javascript复制where 1=1
<if test="name!=null and name !=''">
and user.name like('%',name,'%')
</if>
<if test="age!=null">
and age in
<foreach item="item" index="index" collection="age"
open="(" separator="," close=")">
#{item}
</foreach>
</if>
采用注解形式:
代码语言:javascript复制public class UserCondition {
@Conditional(table = "user",value = ContainsCondition.class)
private String name;
@Conditional(value = InCondition.class)
private List<Integer> age;
}
写法速度上一目了然,注解性能等价于写具体where条件。
分页处理
mybatis分页可以说是所有orm框架里分页最慢的,而且并没有对分页进行优化,列如:统计字段并不需要排序条件,查询字段也是可以精简到select 1。dream框架做到了上述精简。
目前持久层框架普遍的一个问题,每次查询时,都要重新注入分页条件,这一点性能对项目整体而言是微乎其微的,但dream做到了只分页一次,拒绝多次分页,性能等价于直接在SQL写分页条件
极致缓存
任何查询数据都会缓存,而且保证读到的缓存与数据库一致,硬件环境的足够优秀,并不会关注这些,但并不妨碍dream提供这种方案,提高性能
类型转换器
类型转换器在mybatis概念里,就是指定要采用什么样的方式设置占位符值,普遍orm框架为了简单完全是依靠Java属性字段判断的,列如:Java是字符串采用setString方案,但此时如果数据库字段是
int类型,采用setString就不合理啦,dream在选型类型转换器时,是非常严格的,由Java字段返回值类型和数据库字段类型共同决定,列如SQL
代码语言:javascript复制select * from user where user_id=@$(userId)
dream会解析到Java对象字段userId的值,保存到表user字段为user_id里,获取到了java字段属性以及数据库字段属性,进而严格选择类型转换器
无感屏蔽映射
使用mybatis需要用resultMap写Java属性与数据库字段的映射
1:编写Java对象接受类
代码语言:javascript复制public class User {
private Integer id;
private String name;
private List<Blog> blogList;
}
public class Blog {
private Integer id;
private String name;
}
2:编写映射关系
代码语言:javascript复制<resultMap id="xxx" type="xxx.xxx.User">
<result column="id" property="id"></result>
<result column="name" property="name"></result>
<collection property="blogList" ofType="xxx.xxx.Blog">
<result column="id" property="id"></result>
<result column="name" property="name"></result>
</collection>
</resultMap>
所谓无感就是不需要感知就已实现,dream仅仅就需要第一步步骤即可,不需要写任何映射关系,因为dream映射原理前提知道这个字段属于那个表,进而进行高级映射
代码语言:javascript复制@View("user")
public class User {
private Integer id;
private String name;
private List<Blog> blogList;
}
@View("blog")
public class Blog {
private Integer id;
private String name;
}
无感屏蔽多租户
考虑同一个库,同一个schema情况,将现有项目改写成多租户,实现成本是多少,可能会说成本太大啦,所有SQL基本上都要翻新,而dream却给了你0成本方案,既然无感知,成本自然为0
查询用户表user和文章表blog的前一条数据
代码语言:javascript复制SELECT
*
FROM
(
SELECT
u.id,
u.NAME,
u.age,
u.email,
b.id bId,
b.NAME bName
FROM
USER u
LEFT JOIN blog b ON b.user_id = u.id
) t_tmp
LIMIT 1
若用户表和文章表都存在租户字段,将其改造为多租户,dream可以让你不用修改当前SQL,在启动类添加开启多租户插件即可自动将其改造成多租户
代码语言:javascript复制SELECT
*
FROM
(
SELECT
u.id,
u.NAME,
u.age,
u.email,
b.id bId,
b.NAME bName
FROM
USER u
LEFT JOIN blog b ON ( b.user_id = u.id )
AND b.tenant_id =?
WHERE
u.tenant_id =?) t_tmp
LIMIT 1
dream的识别是高强度的,不会因为SQL复杂,漏加任何租户条件,那性能如何?是等价于直接写租户条件的,无性能损耗
无感屏蔽数据权限
采用mybatis方案进行数据权限隔离,会在where条件注入 ${权限条件},是否可以不写${权限条件},一样完成数据权限注入,这样实现才是真正意义上的权限SQL与业务SQL解耦
同样SQL,需要注入数据权限,假如:查询自己所在部门
代码语言:javascript复制SELECT
*
FROM
(
SELECT
u.id,
u.NAME,
u.age,
u.email,
b.id bId,
b.NAME bName
FROM
USER u
LEFT JOIN blog b ON b.user_id = u.id
) t_tmp
LIMIT 1
开启数据权限插件
代码语言:javascript复制SELECT
*
FROM
(
SELECT
u.id,
u.NAME,
u.age,
u.email,
b.id bId,
b.NAME bName
FROM
USER u
LEFT JOIN blog b ON b.user_id = u.id
WHERE
u.dept_id = 1
) t_tmp
LIMIT 1
u.dept_id=1是开发者自己注入的数据权限,不要担心,dream会解析出别名告诉开发者,完成数据权限注入,此时,SQL非常清爽,性能等价于在SQL直接写注入权限条件
无感屏蔽逻辑删除
有些字段是需要进行逻辑删除的,有些字段不需要,区别在于表是否加了逻辑字段,假如:未来有个需求,这个表不需要逻辑删除,另一张表需要逻辑删除,代码修改必不可少,幸运的是有些框架提供了逻辑删除,自动将delete语句改成update语句,代码量基本上无改动,事实上,表与表之间关联条件以及where条件是否都加了逻辑条件,仍然需要一步一步改。
同样的SQL,假设用户表user和文章表都存在逻辑删除字段,改造为逻辑删除
代码语言:javascript复制SELECT
*
FROM
(
SELECT
u.id,
u.NAME,
u.age,
u.email,
b.id bId,
b.NAME bName
FROM
USER u
LEFT JOIN blog b ON b.user_id = u.id
) t_tmp
LIMIT 1
开启逻辑删除插件
代码语言:javascript复制SELECT
*
FROM
(
SELECT
u.id,
u.NAME,
u.age,
u.email,
b.id bId,
b.NAME bName
FROM
USER u
LEFT JOIN blog b ON ( b.user_id = u.id )
AND b.del_flag = 0
WHERE
u.del_flag = 0
) t_tmp
LIMIT 1
完成了SQL操作的逻辑字段追加,删除数据库里的逻辑字段就不采用逻辑删除,同样,希望某张表采用逻辑删除,加个逻辑字段即可,代码不需要做任何修改,性能等价于直接写逻辑删除条件,性能无损耗
极致的数据库关键字处理
数据库关键字,不是关键字可以不加特殊符号,关键字必须要加,dream提供方案,SQL语句可以不加特殊符号对关键字处理,一样可以正常执行
SQL语句,若user和id为关键字,不做处理会执行报错,正确做法需要对user和id加特殊符号
代码语言:javascript复制SELECT
*
FROM
(
SELECT
u.id,
u.NAME,
u.age,
u.email,
b.id bId,
b.NAME bName
FROM
USER u
LEFT JOIN blog b ON b.user_id = u.id
) t_tmp
LIMIT 1
开启关键字插件
代码语言:javascript复制SELECT
*
FROM
(
SELECT
u.`id`,
u.NAME,
u.age,
u.email,
b.`id` bId,
b.NAME bName
FROM
`USER` u
LEFT JOIN blog b ON b.user_id = u.`id`
) t_tmp
LIMIT 1
自动完成对user和id关键字处理,性能等价于直接写关键字处理