Grails中的批量更新记录

时间:2010-05-28 13:05:20

标签: grails groovy gorm

我必须根据各个操作计算每个用户的“总数” - 也就是说,User hasMany Actions并且每个Action都有一个点。所以我需要基本上得到所有行动的所有要点的总和。

定期添加和减少操作。由于这可能是一个相当繁重的操作,因此每次需要时执行“total”都是不可行的。因此,我想为每个用户每天运行一次操作,并将用户的总点数存储为int。

因为我有成千上万的用户,所以我想找出最好的方法。我应该基本遍历所有用户并每次调用User.save(),还是我可以在Grails / GORM中使用某种批量更新机制?

2 个答案:

答案 0 :(得分:1)

您问题中的模型是您的实际模型还是简化版?如果您正在做的只是User hasMany Actions并且每个Action都有一个您想要总结的点值(一个整数?),这实际上是关系数据库擅长的那种。如果你的数据库上有适当的索引,我认为这只是一个非常快速的调用,只要你正在进行groupBy查询(或使用grails投影标准)。

这是一个示例方法,它将获取用户列表并返回一个数组,该数组将user.id与用户当前拥有的点数相对应:

def calculateCurrentPoints(users) {
    Action.executeQuery('select a.user.id, sum(points) from Action a where a.user.id in (:userIds) group by a.user.id', [userIds: users.id])
}

如果需要,您可以轻松将其转换为用户ID到点的地图,以便于查找:

def calculateCurrentPoints(users) {
    def result = Action.executeQuery('select a.user.id, sum(points) from Action a where a.user.id in (:userIds) group by a.user.id', [userIds: users.id])
    result.inject([:]) { map, userWithPoints -> 
        map[userWithPoints[0]] = userWithPoints[1]
        return map
    }
}

如果这确实比我想象的要慢,你可以使用带有HQL的executeUpdate,类似于我上面的内容,更新每个用户的“totalPoints”字段(或者随时更新为服务的一部分)您向该用户添加一个新的Action)。

答案 1 :(得分:0)

调用User.save()实际上不会将更改写入数据库,只有在刷新Hibernate会话时才会写入更改(docs

您可以手动刷新会话,访问SessionFactory并在生成的会话中调用flush,如FAQ所示。

我想你会想要使用批处理技术加载用户,以确保你不会同时拥有内存中的所有数千个用户。

另外,如果你想缓存这个值但是每当你添加一个动作时它都会自动更新,你可以挂钩到活动记录的事件来更新计算值,这里是example from Ruby