2010-02-15 25 views
8

Estoy buscando una buena forma de generar una ID de orden única. ¿Puedes ver algún problema con el código a continuación?¿Cómo se genera un número de pedido único?

int customerId = 10000000; 

long ticks = DateTime.UtcNow.Ticks; 

long orderId = customerId + ticks; 

int orderNumber = orderId.GetHashCode(); 

Voy a verificar que el número sea único en la base de datos antes de crear el pedido.

+2

puramente teórica, los hashes pueden colisionar. –

+0

Seguramente no es lo único que está buscando, solo el siguiente número secuencial ... Estoy de acuerdo con la gente a continuación que habla sobre el uso de una columna de identidad. – Paddy

+3

@Developer Art: nada teórico al respecto. Hashes colisionan * todo el tiempo *. Solo hay unos cuatro mil millones disponibles, por lo que chocarán. –

Respuesta

7

¿Qué tal tener un campo IDENTIDAD en la base de datos lo hace por usted?

También tendrá la ventaja de que los números de orden eliminados/cancelados no serán reutilizados (lo cual es bueno o incluso puede ser necesario para la contabilidad).

0

SI está usando SQL Server, realmente debería buscar la especificación IDENTITY. Te permite hacer esto con facilidad y velocidad.

Su solución no es única porque las cosas pueden suceder tan rápido en el sistema que dos procesos, que se ejecutan en secuencia o al mismo tiempo, pueden obtener el mismo valor de tic.

+0

la identificación del cliente variará para cada orden. Creo que combinar el ID del cliente con los ticks debería producir el valor único que estoy buscando. –

24

Si está almacenando sus registros en una base de datos, realmente debe buscar en las capacidades disponibles allí para generar claves únicas de sustitución. En SQLServer esto sería un campo IDENTITY y en Oracle sería un campo que usa un SEQUENCE para generar un nuevo valor.

Si hay una razón de peso por la que no puede utilizar su base de datos para generar una clave única, usted debe buscar en algo así como un Guid - que tiene una probabilidad mucher más alta que la manipulación de fecha y hora para generar un valor único . Las guías se pueden convertir trivialmente en cadenas, por lo que su identificador sería una cadena en este caso.

Lo que está haciendo con hashes no es una buena idea - nada garantiza que los hashes serán únicos, y en muchos casos sí colisionan. Guides: no ofrecen una garantía del 100% de exclusividad en las máquinas, pero en una sola máquina siempre deben ser únicas. E incluso en todas las máquinas, sus posibilidades de colisión son extremadamente remotas. Además, usar el tiempo de la máquina como una forma de acumular el valor subyacente está sujeto a las condiciones de carrera (como las que Eric describe).

Las guías son valores de 128 bits, por lo que no puede representarlos como un simple int o long. Te solicitará que uses string como tus ID, lo que puede o no ser posible en tu caso, dependiendo de otras consideraciones (como si controlas o no el modelo de datos). Si puede usarlos, utilizando un GUID es muy fácil:

string customerId = Guid.NewGuid().ToString(); // fetch new guid and save as string 
string orderNumber = Guid.NewGuid().ToString(); // same story here... 

Si realmente debe utilizar un identificador numérico, y que está dispuesto a abandonar fácilmente escalar su aplicación a través de múltiples servidores, se puede utilizar un incremento automático número global para suministrar una clave única. Tendría que inicializar este número con el siguiente valor disponible (máximo + 1) de su base de datos cuando se inicia la aplicación. También debería proteger este valor del uso simultáneo de múltiples hilos.Me gustaría concluir esta responsabilidad en una clase:

class static UniqueIDGenerator 
{ 
    // reads Max+1 from DB on startup 
    private static long m_NextID = InitializeFromDatabase(); 

    public static long GetNextID() { return Interlocked.Increment(ref m_NextID); } 
} 


EDIT:En este día y edad, razones de peso para la generación de identificadores únicos en su capa de aplicación en lugar de en la base de datos son muy poco frecuentes . Realmente debería usar las capacidades que proporciona la base de datos.

+4

+1 - Muy buena respuesta. – JasCav

0

Utilizaría la columna IDENTIDAD y, si no es así, usar System.Guid.NewGuid() para generar un GUID para usted.

14

Supongamos que tiene dos identificadores de clientes que difieren en 100, y ambos hacen un pedido que está a 100 unidades de tiempo. Su singularidad acaba de salir por la ventana.

Dice que va a comprobar la singularidad de la base de datos; no dices lo que vas a hacer si hay una colisión. Tampoco dices lo que vas a hacer con respecto a las condiciones de carrera; supongamos que se crean dos id. de orden colisionante al mismo tiempo, ninguno de los dos está en la base de datos. Usted pregunta a la base de datos en dos hilos diferentes si el artículo es único; es. A continuación, ingresa ambos y se ha violado la exclusividad aunque se haya realizado el control.

Esta es una forma muy, muy mala de obtener la singularidad. Lo que sería mejor es mover esto a la capa de la base de datos. Puede mantener un contador de órdenes globalmente seguro y asignar cada pedido nuevo al siguiente número de orden más alto.

Por cierto, durante muchos años he formulado una pregunta sobre esta pregunta como una entrevista técnica. He notado una fuerte correlación entre el conjunto de personas que intentan utilizar el tiempo como fuente de exclusividad y el conjunto de personas que no son contratadas. El tiempo es terrible fuente de singularidad; muchas cosas diferentes pueden suceder al mismo tiempo.

Lo que es aún peor es el uso de números aleatorios. Los números aleatorios son una fuente de singularidad aún peor que las marcas de tiempo. Supongamos que tiene un generador de números verdaderamente aleatorio que genera enteros aleatorios de 32 bits para los ID de los pedidos. ¿Cuántas órdenes necesita tener antes de que las probabilidades superen el cincuenta por ciento de que haya generado dos órdenes con la misma identificación? La respuesta sorprende a mucha gente: solo hay 77 mil antes de que haya un 50% de probabilidad de que hayas generado dos órdenes con el mismo número (y solo 9300 hasta que haya un 1% de probabilidad).

Recuerda: qué lo que buscas es una garantía de singularidad. No es un probable singularidad, sino una garantía de hierro que un número de orden se refiere a exactamente un pedido. Si eso es lo que necesita, entonces asegúrese de implementarlo.

0
+1

Si está sugiriendo que la ID del pedido se genere de forma aleatoria utilizando la aleatoriedad real, esta es una * idea peligrosamente terrible *.¡Las probabilidades de obtener una colisión entre dos números de 32 bits verdaderamente aleatorios aumentan a> 50% después de solo 77000 intentos! –

+0

@Eric: Tiene razón, no estoy sugiriendo que se genere un número de ID de pedido aleatoriamente, solo que la generación de un número debe ser informada de los riesgos de tales operaciones, como ha señalado. La teoría de números aleatorios es un buen lugar para encontrar estas trampas, por lo que pueden evitarse. –

Cuestiones relacionadas