【发布时间】:2020-03-31 12:25:01
【问题描述】:
我定义了以下实体(简化)...
@Entity(name = "metrics")
data class MetricsEntity(
val name: String,
// ... other properties omitted for clarity
@ElementCollection(fetch = FetchType.EAGER)
@MapKeyColumn(name = "event_name")
@Column(name = "event_count")
@CollectionTable(name = "metric_event", joinColumns = [JoinColumn(name = "metrics_id")])
val events: MutableMap<String, Int>,
)
这里的想法是,对于指标表中的每个条目,我们都会记录事件计数,并最终得到一个包含此类条目的表...
metrics_id | event_name | event_count
------------+-----------------------------------+-------------
15647624 | Launched | 1
15647624 | Registration_successful | 10
15647624 | Registration_failed | 2
15647624 | History_viewed | 1
在代码中,我们使用类似这样的方式加载指标实体...
val metrics = metricsRepository.findByProperties(properties)
...获取单个指标。此处的选择标准已被简化,但足以说明我们从该查询中获得了一个指标实例。这里的仓库定义为...
interface MetricsRepository : CrudRepository<MetricsEntity, Long> {
...
}
现在我们要么更新事件映射以添加一个新计数,要么使用以下代码增加现有计数...
metrics.events[eventName] = (it.events[eventName] ?: 0) + 1
metricsRepository.save(it)
这在绝大多数情况下都有效,但保存调用时不时会在上表中引发称为 metric_event_constraint 的约束违规,该约束被定义为...
ALTER TABLE metric_event ADD CONSTRAINT metric_event_constraint UNIQUE (metrics_id, name);
这似乎表明当一行已经存在时,保存操作正在保存一个新行。查看日志表明我在尝试修改相同计数的多个线程之间发生冲突...
08:58:18.466 INFO 3 --- [TaskExecutor-11] incr count for event Launched, count 1
08:58:18.487 INFO 3 --- [cTaskExecutor-4] incr count for event Launched, count 1
08:58:18.618 ERROR 3 --- [cTaskExecutor-4] incr count failed for request
08:58:24.623 INFO 3 --- [TaskExecutor-94] incr count for event Launched, count 2
08:59:14.951 INFO 3 --- [askExecutor-126] incr count for event Launched, count 3
...这里第一个事件起作用并增加计数,第二个事件失败并且没有(捕获到约束违规),第三个和第四个工作正常。当我们想要 4 个时,总数为 3。在我看来,第一个和第二个事件发生了冲突。
所以问题首先是你认为这个总结是否正确?其次,我如何使它工作;)?我的假设是我需要锁定度量实体,那么我将如何使用使用的 crud 存储库和实体类的框架来解决这个问题?
这背后的数据库是 Postgres。
问候,
标记
【问题讨论】:
标签: postgresql spring-boot jpa kotlin