明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

一個(gè)用java完成的數(shù)據(jù)庫序列生成器

[摘要]如果是集群等應(yīng)用這個(gè)就不行了,只能在單應(yīng)用的情況下使用對(duì)于每個(gè)序列鍵只需在第一次使用時(shí)查詢數(shù)據(jù)庫,后面的都將不需要查詢有非常詳細(xì)的注釋,我就不多說了package org.shaoye.common...
如果是集群等應(yīng)用這個(gè)就不行了,只能在單應(yīng)用的情況下使用
對(duì)于每個(gè)序列鍵只需在第一次使用時(shí)查詢數(shù)據(jù)庫,后面的都將不需要查詢
有非常詳細(xì)的注釋,我就不多說了


package org.shaoye.common.sql;

import java.util.HashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
* 類<code>Key</code>是一個(gè)數(shù)據(jù)庫主鍵生成器,用序列號(hào)的方式來產(chǎn)生數(shù)據(jù)庫中需要的主鍵值。
* <p>
* <code>Key</code>目前支持的數(shù)據(jù)庫包括Oracle的所有版本、MySql的3.x以上的版本
* 以及所有支持max()函數(shù)的數(shù)據(jù)庫,支持字段類型僅為數(shù)字類型的主鍵,對(duì)于字符及其它類型的主鍵尚不提供支持。
* <p>
* 在使用時(shí)只需提供表名、字段名(主鍵)以及到數(shù)據(jù)庫的JDBC連接,如果想要獲得message表的id字段的下一個(gè)
* 主鍵值時(shí):
* <p><blockquote><pre>
* java.sql.Connection conn = ...;
* org.shaoye.common.sql.Key key = org.shaoye.common.sql.Key.getInstance();
* int keyValue = key.getNextKey("message", "id", conn);
* String sql = "insert into message (id,...) values (" + keyValue + ",...)";
* //執(zhí)行插入操作...
* </pre></blockquote><p>
*
* @author 令少爺(shaoye@vip.sina.com)
* @since magic 0.1
*/
public final class Key {

/**
* key的最大值,默認(rèn)為9223372036854775807,即long類型的最大值
*/
private long max = 9223372036854775807L;

/**
* key的最小值,默認(rèn)為1
* */
private long min = 1L;

/**
* Key的唯一實(shí)例,通過getInstance()方法獲得
* */
private static Key keygen = new Key();

/**
* KeyInfo類的實(shí)例列表,默認(rèn)容量為5個(gè)
* */
private HashMap keyList = new HashMap(5); //keyInfo 列表

/**
* 私有的默認(rèn)構(gòu)造方法,防止外部構(gòu)造類的實(shí)例
* */
private Key() {
}

/**
* 獲得Key的唯一實(shí)例
* */
public static Key getInstance() {
return keygen;
}

/**
* 用指定的表和字段獲得key的下一個(gè)值,主鍵的值不得超過2147483647
* @param tableName 數(shù)據(jù)庫中的表名,表中必須有一個(gè)數(shù)字主鍵
* @param keyName 表(tableName)中的字段名
* @param connJDBC連接,如果欲獲得的key是第一次取值,則必須保證conn能連接到數(shù)據(jù)庫
* @return key的下一個(gè)主鍵的int值
* @throws <code>KeyException</code>如果表名或字段名不存在、訪問數(shù)據(jù)庫錯(cuò)誤或key的值大于2147483647時(shí)拋出
*/
public int getNextKey(String tableName, String keyName, Connection conn) throws KeyException {
long value = getNextKeyLong(tableName, keyName, conn);
if (value > 2147483647L) {
 throw new KeyException("Key's value too big,please call getNextKeyLong method!");
}
return (new Long(value)).intValue();
}

/**
* 用指定的表和字段獲得key的下一個(gè)值,最大為9223372036854775807
* @param tableName 數(shù)據(jù)庫中的表名,表中必須有一個(gè)數(shù)字主鍵
* @param keyName 表(tableName)中的字段名
* @param connJDBC連接,如果欲獲得的key是第一次取值,則必須保證conn能連接到數(shù)據(jù)庫
* @return key的下一個(gè)主鍵的long值
* @throws <code>KeyException</code>如果表名或字段名不存在或訪問數(shù)據(jù)庫錯(cuò)誤時(shí)拋出
*/
public long getNextKeyLong(String tableName, String keyName, Connection conn)
throws KeyException {
KeyInfo keyinfo;
String item = tableName + "." + keyName;
try {
 if (keyList.containsKey(item)) {
keyinfo = (KeyInfo) keyList.get(item);
 }
 else {
keyinfo = new KeyInfo(tableName, keyName, conn);
keyList.put(item, keyinfo);
 }
 return keyinfo.getNextKey();
}
catch (SQLException sqle) {
 throw new KeyException(sqle);
}
}

/**
* 用指定的"表<code>.</code>字段"形式的字符串獲得key的下一個(gè)值,主鍵的值不得超過2147483647
* @param tableDotField"表.字段"形式的字符串,如:message.id
* @param connJDBC連接,如果欲獲得的key是第一次取值,則必須保證conn能連接到數(shù)據(jù)庫
* @return key的下一個(gè)主鍵的int值
* @throws <code>KeyException</code>如果表名或字段名不存在、訪問數(shù)據(jù)庫錯(cuò)誤或key的值
* 大于2147483647時(shí)拋出
*/
public int getNextKey(String tableDotField, Connection conn) throws KeyException {
long value = getNextKeyLong(tableDotField, conn);
if (value > 2147483647L) {
 throw new KeyException("Key's value too big,please call getNextKeyLong method!");
}
return (new Long(value)).intValue();
}

/**
* 用指定的"表<code>.</code>字段"形式的字符串獲得key的下一個(gè)值,最大為9223372036854775807
* @param tableDotField"表.字段"形式的字符串,如:message.id
* @param connJDBC連接,如果欲獲得的key是第一次取值,則必須保證conn能連接到數(shù)據(jù)庫
* @return key的下一個(gè)主鍵的int值
* @throws <code>KeyException</code>如果表名或字段名不存在或訪問數(shù)據(jù)庫錯(cuò)誤時(shí)拋出
*/
public long getNextKeyLong(String tableDotField, Connection conn) throws KeyException {
int dot_index = tableDotField.indexOf(".");
if (tableDotField.indexOf(".") < 1) {
 throw new KeyException("Unknown Key '" + tableDotField + "'!");
}
String tab = tableDotField.substring(0, dot_index);
String key = tableDotField.substring(dot_index);
return getNextKeyLong(tab, key, conn);
}

/**
* 用指定的表和字段獲得key的當(dāng)前值,主鍵的值不得超過2147483647
* @param tableName 數(shù)據(jù)庫中的表名,表中必須有一個(gè)數(shù)字主鍵
* @param keyName 表(tableName)中的字段名
* @param connJDBC連接,如果欲獲得的key是第一次取值,則必須保證conn能連接到數(shù)據(jù)庫
* @return key的當(dāng)前int值
* @throws <code>KeyException</code>如果表名或字段名不存在、訪問數(shù)據(jù)庫錯(cuò)誤或key的值大于2147483647時(shí)拋出
*/
public int getCurrentKey(String tableName, String keyName, Connection conn)
throws KeyException {
long value = getCurrentKeyLong(tableName, keyName, conn);
if (value > 2147483647L) {
 throw new KeyException("Key's value too big,please call getCurrentKeyLong method!");
}
return (new Long(value)).intValue();
}

/**
* 用指定的表和字段獲得key的當(dāng)前值,最大為9223372036854775807
* @param tableName 數(shù)據(jù)庫中的表名,表中必須有一個(gè)數(shù)字主鍵
* @param keyName 表(tableName)中的字段名
* @param connJDBC連接,如果欲獲得的key是第一次取值,則必須保證conn能連接到數(shù)據(jù)庫
* @return key的當(dāng)前l(fā)ong值
* @throws <code>KeyException</code>如果表名或字段名不存在或訪問數(shù)據(jù)庫錯(cuò)誤時(shí)拋出
*/
public long getCurrentKeyLong(String tableName, String keyName, Connection conn)
throws KeyException {
KeyInfo keyinfo;
String item = tableName + "." + keyName;
try {
 synchronized (keyList) {
if (keyList.containsKey(item)) {
 keyinfo = (KeyInfo) keyList.get(item);
}
else {
 keyinfo = new KeyInfo(tableName, keyName, conn);
 keyList.put(item, keyinfo);
}
 }
 return keyinfo.getCurrentKey();
}
catch (SQLException sqle) {
 throw new KeyException(sqle);
}
}

/**
* 用指定的"表<code>.</code>字段"形式的字符串獲得key的當(dāng)前值,主鍵的值不得超過2147483647
* @param tableDotField"表.字段"形式的字符串,如:message.id
* @param connJDBC連接,如果欲獲得的key是第一次取值,則必須保證conn能連接到數(shù)據(jù)庫
* @return key的當(dāng)前int值
* @throws <code>KeyException</code>如果表名或字段名不存在、訪問數(shù)據(jù)庫錯(cuò)誤或key的值
* 大于2147483647時(shí)拋出
*/
public int getCurrentKey(String tableDotField, Connection conn) throws KeyException {
long value = getCurrentKeyLong(tableDotField, conn);
if (value > 2147483647L) {
 throw new KeyException("Key's value too big,please call getNextKeyLong method!");
}
return (new Long(value)).intValue();
}

/**
* 用指定的"表<code>.</code>字段"形式的字符串獲得key的當(dāng)前值,最大為9223372036854775807
* @param tableDotField"表.字段"形式的字符串,如:message.id
* @param connJDBC連接,如果欲獲得的key是第一次取值,則必須保證conn能連接到數(shù)據(jù)庫
* @return key的當(dāng)前int值
* @throws <code>KeyException</code>如果表名或字段名不存在或訪問數(shù)據(jù)庫錯(cuò)誤時(shí)拋出
*/
public long getCurrentKeyLong(String tableDotField, Connection conn) throws KeyException {
int dot_index = tableDotField.indexOf(".");
if (tableDotField.indexOf(".") < 1) {
 throw new KeyException("Unknown Key '" + tableDotField + "'!");
}
String tab = tableDotField.substring(0, dot_index);
String key = tableDotField.substring(dot_index);
return getCurrentKeyLong(tab, key, conn);
}
}


/**
* 內(nèi)部類,用來存儲(chǔ)主鍵信息
* */
class KeyInfo {
private long max = 9223372036854775807L;
private long min = 1L;
private long nextKey;
private String tableName;
private String keyName;
private Connection conn = null;
/**
* keyInfo 對(duì)象初始化
*/
KeyInfo(String tableName, String keyName, Connection _conn) throws SQLException {
this.tableName = tableName;
this.keyName = keyName;
this.conn = _conn;
retrieveFromDB();
}
int getMax() {
return (new Long(max)).intValue();
}
long getMaxLong() {
return max;
}
int getMin() {
return (new Long(min)).intValue();
}
long getMinLong() {
return min;
}
/**
* 取下一鍵值
*/
int getNextKey() {
return (new Long(getNextKeyLong())).intValue();
}
/**
* 取下一鍵值
*/
synchronized long getNextKeyLong() {
nextKey++;
return nextKey;
}
/**
* 取當(dāng)前鍵值
*/
synchronized int getCurrentKey() {
return (new Long(nextKey)).intValue();
}
/**
* 取當(dāng)前鍵值
*/
synchronized long getCurrentKeyLong() {
return nextKey;
}
/**
* 從數(shù)據(jù)庫中取當(dāng)前最大值
*/
void retrieveFromDB() throws SQLException {
PreparedStatement pstmt = null;
ResultSet rs = null;
int keyFromDB = 0;
String sql = "select max(" + keyName + ") from " + tableName;
try {
 pstmt = conn.prepareStatement(sql);
}
catch (Exception ex) {
 throw new KeyException("Can't connect DataBase!");
}
try {
 rs = pstmt.executeQuery();
}
catch (SQLException sqle) {
 if (pstmt != null)
pstmt.close();
 throw new KeyException(
"'" + keyName + "' or '" + tableName + "' isn't exist in DataBase!",
sqle);
}
try {
 if (rs.next()) {
nextKey = rs.getLong(1);
if (nextKey < min) {
 nextKey = min;
}
 }
 else {
nextKey = min;
 }
}
catch (SQLException sqle) {
 throw (sqle);
}
finally {
 if (rs != null)
rs.close();
 if (pstmt != null)
pstmt.close();
}
}
}