`
pwosboy
  • 浏览: 84889 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

UniqueID Generator: A Pattern for Primary Key Generation

阅读更多

Motivation
Enterprise JavaBeans is a server-side component model that targets the specific business domain of online transaction processing (OLTP) applications. OLTP applications generally have the need to store information persistently. The data records or objects for each transaction require unique identifiers to allow them to be stored and retrieved accurately. Thus there's a need to generate unique identifiers for the data involved in an EJB transaction processing system.

For the purposes of this pattern, I'm assuming a relational database is used as the data store rather than an object database, which would provide its own ID generator. A relational database table typically has a primary key column that's indexed to prevent duplicate IDs, which would lead to data integrity problems. Thus each row stored in the table is uniquely identifiable. For instance, in EJB the return value from the call to myHome.findByPrimaryKey is a single entity bean, not multiple entities!

There are numerous ways to generate unique IDs in a Java application. Let's review some approaches before discussing the UniqueID generator pattern presented in this article.

System.currentTimeMillis()
An easy way to generate unique IDs is to utilize the System.currentTimeMillis() method to get the current time in milliseconds and use it as your ID. Although it's an easy way to start creating applications, this approach has implications across high-volume applications. A high-volume OLTP application may perform several calls to System.currentTimeMillis() at the same time, resulting in the generation of duplicate IDs. Thus the generator must perform some sort of synchronization on ID requests. Typically, this is done with a wrapper object that uses the synchronized modifier to queue threads accessing it.

Next, you ask, "What about synchronization across multiple JVMs?" Certainly a clustered-server, multi-JVM architecture will be the norm for an enterprise application, but a clustered application poses two problems for this approach toward generating unique IDs:

  1. The system time on each machine may be different. Thus, in a multi-JVM architecture, calls to System.currentTimeMillis() can lead to duplicate values.
  2. The Java synchronize operator doesn't work across multiple JVMs, so even if the system times were equal, simultaneous calls to different machines could still result in duplicate IDs.

EntityBean Key Generator
This approach uses an entity bean to select the next value from a relational database table, which holds the latest value for unique ID generation. An entity bean can encapsulate the SQL, which it executes in a generic fashion by loading in a bean environment property containing a SQL string for each type of database. For instance, in Oracle the dual table should automatically return a sequence value. The SQL statement might look something like this:

"select mysequence.nextval from dual"

Oracle sequences are a proprietary feature and increment the value automatically for the caller by a specified increment count. Other databases that don't have this feature must increment a next ID field and select it in one call. Stored procedures are a common cure for the need to execute multiple database operations within a single request. To get the same ID generation capabilities from Microsoft SQL Server, a stored procedure could be called that both returns a value and increments it for the next caller. Since the stored procedure performs its work inside a transaction in one database request, it eliminates a "window" of opportunity when simultaneous calls for another ID get the same row and attempt to update the value.

Thus our entity bean key generator executes SQL, which it retrieved generically from its bean environment property and executed on the database. However, there are some drawbacks to this approach:

  • Each call to get another ID is a remote method invocation, which can create unwanted chatter depending on where the entity bean is deployed in your system.
  • Some might argue that entity beans are for business entities rather than utilitarian functionality like generating IDs for business entities.
  • Few application servers provide synchronized caching across a cluster. Thus the ability to cache a set of IDs, improving ID generation by preventing database operations, is negated when the application is clustered.

A more scalable approach to ID generation that provides both local caching and guaranteed unique IDs is a singleton object that hands out IDs from its local cache (see Figure 1). Each time the cache of the singleton object is depleted, it gets a set of IDs representing the next available IDs for the application. The singleton fetches IDs from a stateless session bean that accesses the database in a portable manner, allowing it to interact with any database.

Applicability
Use UniqueID Generator: (Source code)

  1. To return a unique identifier for object and/or database row identity
  2. To cache sets of IDs across multiple JVMs for scalable ID generation
  3. To abstract database implementations from the core ID generation classes

Structure
Participants

  • Singleton: Acts as the wrapper of the UniqueIDEJB and caches sets of unique IDs to prevent chatty remote invocations and database operations
  • UniqueIDEJB: Component made up of UniqueID (remote interface) and UniqueIDHome (home interface); performs generic SQL to fetch a set of IDs from the database and return them to the singleton client

    Collaborations

  • Singleton: Calls UniqueIDEJB component to fetch a set of IDs; set is cached locally and a new set is fetched when the maximum is surpassed

Consequences
The UniqueID generator has several key benefits and some limitations:

  1. Limited remote method invocations and database operations: The UniqueID generator's singleton object caches a set of IDs that are depleted before another request is made to the UniqueIDEJB. This limits the number of remote method invocations on the EJB and the number of hits the database must handle to generate new IDs.
  2. Guaranteed UniqueIDs: The UniqueID generator pattern guarantees unique identifiers for your objects/data across an n-tiered solution. If a set of IDs is requested from multiple JVMs at the same time, the transaction isolation of the UniqueIDEJB and/or database layer will automatically queue multiple requests to ensure that only one singleton's request for an ID set is processed at a time.
  3. Portable across EJB servers: The pattern represents a component that's portable across EJB servers. It's a session bean, and session beans have been mandatory in the specification since its inception, whereas any EJB server still not up to the 1.1 version of the specification wouldn't be able to utilize an entity bean-based pattern.
  1. Portable across database servers: The implementation of the pattern really determines its portability, but the pattern itself allows for database-specific SQL to be loaded generically from the EJB's environment so that no code changes are required to deploy it against disparate databases.
  2. Singleton knows nothing about the "incrementBy" value: The singleton object knows nothing about how many IDs are returned in a set. This is controlled at the UniqueIDEJB level by an environment property. To change the incrementBy value, simply redeploy the EJB with a hot-deploy mechanism to avoid downtime and the increment will be changed to the new value without repercussions on the rest of the application.
  3. ID gaps: Gaps in IDs will occur with this solution. For example, if a set of 50 IDs is retrieved and the server crashes midway, 25 IDs would be lost. My recommendation is to increment only by one until ready for production, then set the UniqueIDEJB's incrementBy environment property to be sufficient for your application's load. This prevents wasting IDs in development and test.
  4. Support for other data types: The structure section's class diagram shows a long data type used for IDs, yet this could be any data type your application requires. However, the UniqueID generator pattern would have to be extended to account for different ID data types in a single application. For instance, if your application mixed doubles, strings, longs, and ints as keys, the singleton would have to be extended.

Implementation
Consider the following issues when implementing a generic, portable UniqueID generator pattern:

  • Determining incrementBy for your application: The amount of IDs contained in each ID set (and subsequently cached in the JVM) should be determined based on the number of users attempting "insert" transactions per JVM. Thus, if your incrementBy is 50 on a single J2EE server, set it to approximately 25 if you cluster two servers. Also, set incrementBy to a low number, even 1, for development and testing. As with any tunable parameter, metrics gathered from stress testing your application should ultimately drive your settings.
  • Ensure portability across EJB servers: When communicating from the UniqueIDEJB to the database, don't use proprietary logic to obtain a connection from a connection pool. Use data sources looked up through JNDI instead.
  • Ensuring portability across databases: There are a few ways to ensure that your code to fetch a set of IDs is portable. One way is to store the SQL that will be executed in the EJB's environment. The SQL is set in the deployment descriptor, which allows it to be modified during deployment rather than having to modify the codebase. Another option is to use data access objects (DAOs) to contain the database-specific SQL code. Last, your UniqueIDEJB component couldn't take advantage of database-specific sequence generators. Your component's implementation should create the table at runtime if it doesn't exist already. This approach isn't recommended, but it's an alternative nonetheless.
  • Generating different IDs for different tables (classes): To generate a different ID for different tables, each class in the pattern would have to change its interface to take a "sequence" parameter, which indicates which class you want to get the next ID for and is forwarded throughout the pattern to the JDBC call against the database.
  • Generating IDs shouldn't rely on a business transaction outcome: The UniqueIDEJB should create its own new transaction when getting an ID set. Incrementing the database to the "next ID value" shouldn't rely on whether or not the business transaction currently executing in your application succeeds or fails.
  • Business transactions rely on generated ID success: An error fetching an ID set from the UniqueIDEJB will cause a business transaction to fail. Don't mix different approaches to generating unique IDs when one fails. For instance, let's say your application uses the System.currentTimeMillis() approach to key generation if the first approach, calling UniqueIDEJB, fails. This provides an extra layer of fault tolerance to your application, but you could encounter duplicate IDs! If your database counter is near the number generated by the System.currentTimeMillis(), you'll have problems.

Sample Code
The code in Listing 1 shows how to implement the singleton to cache the ID set, fetch a new set, and handle failures when calling the UniqueIDEJB.

Summary
This month I provided an EJB pattern to a common problem in the OLTP world, generating unique IDs. While there are variations of the pattern, the UniqueID generator overcomes many scalability and flexibility issues where other patterns fall short, such as local ID caching, limiting remote method invocations, and portability. I hope this pattern is helpful for your EJB engagement. For other EJB patterns see www.theServerSide.com. And let me know if you're interested in JDJ featuring more patterns in the future.

Several patterns exist for generating primary keys for your EJB application. This month I'll provide a pattern for generating PKs that's scalable, generic, and portable.

分享到:
评论

相关推荐

    解决 java.lang.RuntimeException: Could not generate DH keypair异常处理所需的bcprov的jar

    解决 java.lang.RuntimeException: Could not generate DH keypair异常处理。 bcprov-ext-jdk15on-1.60、bcprov-jdk15on-1.60两个包放到jre下的$JAVA_HOME/jre/lib/ext的路径下,然后配置$JAVA_HOME/jre/lib/...

    图像描述--Show and Tell: A Neural Image Caption Generator

    完整工程案例:图像描述---Show and Tell: A Neural Image Caption Generator,基于Inception V3与LSTM实现图像描述,运行环境(Tensorflow1.0及以上,Python3.6)

    password-generator:密码生成器:key:

    密码生成器 :key: 框架 Electron.js 想发展吗? 要求 Node.js从下载。 ...git clone ...cd password-generator 安装依赖项 npm install 运行应用 npm run start 执照 该应用程序已获得

    idgenerator:idgenerator是基于redis的id生成器

    idgenerator是基于redis的id生成器 dgenerator是基于redis的id生成器 安装 取得 go get github.com/lbfatcgf/idgenerator 快速开始 package main import ( "fmt" "net/http" "os" "os/signal" "syscall" ...

    unique-names-generator:生成唯一且令人难忘的名称字符串

    文件本文档适用于unique-names-generator v4。 如果您使用的是该库的3.x版本,请参阅有关版本1和版本2,请参阅迁移到v4 如果要从库的较旧版本迁移到v4,请阅读目录 先决条件此项目需要NodeJS(至少为版本6)和NPM。 ...

    generator-generator:生成一个Yeoman生成器

    发电机-发电机 Yeoman发电机产生Yeoman发电机入门安装: npm install -g generator-generator 运行: yo generator指令yo generator显示用于生成新发电机的向导yo generator:subgenerator 生成名称为的子yo ...

    route-generator:Laravel 4.2 路由和路由控制器生成器

    composer require "emsifa/route-generator:dev-master" --dev 在您的app/config/app.php ,将Emsifa\RouteGenerator\RouteGeneratorServiceProvider添加到数组providers 例子 生成简单路由 ...

    Nero 14 Key Generator

    A key generator for Nero 14.

    music-pattern-generator:Javascript MIDI音乐模式生成器

    Music Pattern Generator是一款用于创建音乐节奏的应用程序。 它发送MIDI数据,因此它本身不会发出任何声音。 为此,您需要将其连接到可以处理MIDI数据以产生声音的MIDI软件或硬件。 观看。 处理器 Music Pattern ...

    sap key generator1.0

    开发员想要修改SAP的object时(比如说SAP 程序)时,需要注册此Key,此key与SAP object相关。也就是说,对于一个object,你就需要一个key。看来我要进的这个Table是系统标准的程序中用的,所以系统要你输入这个key。

    id-generator:自用id生成器

    【id-generator:自用id生成器】 在软件开发中,唯一标识符(ID)的生成是至关重要的,尤其是在分布式系统中。`id-generator` 是一个专门为个人或团队自定义设计的ID生成器,它旨在为应用程序提供高效、唯一且可...

    idGenerator:使用golanggo的idGenerator

    #ID产生器 用go实现的id生成器,支持每秒qps:131072,超过需要等待下一秒 依赖 mysql(或zk,redis等) 需要使用mysql来保证多台机器获取到的workId不同当然,如果是单点,那随意设置workId 使用介绍 初始化程序 ...

    central pattern generator程序

    "Central Pattern Generator(CPG)程序"是一种模拟生物运动控制机制的数学模型,常用于机器人学、生物力学和神经科学的研究。在这个特定的程序中,它由7个CPG单元组成一个网络,能够产生周期性的振荡输出,适用于...

    Mavlink Generator : Mavlink消息生成工具

    该工具根据.xml文件生成mavlink消息的头文件。如果从github 克隆的Mavlink Generator在使用时,没有改过的文件也被更新(比如头文件里的注释),可以用这个代替,这个不会有上述问题

    api-key-generator:使用 Python 的简单 API 密钥生成器

    api-key-生成器使用 Python 的简单 API 密钥生成器开发环境操作系统:Windows 8.1 64 位工具: Python 2.7.9 MongoDB 3.0.2(从下载 64 位安装程序) pymongo ( pip install pymongo ) 参数解析吉特用法您可以将此...

    id-generator:整体唯一ID生成器

    id生成器 项目说明 实现请参考 将百度uid-generator组件封装成独立的springboot应用提供服务 使用方法 修改application.properties,配置好数据库 执行doc / init.sql初始化表 运行springboot项目 连接调用 1. 获取...

    java实现学生管理系统源码-Design_Pattern_Generator:Design_Pattern_Generator

    java实现学生管理系统源码作业 3 描述:IntelliJ 插件中名称冲突功能的面向对象设计和实现,使用来自作业 1 和 2 的设计模式代码生成器。 等级: ...存储库的经验,学习了许多设计模式,创建了模型和设计模式代码生成器...

    keras实现:图像描述---Show and Tell: A Neural Image Caption Generator

    完整工程:图像描述---Show and Tell: A Neural Image Caption Generator,使用keras实现图像描述,运行环境(keras==2.0.3,tensorflow==1.1.0,pandas==0.19.1,numpy==1.12.1,h5py==2.7.0,matplotlib==2.1.0,...

    Central Pattern Generator

    ### Central Pattern Generator (CPG)在仿生机器人中的应用与模拟 #### 摘要解析与核心概念 “中央模式生成器”(Central Pattern Generator,简称CPG)是一种神经网络模型,负责产生生物体运动所需的节奏性信号。...

Global site tag (gtag.js) - Google Analytics