让系统管理数据库序列生成(系统生成代理主键)

1.我们知道oracle 中有sequence做代理主键(自动增长)数据库实现 每次调用INSERT 都需要
BIZASSISTANT.OFSMSLOG_SEQ.NEXTVAL 这样的调用。数据库一旦更换OFSMSLOG_SEQ没有及时同步过去或者重新生成的序列和原有数据ID主键冲突等问题会发生。
先将sequence 生成让代码实现,这样代码移植后就不会出现上面问题了

代码如下
SequenceManager.java
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/***********************************************************************
*
* SequenceManager.java
* @copyright Copyright: 2009-2012
* @creator 周辉<br/>
* @create-time Jul 16, 2009 11:12:09 AM
* @revision $Id: *
***********************************************************************/
public class SequenceManager {
private static final String CREATE_ID =
"INSERT INTO ofID (id, idType) VALUES (1, ?)";

private static final String LOAD_ID =
"SELECT id FROM ofID WHERE idType=?";

private static final String UPDATE_ID =
"UPDATE ofID SET id=? WHERE idType=? AND id=?";

// Statically startup a sequence manager for each of the sequence counters.
private static Map<Integer, SequenceManager> managers = new ConcurrentHashMap<Integer, SequenceManager>();



/**
* Returns the next ID of the specified type.
*
* @param type the type of unique ID.
* @return the next unique ID of the specified type.
*/
public static long nextID(int type) {
if (managers.containsKey(type)) {
return managers.get(type).nextUniqueID();
}
else {
// Verify type is valid from the db, if so create an instance for the type
// And return the next unique id
SequenceManager manager = new SequenceManager(type, 1);
return manager.nextUniqueID();
}
}



/**
* Used to set the blocksize of a given SequenceManager. If no SequenceManager has
* been registered for the type, the type is verified as valid and then a new
* sequence manager is created.
*
* @param type the type of unique id.
* @param blockSize how many blocks of ids we should.
*/
public static void setBlockSize(int type, int blockSize) {
if (managers.containsKey(type)) {
managers.get(type).blockSize = blockSize;
}
else {
new SequenceManager(type, blockSize);
}
}

private int type;
private long currentID;
private long maxID;
private int blockSize;

/**
* Creates a new DbSequenceManager.
*
* @param seqType the type of sequence.
* @param size the number of id's to "checkout" at a time.
*/
public SequenceManager(int seqType, int size) {
managers.put(seqType, this);
this.type = seqType;
this.blockSize = size;
currentID = 0l;
maxID = 0l;
}

/**
* Returns the next available unique ID. Essentially this provides for the functionality of an
* auto-increment database field.
*/
public synchronized long nextUniqueID() {
if (!(currentID < maxID)) {
// Get next block -- make 5 attempts at maximum.
getNextBlock(5);
}
long id = currentID;
currentID++;
return id;
}

/**
* Performs a lookup to get the next available ID block. The algorithm is as follows:
* <ol>
* <li> Select currentID from appropriate db row.
* <li> Increment id returned from db.
* <li> Update db row with new id where id=old_id.
* <li> If update fails another process checked out the block first; go back to step 1.
* Otherwise, done.
* </ol>
*/
private void getNextBlock(int count) {
if (count == 0) {
return;
}

Connection con = null;
PreparedStatement pstmt = null;
boolean abortTransaction = false;
boolean success = false;

try {
con = DbConnectionManager.getTransactionConnection();
// Get the current ID from the database.
pstmt = con.prepareStatement(LOAD_ID);
pstmt.setInt(1, type);
ResultSet rs = pstmt.executeQuery();

long currentID = 1;
if (!rs.next()) {
rs.close();
pstmt.close();

createNewID(con, type);
}
else {
currentID = rs.getLong(1);
rs.close();
pstmt.close();
}

// Increment the id to define our block.
long newID = currentID + blockSize;
// The WHERE clause includes the last value of the id. This ensures
// that an update will occur only if nobody else has performed an
// update first.
pstmt = con.prepareStatement(UPDATE_ID);
pstmt.setLong(1, newID);
pstmt.setInt(2, type);
pstmt.setLong(3, currentID);
// Check to see if the row was affected. If not, some other process
// already changed the original id that we read. Therefore, this
// round failed and we'll have to try again.
success = pstmt.executeUpdate() == 1;
if (success) {
this.currentID = currentID;
this.maxID = newID;
}
}
catch (SQLException e) {
abortTransaction = true;
}
finally {
try {
if (pstmt != null) {
pstmt.close();
}
}
catch (Exception e) {
}
DbConnectionManager.closeTransactionConnection(con, abortTransaction);
}

if (!success) {
// Call this method again, but sleep briefly to try to avoid thread contention.
try {
Thread.sleep(75);
}
catch (InterruptedException ie) {
// Ignore.
}
getNextBlock(count - 1);
}
}

private void createNewID(Connection con, int type) throws SQLException {

// create new ID row
PreparedStatement pstmt = null;

try {
pstmt = con.prepareStatement(CREATE_ID);
pstmt.setInt(1, type);
pstmt.execute();
}
finally {
DbConnectionManager.closeStatement(pstmt);
}
}
}


其中DbConnectionManager是一个数据库连接的代码,这里就不贴上了
主要是介绍具体代码的实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值