Skip to content

查询数据

見える edited this page May 4, 2022 · 14 revisions

Anima 提供了像使用 Java 8 中的 Stream 那样的方式查询数据库,它的语法看起来像写一条 SQL 语句。

首先我们先将 Anima 的静态方法 select 全局导入。

import static com.hellokaton.anima.Anima.select;

根据主键查询一条数据

User user = select().from(User.class).byId();

这个方法会产生一个 SQL 语句 SELECT * FROM users WHERE id = ? ,Anima 中使用了 PreparedStatement 中占位符的方式传递参数。 同时在控制台也会打印出具体的参数信息。

根据主键列表查询一组数据

List<User> users = select().from(User.class).byIds(1, 2, 3);
// SELECT * FROM users WHERE id in (?, ?, ?)

查询所有数据的条数

long count = select().from(User.class).count();
// SELECT COUNT(*) FROM users

根据条件查询数据

List<User> users = select().from(User.class).like("user_name", "%o%").all();
// SELECT * FROM users WHERE user_name LIKE ?

这里的条件有很多,下面是一个条件的表格

条件 参数示例 等效于 SQL
where where("id", 10) WEHRE id = ?
where where("age > ?", 10) WEHRE age > ?
where where(User::getAge).gt(10) WEHRE age > ?
like like("user_name", "jac%") WEHRE user_name like ?
like like(User::getUserName, "jac%") WEHRE user_name like ?
isNotNull isNotNull("user_name") WEHRE user_name IS NOT NULL
isNotNull isNotNull(User::getUserName) WEHRE user_name IS NOT NULL
isNull isNull("user_name") WEHRE user_name IS NULL
isNull isNull(User::getUserName) WEHRE user_name IS NULL
notEq notEq("age", 27) WEHRE age != ?
notEq notEq(User::getAge, 27) WEHRE age != ?
in in("age", 10, 22, 32) WEHRE age IN (?, ?, ?)
in in("age", list) WEHRE in (?, ?, ?)
in in(User::getAge, list) WEHRE in (?, ?, ?)
between between("age", 10, 22) WEHRE age BETWEEN ? and ?
between between(User::getAge, 10, 22) WEHRE age BETWEEN ? and ?
gt gt("age", 10) WEHRE age > ?
gt gt(User::getAge, 10) WEHRE age > ?
gte gte("age", 10) WEHRE age >= ?
gte gte(User::getAge, 10) WEHRE age >= ?
lt lt("age", 10) WEHRE age < ?
lt lt(User::getAge, 10) WEHRE age < ?
lte lte("age", 10) WEHRE age <= ?
lte lte(User::getAge, 10) WEHRE age <= ?

根据自定义 SQL 语句查询数据

String name = select().bySQL(String.class, "select user_name from users limit 1").one();

或者

List<String> names = select().bySQL(String.class, "select user_name from users limit ?", 3).all();

分页

Page<User> userPage = select().bySQL(User.class, "select * from users").page(1, 10);

查询指定的列

User user = select("user_name").from(User.class).one();
// SELECT user_name FROM users LIMIT 1

Or

User user = select(User::getUserName).from(User.class).one();
// SELECT user_name FROM users LIMIT 1

排序

User user = select("user_name").from(User.class).order("id desc").one();
// SELECT user_name FROM users ORDER BY id desc LIMIT 1

Or

select().from(User.class).order(User::getId, OrderBy.DESC).order(User::getAge, OrderBy.ASC).all();

查询固定条数

List<User> users = select().from(User.class).order("id desc").limit(5);
// SELECT * FROM users ORDER BY id desc LIMIT 5

分页查询

Page<User> userPage = select().from(User.class).order("id desc").page(1, 3);
// SELECT COUNT(*) FROM (SELECT * FROM users) tmp
// SELECT * FROM users ORDER BY id desc LIMIT ?, ?

分页对象 Page 中存储了上下页、总记录数、总页数、是否有上下页等信息。

lambda 表达式的方式

有时候一些人不喜欢写生硬的 SQL,因为他们会遇到重构问题,比如写下了 user_age > ? 当重构字段的时候可能就忘了修改 SQL 语句。 在 Anima 中你可以使用 lambda 表达式来改进这个问题,用几个例子来说明。

User user = select().from(User.class).where(User::getUserName).eq("jack").one();
List<User> user = select().from(User.class)
                .where(User::getUserName).notNull()
                .and(User::getAge).gt(10)
                .all();

你可以看到,其实比起前面的变动很简单,只是把要操作的列(Column)用方法引用(User::getUserName)代替了,其他的都是一样的。

联合查询

Anima 中抛弃了那些以往 ORM 采用的联合查询模型,但依然能够实现数据库多表关联在 Java 中的体现。 它是思路是这样的,从本质来看数据的表关系在程序中体现为 Model 之间的嵌入关系,只要在查询的那一刻确定关系即可, 避免了性能阻碍和延迟加载这些繁琐的概念。

我们用一个例子来说明这些问题:有这样几张表 topicscommentsusers。在 Java 中它们是 3 个模型

public class Topic extends Model {
    private String tid; // 帖子主键
    private Long uid;   // 发布人
    @Ignore
    private List<Comment> comments; // 评论列表
}

public class Comment extends Model {
    private String cid; // 评论主键
    private String tid; // 帖子id
    private Long uid;   // 评论人id
    @Ignore
    private User commentUser; // 评论人对象
}

public class User extends Model {
    private Long uid;  // 用户id,主键
    @Ignore
    private List<Topic> topics; // 用户发布的帖子列表
    @Ignore
    private List<Comment> comments; // 用户发布的评论列表
}

这非常容易理解,一个 topic 有多个 comment,一个 comment 会有一个评论人(commentUser),而一个 user 会发布多个 topiccomment。我们可能会遇到以下的查询场景:

  • 查询 Topic 并查询这个 Topic 下的所有评论
  • 查询 Comment 并查询发布评论的 User 信息
  • 查询 User 并查询他发布的 TopicComment

你想当然的会说用 SQL 的 join 来完成,但是这时候会遇到一个问题,查询出的结果其实是包含多种 Model 信息的,我们必须再创建一个 Model 去存储,这比较麻烦。在 Anima 种实现上面的三个查询是这样的

select().from(Topic.class)
        .join(
            Joins.with(Comment.class).as(Topic::getComments)
                 .on(Topic::getTid, Comment::getTid)
        ).byId("2333");

我们要查询 TopicTopic 下有多个评论,所以使用 join 方法来查询那些评论(当不使用的时候 comments 将是 null), 在 join 方法中接收一个 JoinParam,这里我们使用 Joins 这个静态方法构造了一个。 with 传入了 Comment(告诉anima我要查询 comments 这张表的数据),使用 as 指定了 Topic 里的哪个 字段将存储评论列表,on 方法告诉他们的关系是什么(anima得知道怎么查这些评论),很简单 topics.tid = comments.tid

select().from(Comment.class)
        .join(
            Joins.with(User.class).as(Comment::getCommentUser)
                 .on(Comment::getUid, User::getUid)
        ).byId("2333");

由上面的思路这个写法就会更简单,此处你自行分析。

select().from(User.class)
        .join(
            Joins.with(Topic.class).as(User::getTopics)
                 .on(User::getUid, Topic::getUid)
        )
        .join(
            Joins.with(Comment.class).as(User::getComments)
                 .on(User::getUid, Comment::getUid)
        ).byId(1024L);

这样就会查询出 User 中发布的评论和帖子列表。