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 + -
显示快捷键?