【发布时间】:2015-02-22 10:05:57
【问题描述】:
我正在为现有的 MySQL 数据库编写基于 Java 的服务器。我可以更改数据库的结构,但任何更改也意味着挖掘一个相当古老的 CakePHP 项目,我希望尽可能不改动那个项目。
我对 Java 中的数据库访问没有太多经验,所以当我开始寻找一个好的框架时,我最终选择了 Spring Data Repositories(主要是因为我已经拥有用于 REST 服务的 Spring Boot Actuator)并且因为滚动 Hibernate 或手动执行其他 JPA 实现似乎既繁琐又复杂。
现在的问题是,我的查询速度不是很快。一个例子是查询我的约 200 个用户,并加载他们的关联(user.groups、user.groups.rights、user.groups.rights.permissions、user.rights、user.rights.permissions、users.nfc_keys)。我需要所有这些数据,因为连接到 Java 服务器的客户端之一需要这些信息来登录用户,即使主服务器出现故障并加快登录速度(换句话说,它会缓存信息)。
问题是,查询需要 8 秒才能执行!我知道这些问题,具体来说是 n+1 问题。因为我所有的收藏都是延迟加载的,所以休眠会为每个用户单独查询组、groups.rights、....。例如,我的组字段如下所示:
@ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
@JoinTable(
name = "user_group_memberships",
joinColumns={@JoinColumn(name="user_id", referencedColumnName="id")},
inverseJoinColumns={@JoinColumn(name="group_id", referencedColumnName="id")}
)
private List<Group> groups;
我尝试将 FetchType 更改为 EAGER,唯一要做的就是通过查询急切地获取所有组,但不是使用 SQL 连接,而是再次通过执行 n 查询。
我查看了this blog post 并在 UserRepository 中实现了一个查询,使用 LEFT JOIN FETCH 加载信息,需要从 Lists 更改为 Sets,由于我的 hashCode/equals 实现而对空指针问题感到恼火,再次延迟加载/设置代理,发现查询时间减少到大约 2 秒,这还不错,但与 CakePHP 执行相同查询所需的时间相比仍然非常慢。
我现在的问题主要是:是否有直接的解决方案可以使用 Spring Data Repositories 解决这些问题,或者我是否最好切换到不同的框架(在这个早期的项目阶段仍有可能)?我专门查看了 Play 框架中使用的 Ebeans,它们似乎有一个非常好的 API,并且还允许定义获取路径(这应该更好地解决 n+1 问题),但是我也读到了该项目维护不善的信息。你有什么意见?
【问题讨论】:
-
您需要启用查询日志,并研究MySql创建的查询计划。如果查询没有使用您期望的索引(您会看到表扫描等),您可能必须添加索引或手动制作查询。
标签: java spring hibernate ebean