Skip to content

链式操作

在 dream-orm中,内置了 QueryDefUpdateDefDeleteDefInsertDef 用于对数据进行查询、修改、删除和插入操作,链式依赖APT在编译时生成对应代码,默认处于关闭状态。

开启链式操作

FlexAPT注解

java
public @interface EnableFlexAPT {
    /**
     * 生成apt类的后缀
     *
     * @return
     */
    String classSuffix() default "Def";

    /**
     * 生成类所在目录
     * 支持./、../和/
     *
     * @return
     */
    String dir() default "../def";
}
属性描述
classSuffix生成apt类的后缀
dir生成类所在目录

APT编译生成的代码不仅仅依赖Table注解声明的类,还依赖View注解声明的类。

查询SQL

select

举例:查询多个字段

sql
select(account.id,account.name)

SQL输出

sql
SELECT `account`.`id`,`account`.`name`

举例:查询数组

sql
select(account.accountView)

accountView数组是由视图类AccountView编译生成的数组,查询的字段等同于视图类声明的属性

SQL输出

sql
SELECT `account`.`id`,`account`.`name`,`account`.`age`,`account`.`email`

字段别名

sql
account.name.as("uname")

SQL输出

sql
`account`.`name` `uname`

case

测试

sql
case_(account.age).when(11).then(11).when("11").then("字符串11").else_("默认值").end()

SQL输出

sql
CASE `account`.`age` WHEN 11 THEN 11 WHEN '11' THEN '字符串11' ELSE '默认值' END

测试条件

sql
case_().when(account.age.eq(11)).then(11).when(account.age.eq("11")).then("字符串11").else_("默认值").end();

SQL输出

sql
CASE  WHEN `account`.`age`=? THEN 11 WHEN `account`.`age`=? THEN '字符串11' ELSE '默认值' END

函数

目前,dream-orm已支持 80+ 个常见的 SQL 函数,查看已支持的 所有函数 。 若还不满足,您可以参考 FunctionDef ,然后在自己的项目里进行自定义扩展。

支持的函数函数说明
ascii返回字符串 s 的第一个字符的 ASSCII 码
len返回字符串 s 的字符数
length返回字符串 s 的长度
concat将字符串 s1,s2 等多个字符串合并为一个字符串
group_concat将同一组的列显示出来,并且用分隔符分隔
find_in_set返回在字符串 s2 中与 s1 匹配的字符串的位置
coalesce返回第一个非NULL参数
concat_ws同 CONCAT(s1, s2, ...),但是每个字符串之间要加上 x
instr从字符串 s 中获取 s1 的开始位置
locate函数返回subStr在string中出现的位置
lcase将字符串 s 的所有字符都变成小写字母
lower将字符串 s 的所有字符都变成小写字母
upper将字符串 s 的所有字符都变成大写字母
left返回字符串 s 的前 n 个字符
repeat将字符串 s 重复 n 次
right返回字符串 s 的后 n 个字符
ltrim去掉字符串 s 开始处的空格
rtrim去掉字符串 s 结尾处的空格
trim去掉字符串 s 开始处和结尾处的空格
reverse将字符串 s 的顺序反过来
replace用字符串 s2 代替字符串 s 中的字符串 s1
strcmp比较字符串 s1 和 s2
substr获取从字符串 s 中的第 n 个位置开始长度为 len 的字符串
abs返回绝对值
avg返回指定列的平均值
sum返回指定字段值的和
count查询数据总量
ceil返回大于或等于 x 的最小整数(向上取整)
ceiling返回大于或等于 x 的最小整数(向上取整)
floor返回小于或等于 x 的最大整数(向下取整)
rand返回 0~1 的随机数
pi返回圆周率
min返回指定列的最小值
max返回指定列的最大值
sign返回 x 的符号,x 是负数、0、正数分别返回 -1、0、1
truncate返回数值 x 保留到小数点后 y 位的值
round返回离 x 最近的整数(四舍五入)
pow返回 x 的 y 次方
power返回 x 的 y 次方
sqrt返回 x 的平方根
exp返回 e 的 x 次方
mod返回 x 除以 y 以后的余数
ln返回数字的自然对数
log返回自然对数(以 e 为底的对数)
log2返回以 2 为底的对数
log10返回以 10 为底的对数
sin求正弦值
asin求反正弦值
cos求余弦值
acos求反余弦值
tan求正切值
atan求反正切值
atan2返回两个值的反正切
cot求余切值
date_add计算开始日期 d 加上 n 天的日期
date_sub计算起始日期 d 减去 n 天的日期
date_format以不同的格式显示日期/时间数据
str_to_date将字符串转换为日期时间
curdate返回当前日期
datediff计算日期 d1 到 d2 之间相隔的天数
year返回日期 d 中的年份值
month返回日期 d 中的月份值,范围是 1~12
day返回日期 d 中的天数值
quarter返回日期 d 是第几季度,范围 1-4
hour返回时间 t 中的小时值
minute返回时间 t 中的分钟值
second返回时间 t 中的秒钟值
dayofweek返回日期 d 是星期几,1 表示星期日,2 表示星期二
dayofyear计算日期 d 是本年的第几天
weekofyear计算日期 d 是本年的第几个星期,范围是 1-53
last_day提取给定日期当月的最后一天
date提取时间的日期部分
now返回当前日期和时间
sysdate返回当前日期和时间
ifnull如果不是NULL,则返回第一个参数。 否则,IFNULL函数返回第二个参数
if_如果expr1为TRUE,则IF()返回值为expr2,否则返回值为expr3
lpad字符串 s2 来填充 s1 的开始处,使字符串长度达到 len
rpad字符串 s2 来填充 s1 的结尾处,使字符串长度达到 len
space返回 n 个空格
unix_timestamp以 UNIX 时间戳的形式返回当前时间
from_unixtime把 UNIX 时间戳的时间转换为普通格式的时间
nullif如果两个参数相等,则返回NULL;否则就返回第一个参数
convert将任何类型的值转换为具有指定类型的值
cast将任何类型的值转换为具有指定类型的值
to_char指定的格式将时间戳值、间隔值、数字值转为字符串
to_number将指定的字符串转为一个数字
to_date转换为 普通的时间格式
to_timestamp转换可为 时间戳格式

from

测试

sql
select(account.id).from(account)

SQL输出

sql
SELECT `account`.`id` FROM `account`

测试关联查询以及表别名

sql
AccountTableDef account2=new AccountTableDef("account2")
select(account.id).from(account).leftJoin(account2).on(account2.id.eq(account.id))

AccountTableDef是APT自动生成的,传入一个字符串表示表的别名

SQL输出

sql
SELECT `account`.`id` FROM `account`  LEFT JOIN `account` `account2` ON `account2`.`id`=`account`.`id`

where

测试

sql
select(account.id).from(account).where(account.name.like("a"))

SQL输出

sql
SELECT `account`.`id` FROM `account`  WHERE `account`.`name` LIKE CONCAT('%',?,'%')

测试动态条件1

sql
select(account.id).from(account).where(account.name.like("a", Objects::isNull))

SQL输出

SELECT `account`.`id` FROM `account`

测试动态条件2

sql
select(account.id).from(account).where(account.name.like("a").when(false))

SQL输出

sql
SELECT `account`.`id` FROM `account`

and

测试

sql
account.name.like("a").and(account.age.eq(11))

SQL输出

sql
`account`.`name` LIKE CONCAT('%',?,'%') AND `account`.`age`=?

or

测试

sql
account.name.like("a").or(account.age.eq(11))

SQL输出

sql
`account`.`name` LIKE CONCAT('%',?,'%') OR `account`.`age`=?

groupBy

测试

sql
select(count(account.id)).from(account).groupBy(account.age);

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  GROUP BY `account`.`age`

having

测试

sql
select(count(account.id)).from(account).groupBy(account.age).having(account.name.likeLeft("a"))

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  GROUP BY `account`.`age` HAVING `account`.`name` LIKE CONCAT('%',?)

orderBy

测试

sql
select(count(account.id)).from(account).orderBy(account.age.desc(),account.name.asc())

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  ORDER BY `account`.`age` DESC,`account`.`name` ASC

limit

测试

sql
select(count(account.id)).from(account).limit(5,10)

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  LIMIT ?,?

offset

测试

sql
select(count(account.id)).from(account).offset(10,5)

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  LIMIT ? OFFSET ?

union

测试

sql
select(count(account.id)).from(account).union(select(count(account.id)).from(account))

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  UNION SELECT COUNT(`account`.`id`) FROM `account`

unionAll

测试

sql
select(count(account.id)).from(account).unionAll(select(count(account.id)).from(account))

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  UNION ALL SELECT COUNT(`account`.`id`) FROM `account`

forUpdate

测试

sql
select(count(account.id)).from(account).forUpdate()

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  FOR UPDATE

forUpdateNoWait

测试

sql
select(count(account.id)).from(account).forUpdateNoWait()

SQL输出

sql
SELECT COUNT(`account`.`id`) FROM `account`  FOR UPDATE NOWAIT

更新SQL

测试

sql
update(account).set(account.age, account.age.add(1)).set(account.name, "accountName").where(account.id.eq(1))

SQL输出

sql
UPDATE `account`  SET `account`.`age`=`account`.`age`+1,`account`.`name`=?  WHERE `account`.`id`=?

新增SQL

测试

sql
insertInto(account).columns(account.name, account.age).values("accountName", 12)

SQL输出

sql
INSERT INTO `account` (`name`,`age`)VALUES(?,?)

删除SQL

测试

sql
delete(account).where(account.id.eq(1))

SQL输出

sql
DELETE FROM `account`   WHERE `account`.`id`=?

综合操作

创建好的链式SQL最终目的是为了进行数据库操作,可以使用FlexMapper接口

java
/**
 * 链式操作类
 */
public interface FlexMapper {
    /**
     * 白名单,列如开启插件后,链式并不默认添加,需要在白名单额外增加
     */
    Set<Class<? extends Inject>> WHITE_SET = new HashSet<>();

    /**
     * 查询并返回一条
     *
     * @param query 查询定义器
     * @param type  返回类型
     * @param <T>
     * @return 单条数据
     */
    <T> T selectOne(Query query, Class<T> type);

    /**
     * 查询并返回集合
     *
     * @param query 查询定义器
     * @param type  返回类型
     * @param <T>
     * @return 集合数据
     */
    <T> List<T> selectList(Query query, Class<T> type);

    /**
     * 查询并返回分页
     *
     * @param query 查询定义器
     * @param type  返回类型
     * @param page  分页
     * @param <T>
     * @return 分页数据
     */
    <T> Page<T> selectPage(Query query, Class<T> type, Page page);

    /**
     * 更新操作
     *
     * @param updateDef 更新定义器
     * @return 更新数量
     */
    int update(Update updateDef);

    /**
     * 删除操作
     *
     * @param deleteDef 删除定义器
     * @return 删除数量
     */
    int delete(Delete deleteDef);

    /**
     * 插入操作
     *
     * @param insertDef 插入定义器
     * @return 插入数量
     */
    int insert(Insert insertDef);
}
方法描述
WHITE_SET链式使用插件的白名单,默认不添加,处于性能考虑,需要开发者手动加入插件到白名单
selectOne根据查询链式SQL查询一条数据
selectList根据查询链式SQL查询多条数据
selectPage根据查询链式SQL分页查询多条数据(链式SQL不支持手动加入分页)
update根据更新链式SQL做修改操作
delete根据删除链式SQL做删除操作
insert根据插入链式SQL做插入操作

测试一:查询单条

测试

java
/**
 * 测试主键查询
 */
@Test
public void testSelectById() {
    Query query = select(account.accountView).from(account).where(account.id.eq(1));
    AccountView accountView = flexMapper.selectOne(query, AccountView.class);
    System.out.println("查询结果:" + accountView);
}

控制台输出

tex
方法:null
语句:SELECT `account`.`id`,`account`.`name`,`account`.`age`,`account`.`email` FROM `account`  WHERE `account`.`id`=?
参数:[1]
用时:110ms
查询结果:AccountView{id=1, name='Jone', age=18, email='test1'}

测试二:查询多条

测试

java
    /**
     * 测试查询多条
     */
    @Test
    public void testSelectList() {
        Query query = select(account.accountView).from(account).where(account.id.gt(3));
        List<AccountView> accountViews = flexMapper.selectList(query, AccountView.class);
        System.out.println("查询结果:" + accountViews);
    }

控制台输出

tex
方法:null
语句:SELECT `account`.`id`,`account`.`name`,`account`.`age`,`account`.`email` FROM `account`  WHERE `account`.`id`>?
参数:[3]
用时:34ms
查询结果:[AccountView{id=4, name='Sandy', age=21, email='test4'}, AccountView{id=5, name='Billie', age=24, email='test5'}]

测试三:分页查询

测试

java
    /**
     * 测试分页查询
     */
    @Test
    public void testSelectPage() {
        Query query = select(account.accountView).from(account).where(account.id.gt(1));
        Page page=new Page(1,2);
        page = flexMapper.selectPage(query, AccountView.class,page);
        System.out.println("总数:"+page.getTotal()+"\n查询结果:" + page.getRows());
    }

控制台输出

tex
方法:null
语句:SELECT COUNT(1) FROM `account`  WHERE `account`.`id`>?
参数:[1]
用时:48ms
方法:null
语句:SELECT `account`.`id`,`account`.`name`,`account`.`age`,`account`.`email` FROM `account`  WHERE `account`.`id`>? LIMIT ?,?
参数:[1, 0, 2]
用时:18ms
总数:4
查询结果:[AccountView{id=2, name='Jack', age=20, email='test2'}, AccountView{id=3, name='Tom', age=28, email='test3'}]

测试四:更新操作

测试

java
    /**
     * 测试更新
     */
    @Test
    public void testUpdate() {
        Update updateDef = update(account).set(account.age, account.age.add(1))
            .set(account.name, "accountName").where(account.id.eq(1));
        flexMapper.update(updateDef);
    }

控制台输出

tex
方法:null
语句:UPDATE `account`  SET `account`.`age`=`account`.`age`+1,`account`.`name`=?  WHERE `account`.`id`=?
参数:[accountName, 1]
用时:13ms

测试五:新增操作

测试

java
    /**
     * 测试插入
     */
    @Test
    public void testInsert() {
        Insert insertDef = insertInto(account).columns(account.name, account.age).values("accountName", 12);
        flexMapper.insert(insertDef);
    }

控制台输出

tex
方法:null
语句:INSERT INTO `account` (`name`,`age`)VALUES(?,?)
参数:[accountName, 12]
用时:7ms

测试六:删除操作

测试

java
    /**
     * 测试删除
     */
    @Test
    public void testDelete() {
        DeleteDef deleteDef= delete(account).where(account.id.eq(1));
        flexMapper.delete(deleteDef);
    }

控制台输出

tex
方法:null
语句:DELETE FROM `account`   WHERE `account`.`id`=?
参数:[1]
用时:9ms