【问题标题】:Generate Primary key without using Database不使用数据库生成主键
【发布时间】:2010-08-26 13:20:21
【问题描述】:

我最近遇到一个问题,是关于“在 5 个应用服务器的集群环境中生成主键 - [OAS 版本 10] 而不使用数据库”。

通常我们通过 DB 序列生成 PK,或者将值存储在数据库表中,然后使用 SP 生成新的 PK 值......但是当前的要求是为我的应用程序生成主键,而不使用引用数据库JDK 1.4。

需要专家的帮助才能找到更好的方法来处理这个问题。

谢谢,

【问题讨论】:

  • 您需要数字主键还是基于字符串的也可以?
  • 只是好奇...你能简单解释一下,为什么不能使用数据库来生成主键?
  • 数据类型没有限制。字符串也可以。

标签: java database oracle primary-key


【解决方案1】:

使用UUID 作为主键,使用generate 作为客户端。

编辑:
自从您发表评论后,我觉得我应该详细说明为什么这是一种做事的好方法。

虽然顺序主键是数据库中最常见的,但对于分布式数据库或(特别是)支持“断开连接”用户界面(即用户不存在的 UI)的数据库来说,使用随机生成的主键通常是最佳选择一直连接到数据库。

UUID 是随机生成密钥的最佳形式,因为它们保证非常独特;两次生成相同 UUID 的可能性非常低,几乎完全不可能。 UUID 也无处不在;几乎每个平台都支持内置它们的生成,而对于那些不支持的平台,几乎总是有第三方库来填补空缺。

使用随机生成的主键的最大好处是,您可以在客户端构建许多复杂的数据关系(使用主键和外键),并且(例如,当您准备保存时)只需将所有内容转储到数据库在单个批量插入中,而不必依赖插入后步骤来获取稍后关系插入的密钥。

另一方面,UUID 是 16 字节,而不是标准的 4 字节 int -- 是空间的 4 倍。这些天真的是一个问题吗?我会说不是,但我知道有些人会反对。当涉及到 UUID 时,唯一真正的性能问题是索引,特别是聚集索引。我将走进 SQL Server 世界,因为我不经常针对 Oracle 进行开发,这是我目前的舒适区,并谈到 SQL Server 默认情况下会在所有字段上创建聚集索引的事实表的主键。这在自动增量 int 世界中工作得相当好,并为基于键的查找提供了一些良好的性能。然而,任何称职的 DBA 都会以不同的方式进行集群,但是那些不注意集群并且也使用 UUID(微软世界中的 GUID)的人往往会在插入繁重的数据库上遇到一些令人讨厌的减速,因为集群每次插入都必须重新计算索引,如果它针对 UUID 聚集,这可能会将新键放在聚集序列的中间,可能需要重新排列大量数据以保持聚集指数。这在 Oracle 世界中可能是也可能不是问题——我只是不知道 Oracle PK 是否像在 SQL Server 中那样默认集群。

如果那个连续的句子太难理解,请记住这一点:如果您使用 UUID 作为主键,不要聚集在那个键上

【讨论】:

  • 看来这适用于 JDK 1.5,我的要求是 JDK 1.4
  • @apx1sharma:啊,我完全错过了你问题中的那个限制。这里有两个第三方库应该可以解决问题:JUGJohann Burkard's UUID library
【解决方案2】:

您可能会发现查找 UUID 生成很有帮助。

在简单的情况下,一个程序在每台机器上运行一个线程,您可以执行以下操作

MAC address + time in nanseconds since 1970.

【讨论】:

    【解决方案3】:

    如果您根本无法使用数据库,那么 GUID/UUID 是唯一可靠的方法。但是,如果您可以偶尔使用数据库,请尝试HiLo algorithm

    【讨论】:

    • 正如我上面提到的“Radolpho”.. UUID 类可用于 JDK 5,但是我正在寻找 JDK 4 中的解决方案
    【解决方案4】:

    您应该考虑使用 UUID 形式的 id。 Java5 有一个class 来表示它们(并且还必须有一个工厂来生成它们)。使用这个工厂类,您可以将代码反向移植到您的 anticated Java 1.4 以获得您需要的标识符。

    【讨论】:

      【解决方案5】:

      查看 Hibernate 使用的these strategies(链接中的第 5.1.5 节)。你一定会发现它很有用。 它解释了几种方法及其优缺点,还说明了它们在集群环境中是否安全。

      最重要的是,有可用的代码已经为您实现了它:)

      【讨论】:

      • 这些方法需要DB参与,但我正在寻找一种不涉及数据库的方法。
      • 您可以选择 UUID 算法并重用该算法,在同一部分附近进行了解释):“UUID 包含:IP 地址、精确到四分之一秒的 JVM 启动时间、系统时间和在 JVM 中唯一的计数器值。无法从 Java 代码中获取 MAC 地址或内存地址,因此这是不使用 JNI 的最佳选择。"
      【解决方案6】:

      如果它适合您的应用程序,您可以使用更大的字符串键加上 UUID() 函数或 SHA1(随机数据)。

      对于顺序整数,我将把它留给另一张海报。

      【讨论】:

      • 您能详细说明一下吗? UUID 是 JDK5 的一部分,但我一直在寻找 JDK 4 中的解决方案。我不明白,您打算如何利用 SHA1?
      • SHA1 将对数据进行哈希处理,为相同的数据提供一致的密钥,并且冲突的可能性非常低。那将是您的唯一 ID。
      【解决方案7】:

      您可以根据以下三件事的组合生成密钥

      1. 机器的 IP 地址或 MAC 地址
      2. 当前时间
      3. 每个实例上的增量计数器(以确保不会在一台机器上生成两次相同的密钥,因为由于基础时间精度,两个即时密钥创建中的时间可能看起来相同)

      【讨论】:

      • 是的。我认为,我们可以在您建议的 pont#3 的每个主机上存储一个文件。可以同步对该文件的访问以进一步防止并发访问,以便每个线程可以访问一个数字一次且仅一次,并且在从方法返回之前,该数字可以递增。
      【解决方案8】:

      通过使用 Statement Object,您可以调用 statement.getGeneratedKeys();方法来检索由执行此 Statement 对象生成的自动生成的键。

      Java doc

      【讨论】:

        【解决方案9】:

        这是在 MongoDB 中的操作方式:http://www.mongodb.org/display/DOCS/Object+IDs

        它们包括时间戳。

        但你也可以安装Oracle Express并选择序列,你可以批量选择:

        SQL> select mysequence.nextval from dual connect by level

        下一个值

             1
             2
             3
             4
             5
            ..  
            20
        

        为什么不允许你使用数据库?钱(Oracle express 是免费的)还是单点故障?或者你以后想支持Oracle以外的其他数据库?

        【讨论】:

          【解决方案10】:

          它在许多 基于 Spring 的应用程序中提供 OOB,例如 Hybris-
          typeCode 是表的名称,例如 UserAddress 等。

          private PK generatePkForCode(final String typeCode)
              {
                  final TypeInfoMap persistenceInfo = Registry.getCurrentTenant().getPersistenceManager().getPersistenceInfo(typeCode);
                  return PK.createCounterPK(persistenceInfo.getItemTypeCode());
              }
          

          【讨论】:

            猜你喜欢
            • 2015-01-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-08-20
            • 1970-01-01
            • 1970-01-01
            • 2016-03-08
            • 2016-08-24
            相关资源
            最近更新 更多