-
Notifications
You must be signed in to change notification settings - Fork 46
查询数据
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 <= ? |
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
中存储了上下页、总记录数、总页数、是否有上下页等信息。
有时候一些人不喜欢写生硬的 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
之间的嵌入关系,只要在查询的那一刻确定关系即可,
避免了性能阻碍和延迟加载这些繁琐的概念。
我们用一个例子来说明这些问题:有这样几张表 topics
、comments
、users
。在 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
会发布多个 topic
和 comment
。我们可能会遇到以下的查询场景:
- 查询
Topic
并查询这个Topic
下的所有评论 - 查询
Comment
并查询发布评论的User
信息 - 查询
User
并查询他发布的Topic
和Comment
你想当然的会说用 SQL 的 join
来完成,但是这时候会遇到一个问题,查询出的结果其实是包含多种 Model
信息的,我们必须再创建一个 Model
去存储,这比较麻烦。在 Anima
种实现上面的三个查询是这样的
select().from(Topic.class)
.join(
Joins.with(Comment.class).as(Topic::getComments)
.on(Topic::getTid, Comment::getTid)
).byId("2333");
我们要查询 Topic
,Topic
下有多个评论,所以使用 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
中发布的评论和帖子列表。
Contributing
Documentation
- Getting started
- Create Model
- Query DB
- Save to DB
- Updates and Deletes
- Transaction
- Integration with Spring
- Advanced Usage
Other resources
中文文档