我有一个数据库表,主键定义为时间戳。应用程序根据触发的特定事件将记录插入到数据库中,并且使用的时间戳将是创建此实例的时间戳。由于此应用程序在多个服务器上运行,并且该事件同时在多个服务器中同时触发,因此在某些情况下,由于主键冲突,数据不会插入到数据库中。
为了避免这种情况,我可以改变什么?我现在的想法是,
在执行数据库插入之前等待一段随机时间。
Random r = new Random();
long time = r.nextLong() % 1000;
time = time < 0 ? -time : time; // making sure that the waiting time is positive
try {
Thread.sleep(time);
} catch (InterruptedException e) {
throw new CustomeException(e);
}
Table1DataAccess.getInstance().insert(new Date(), "some description"); // inserting data into the table which has two fields.
使主键成为复合键。
对我来说,它们似乎都不是很好的解决方案,有人能指出我正确的方向吗?
P.S。我尝试插入数据的表有Date
类型的时间戳列,我猜它只有精确到秒。当我使用类型timestamp
时,它提供了默认的微秒精度,它最多可以提供纳秒。
答案 0 :(得分:5)
不要将时间戳用作主键字段。
将Integer或BigInt用于主键自动增量字段
答案 1 :(得分:1)
将主键定义为autoincremet integer / long字段
答案 2 :(得分:1)
如果您有大量插入内容,则等待随机插入时间可能无效。答案假定您希望保留时间戳并对代码进行最小的更改,并且不希望转到DB中可用的自动增量功能。
我早就看到了类似的问题,我们修改了表以包含发起服务器节点来解决它。因此,要么展开timestamp列并保存timestamp_server,要么添加一个额外的列server_node,然后使用它。 这取决于您获取数据的方式。添加server_node列将不那么具有侵入性。但是,您是否还需要更新数据?主键无法更新。因此,在设计考虑中需要考虑这一点。
答案 3 :(得分:0)
首先,将时间戳用作主键是不明智的。主键应该是 唯一标识 数据库条目的内容。在您的应用程序中情况并非如此:即使在同一服务器中,您也可能会发生冲突。这就是为什么所有主要数据库引擎都提供自动生成主键的机制的原因之一。另请查看this answer了解详情。
在使用时间戳的假设情况下(可能因为现在改变整体设计为时已晚),您可以在相应的时间戳前面添加相应服务器的唯一标识符。然而,在同一服务器内同时写入的情况下,不将是唯一标识符。然后,在捕获主键冲突错误时,您需要附加另一个增量标识符。这并不能完全解决你的问题。例如,您可以在同一服务器中拥有相同的增量标识符。你会看到这个过程有多乱。
因此,如果您允许数据库引擎为您分配主键,那么带回家的消息就是可以节省您大量的时间和精力。