sequencemanager.java
来自「Jive是基于JSP/JAVA技术构架的一个大型BBS论坛系统,这是Jive论坛」· Java 代码 · 共 188 行
JAVA
188 行
/** * $RCSfile: SequenceManager.java,v $ * $Revision: 1.3 $ * $Date: 2002/03/25 17:24:55 $ * * Copyright (C) 1999-2002 CoolServlets, Inc. All rights reserved. * * This software is the proprietary information of CoolServlets, Inc. * Use is subject to license terms. */package com.jivesoftware.forum.database;import java.sql.*;import com.jivesoftware.forum.*;/** * Manages sequences of unique ID's that get stored in the database. Database * support for sequences varies widely; some don't use them at all. Instead, * we handle unique ID generation with a combination VM/database solution.<p> * * A special table in the database doles out blocks of unique ID's to each * virtual machine that interacts with Jive. This has the following consequences: * <ul> * <li>There is no need to go to the database every time we want a new unique * id. * <li>Multiple app servers can interact with the same db without id collision. * <li>The order of unique id's may not correspond to the creation date of * objects. * <li>There can be gaps in ID's after server restarts since blocks will * get "lost" if the block size is greater than 1. * </ul><p> * * Each sequence type that this class manages has a different block size value. * Objects that aren't created often have a block size of 1, while frequently * created objects such as threads and messages have larger block sizes. * * @author Matt Tucker */public class SequenceManager { private static final String LOAD_ID = "SELECT id FROM jiveID WHERE idType=?"; private static final String UPDATE_ID = "UPDATE jiveID SET id=? WHERE idType=? AND id=?"; // Statically startup a sequence manager for each of the sequence counters. private static SequenceManager[] managers; static { managers = new SequenceManager[7]; managers[0] = new SequenceManager(JiveGlobals.FORUM, 1); managers[1] = new SequenceManager(JiveGlobals.THREAD, 10); managers[2] = new SequenceManager(JiveGlobals.MESSAGE, 15); managers[3] = new SequenceManager(JiveGlobals.USER, 1); managers[4] = new SequenceManager(JiveGlobals.GROUP, 1); managers[5] = new SequenceManager(JiveGlobals.ATTACHMENT, 3); managers[6] = new SequenceManager(JiveGlobals.FORUM_CATEGORY, 1); } /** * 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) { switch (type) { case JiveGlobals.FORUM: return managers[0].nextUniqueID(); case JiveGlobals.THREAD: return managers[1].nextUniqueID(); case JiveGlobals.MESSAGE: return managers[2].nextUniqueID(); case JiveGlobals.USER: return managers[3].nextUniqueID(); case JiveGlobals.GROUP: return managers[4].nextUniqueID(); case JiveGlobals.ATTACHMENT: return managers[5].nextUniqueID(); case JiveGlobals.FORUM_CATEGORY: return managers[6].nextUniqueID(); default: throw new IllegalArgumentException("Invalid type"); } } private int type; private long currentID; private long maxID; private int blockSize; /** * Creates a new DbSequenceManager. * * @param type the type of sequence. * @param blockSize the number of id's to "checkout" at a time. */ public SequenceManager(int type, int blockSize) { this.type = type; this.blockSize = blockSize; 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 availabe 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) { System.err.println("Failed at last attempt to obtain an ID, aborting..."); return; } boolean success = false; Connection con = null; PreparedStatement pstmt = null; try { con = ConnectionManager.getConnection(); // Get the current ID from the database. pstmt = con.prepareStatement(LOAD_ID); pstmt.setInt(1, type); ResultSet rs = pstmt.executeQuery(); if (!rs.next()) { throw new SQLException("Loading the current ID failed. The " + "jiveID table may not be correctly populated."); } long currentID = rs.getLong(1); 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( Exception sqle ) { sqle.printStackTrace(); } finally { try { pstmt.close(); } catch (Exception e) { e.printStackTrace(); } try { con.close(); } catch (Exception e) { e.printStackTrace(); } } if (!success) { System.err.println("WARNING: failed to obtain next ID block due to " + "thread contention. Trying again..."); // Call this method again, but sleep briefly to try to avoid thread // contention. try { Thread.currentThread().sleep(75); } catch (InterruptedException ie) { } getNextBlock(count-1); } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?