The database has self-growth fields, but the self-growth fields have their own limitations. Some databases do not support self-growth. In the development process, some customer businesses need to generate business process numbers, and simple numbers cannot meet their needs. Therefore, the idea of writing a serial number generator is generated.
1. First create a database table
Create Table sys_max_number (
Mn_id varchar (32) not null,
Mn_key_name varchar (64) not null,
Mn_key_value bigint not null default 0,
Mn_remark varchar (512) not null,
Constraint pk_sys_max_number primary key (mn_id ),
Constraint ak_unique_max_number_sys_max _ unique (mn_key_name)
)
Go
The meanings of each field are as follows: primary key of the database, key of the serial number, key value (0 by default), and description of the serial number key.
The Code is as follows:
Package com. SYS. maxnumber;
Import java. SQL. connection;
Import java. SQL. preparedstatement;
Import java. SQL. resultset;
Import java. SQL. sqlexception;
Import org. Apache. commons. Logging. log;
Import org. Apache. commons. Logging. logfactory;
Import com. Work. Core. DB. dbconnectionfactory;
/**
* @ Author wangmingjie
* @ Date 2009-8-4 09:59:15 AM
*/
Public class keyinfo {
Private Static log = logfactory. getlog (keyinfo. Class );
Private long keymax; // The maximum key value.
Private long keymin; // minimum key value
Private long nextkey; // The next key value
Private int poolsize; // cache size. Note that the number is too large to be wasted.
Private string keyname; // The application in which the primary key is used.
Public keyinfo (INT poolsize, string keyname ){
This. poolsize = poolsize;
This. keyname = keyname;
Retrievefromdb (5); // note that this class cannot be used directly; otherwise, a problem may occur in the case of multithreading.
// It must be called during initialization; otherwise, an error occurs! The purpose is to assign a value to nextkey first.
}
Public long getkeymax (){
Return keymax;
}
Public long getkeymin (){
Return keymin;
}
/**
* Obtain the key value of the Next string. If the length does not match, use zero to fill the front. <br>
* For example, if the parameter is four or intkey = 10, 0010 is returned.
* Note: The getnextintkey method is called here.
* 2,147,483,647,
* @ Param paddinglength
* String length. The maximum length is 10 characters. Because of the integer.
*
* @ Return if the parameter length is greater than the specified length, the actual length of the string is returned.
*/
Public String getnextstringkey (final int paddinglength ){
String S = long. tostring (getnextintkey ());
Int Len = S. Length ();
If (LEN <paddinglength ){
Stringbuffer Buf = new stringbuffer (paddinglength );
For (INT I = 0; I <paddinglength-len; I ++ ){
Buf. append ('0 ');
}
Buf. append (s );
S = Buf. tostring ();
}
Return S;
}
/**
* Obtain the key value of the next integer;
*
* @ Return
*/
Public synchronized int getnextintkey (){
If (nextkey> keymax ){
Retrievefromdb (5 );
}
Return (INT) (nextkey ++ );
}
/**
* Obtain the key value of the long integer.
* @ Return
*/
Public synchronized long getnextlongkey (){
If (nextkey> keymax ){
Retrievefromdb (5 );
}
Return nextkey ++;
}
Private void retrievefromdb (INT count ){
If (COUNT = 0 ){
If (log. iserrorenabled ())
Log. Error ("An error occurred while obtaining the serial number! Abandon acquiring ...");
Return;
}
Boolean success = false;
Long keyfromdb = 0;
String updatesql = "Update sys_max_number set mn_key_value = mn_key_value +"
+ Poolsize + "where mn_key_name =? ";
String selectsql = "select mn_key_value from sys_max_number where mn_key_name =? ";
Connection conn = NULL;
Preparedstatement pstupdate = NULL;
Preparedstatement pstselect = NULL;
Resultset rst = NULL;
Try {
// Conn = dbconnectionfactory. getjdbcconn ();
Conn = dbconnectionfactory. getconnection (); // obtain the database connection from the connection pool
Conn. setautocommit (false );
Pstupdate = conn. preparestatement (updatesql );
Pstupdate. setstring (1, keyname. Trim ());
Pstupdate.exe cuteupdate ();
Pstselect = conn. preparestatement (selectsql );
Pstselect. setstring (1, keyname. Trim ());
RST = pstselect.exe cutequery ();
While (RST. Next ()){
Keyfromdb = RST. getlong (1 );
}
Conn. Commit ();
Success = true;
} Catch (sqlexception e ){
Try {
Conn. rollback ();
} Catch (sqlexception E1 ){
E1.printstacktrace ();
}
E. printstacktrace ();
If (log. iswarnenabled ())
Log. Warn ("failed to get the serial number! ", E );
} Finally {
Try {
If (RST! = NULL)
RST. Close ();
} Catch (sqlexception e ){
}
Try {
If (pstupdate! = NULL)
Pstupdate. Close ();
} Catch (sqlexception e ){
}
Try {
If (pstselect! = NULL)
Pstselect. Close ();
} Catch (sqlexception e ){
}
Try {
If (Conn! = NULL)
Conn. Close ();
} Catch (sqlexception e ){
}
}
Keymax = keyfromdb;
Keymin = keyfromdb-poolsize + 1;
Nextkey = keymin;
If (! Success ){
If (log. iswarnenabled ())
Log. Warn ("Warning, failed to get the next serial number due to thread contention. Perform the next attempt ...");
// Call this method again, but sleep briefly to try to avoid thread contention.
Try {
Thread. Sleep (75 );
} Catch (interruptedexception IE ){
}
Retrievefromdb (count-1 );
}
}
}
==============================================
Package com. SYS. maxnumber;
Import java. util. hashmap;
//
// Import org. Apache. commons. Logging. log;
// Import org. Apache. commons. Logging. logfactory;
/**
* @ Author wangmingjie
* @ Date 2009-8-4 10:33:19 AM
*/
Public class keygenerator {
// Private Static log = logfactory. getlog (keygenerator. Class );
Private Static hashmap <string, keygenerator> kengens = new hashmap <string, keygenerator> (
10 );
/* The minimum value is 1, because the default value in the database is 0, and the generated sequence value is at least 1 */
Private Static final int pool_size = 1;
Private keyinfo;
/**
* Constructor.
* @ Param poolsize obtain several values each time and place them in the cache. If the value is smaller than 1, the default value is 1. <Br>
* The recommended value is 2, which means a maximum of one number is wasted each time the application is restarted, and the efficiency can be doubled. <Br>
* If the value of 1 is used, the probability of waste is the lowest. But it cannot be used in highly concurrent systems.
* @ Param keyname corresponds to the key of the maximum good table.
*/
Private keygenerator (INT poolsize, string keyname ){
If (poolsize <1 ){
Poolsize = pool_size;
}
Keyinfo = new keyinfo (poolsize, keyname );
}
/**
* Ensure thread security.
* @ Param poolsize cache size
* @ Param keyname primary key name
* @ Return
*/
Public static synchronized keygenerator getinstance (INT poolsize, string keyname ){
Keygenerator keygen;
If (kengens. containskey (keyname )){
Keygen = kengens. Get (keyname );
// System. Out. println ("Get from cache" + keyname );
} Else {
Keygen = new keygenerator (poolsize, keyname );
Kengens. Put (keyname, keygen); // register it in hashmap. Improve Efficiency
// System. Out. println ("registered" + keyname );
}
Return keygen;
}
/**
* Get the Sequence Value of the int type
* @ Return
*/
Public int getnextintkey (){
Return keyinfo. getnextintkey ();
}
/**
* Obtain the Sequence Value of the long type. It is generally not used. Unless it is like mobile China Unicom, there are hundreds of millions of calls every day.
* @ Return
*/
Public long getnextlongkey (){
Return keyinfo. getnextlongkey ();
}
/**
* Obtain the Sequence Value of the string type.
* @ Param paddinglength: returns the length of a string. The maximum length is 10 characters. If long is used, it can be up to 19 digits.
* @ Return
*/
Public String getnextstringkey (INT paddinglength ){
Return keyinfo. getnextstringkey (paddinglength );
}
}
= ====
Package com. SYS. maxnumber;
/**
* During the test, modify the retrievefromdb method of keyinfo so that it can be connected through JDBC.
* Note that the keyname must exist in the largest table!
* @ Author wangmingjie
* @ Date 2009-8-4 10:38:19 AM
*/
Public class keyclient {
// General usage, keygenerator. getinstance (1, "bugproject"). getnextintkey ();
// Increase the value of poolsize when the number of concurrent operations is large, which can reduce the number of database accesses.
/**
* Usage
*
* @ Param ARGs
*/
Public static void main (string [] ARGs ){
// Keygenerator keygen = keygenerator. getinstance (1, "bugproject ");
//
// For (INT I = 0; I <25; I ++ ){
// System. Out. println ("Key (" + (I + 1) + ") =" + keygen. getnextintkey ());
//}
//
// For (INT I = 0; I <25; I ++ ){
// System. Out. println ("Key (" + (I + 1) + ") =" + keygen. getnextstringkey (6 ));
//}
Threada T = new threada ();
Thread T1 = new thread (T, "");
Thread t2 = new thread (T, "B ");
Thread T3 = new thread (T, "C ");
Thread t4 = new thread (T, "D ");
T1.start ();
T2.start ();
T3.start ();
T4.start ();
// When there are too many accesses, a transaction deadlock occurs. Therefore, the number of caches must be increased in High-concurrency systems.
// Java. SQL. sqlexception: the transaction (process ID 143) and another process have been deadlocked on the lock resource, and the transaction has been selected as a deadlock victim. Run the transaction again.
// Bkey A (12) = 000137
// Threada TA = new threada ();
// Ta. Run ();
// Threadb TB = new threadb ();
// TB. Run ();
}
}
Class threada implements runnable {
Public void run (){
Keygenerator keygen = keygenerator. getinstance (1, "bugproject ");
For (INT I = 0; I <500; I ++ ){
System. Out. println (thread. currentthread (). getname () + "Key A (" + (I + 1) + ") ="
+ Keygen. getnextintkey () + "|"
+ Keygen. getnextintkey ()
+ "|"
+ Keygen. getnextstringkey (4 ));
}
}
}
Class threadb implements runnable {
Public void run (){
Keygenerator keygen = keygenerator. getinstance (1, "bugproject ");
For (INT I = 0; I <500; I ++ ){
System. out. println (thread. currentthread (). getname () + "Key B (" + (I + 1) + ") =" + keygen. getnextstringkey (6 ));
}
}
}
================ Pojo ============================
Package com. SYS. model;
Import java. Io. serializable;
/**
*
*/
Public class maxnumber implements serializable {
// Constructors
Public maxnumber (){
}
/**
* Constructor for primary key
*/
Public maxnumber (string ID ){
This. setid (ID );
}
// Primary key
Private string ID; // ID
Public java. Lang. String GETID (){
Return ID;
}
Public void setid (string ID ){
This. ID = ID;
}
Private string keyname; // primary key
Private integer keyValue; // Value
Private string remark; // remarks
Public String getkeyname (){
If (keyname = NULL) return NULL;
Else return keyname. Trim ();
}
Public void setkeyname (string keyname ){
This. keyname = keyname;
}
Public integer getkeyvalue (){
Return keyValue;
}
Public void setkeyvalue (integer keyValue ){
This. keyValue = keyValue;
}
Public String getremark (){
If (Remark = NULL) return NULL;
Else return remark. Trim ();
}
Public void setremark (string remark ){
This. remark = remark;
}
/* (Non-javadoc)
* @ See java. Lang. Object # hashcode ()
*/
@ Override
Public int hashcode (){
Final int prime = 31;
Int result = super. hashcode ();
Result = prime * result + (ID = NULL )? 0: Id. hashcode ());
Return result;
}
/* (Non-javadoc)
* @ See java. Lang. Object # equals (Java. Lang. Object)
*/
@ Override
Public Boolean equals (Object OBJ ){
If (this = OBJ)
Return true;
If (! Super. Equals (OBJ ))
Return false;
If (getclass ()! = Obj. getclass ())
Return false;
Final maxnumber Other = (maxnumber) OBJ;
If (ID = NULL ){
If (other. ID! = NULL)
Return false;
} Else if (! Id. Equals (other. ID ))
Return false;
Return true;
}
Public String tostring (){
Stringbuffer sb = new stringbuffer ("");
SB. append ("maxnumber {id ="); sb. append (ID); sb. append (",");
SB. append ("keyname ="); sb. append (keyname); sb. append (",");
SB. append ("keyValue ="); sb. append (keyValue); sb. append (",");
SB. append ("remark ="); sb. append (remark );
SB. append ("}");
Return sb. tostring ();
}
}