⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sequenceutil.java

📁 Sequoia ERP是一个真正的企业级开源ERP解决方案。它提供的模块包括:电子商务应用(e-commerce), POS系统(point of sales),知识管理,存货与仓库管理
💻 JAVA
字号:
/* * $Id: SequenceUtil.java 5462 2005-08-05 18:35:48Z jonesde $ * *  Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org * *  Permission is hereby granted, free of charge, to any person obtaining a *  copy of this software and associated documentation files (the "Software"), *  to deal in the Software without restriction, including without limitation *  the rights to use, copy, modify, merge, publish, distribute, sublicense, *  and/or sell copies of the Software, and to permit persons to whom the *  Software is furnished to do so, subject to the following conditions: * *  The above copyright notice and this permission notice shall be included *  in all copies or substantial portions of the Software. * *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT *  OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *  THE USE OR OTHER DEALINGS IN THE SOFTWARE. */package org.ofbiz.entity.util;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.Hashtable;import java.util.Map;import javax.transaction.Transaction;import org.ofbiz.base.util.Debug;import org.ofbiz.entity.GenericEntityException;import org.ofbiz.entity.jdbc.ConnectionFactory;import org.ofbiz.entity.model.ModelEntity;import org.ofbiz.entity.model.ModelField;import org.ofbiz.entity.transaction.GenericTransactionException;import org.ofbiz.entity.transaction.TransactionUtil;/** * Sequence Utility to get unique sequences from named sequence banks * Uses a collision detection approach to safely get unique sequenced ids in banks from the database * * @author     <a href="mailto:jonesde@ofbiz.org">David E. Jones</a> * @version    $Rev: 5462 $ * @since      2.0 */public class SequenceUtil {    public static final String module = SequenceUtil.class.getName();    Map sequences = new Hashtable();    String helperName;    ModelEntity seqEntity;    String tableName;    String nameColName;    String idColName;    private SequenceUtil() {}    public SequenceUtil(String helperName, ModelEntity seqEntity, String nameFieldName, String idFieldName) {        this.helperName = helperName;        this.seqEntity = seqEntity;        if (seqEntity == null) {            throw new IllegalArgumentException("The sequence model entity was null but is required.");        }        this.tableName = seqEntity.getTableName(helperName);        ModelField nameField = seqEntity.getField(nameFieldName);        if (nameField == null) {            throw new IllegalArgumentException("Could not find the field definition for the sequence name field " + nameFieldName);        }        this.nameColName = nameField.getColName();        ModelField idField = seqEntity.getField(idFieldName);        if (idField == null) {            throw new IllegalArgumentException("Could not find the field definition for the sequence id field " + idFieldName);        }        this.idColName = idField.getColName();    }    public Long getNextSeqId(String seqName, long staggerMax) {        SequenceBank bank = (SequenceBank) sequences.get(seqName);        if (bank == null) {            synchronized(this) {                bank = (SequenceBank) sequences.get(seqName);                if (bank == null) {                    bank = new SequenceBank(seqName, this);                    sequences.put(seqName, bank);                }            }        }        return bank.getNextSeqId(staggerMax);    }    class SequenceBank {        public static final long defaultBankSize = 10;        public static final long startSeqId = 10000;        public static final int minWaitMillis = 5;        public static final int maxWaitMillis = 50;        public static final int maxTries = 5;        long curSeqId;        long maxSeqId;        String seqName;        SequenceUtil parentUtil;        public SequenceBank(String seqName, SequenceUtil parentUtil) {            this.seqName = seqName;            this.parentUtil = parentUtil;            curSeqId = 0;            maxSeqId = 0;            fillBank(1);        }        public synchronized Long getNextSeqId(long staggerMax) {            long stagger = 1;            if (staggerMax > 1) {                stagger = Math.round(Math.random() * staggerMax);                if (stagger == 0) stagger = 1;            }                        if ((curSeqId + stagger) <= maxSeqId) {                Long retSeqId = new Long(curSeqId);                curSeqId += stagger;                return retSeqId;            } else {                fillBank(stagger);                if ((curSeqId + stagger) <= maxSeqId) {                    Long retSeqId = new Long(curSeqId);                    curSeqId += stagger;                    return retSeqId;                } else {                    Debug.logError("[SequenceUtil.SequenceBank.getNextSeqId] Fill bank failed, returning null", module);                    return null;                }            }        }        protected synchronized void fillBank(long stagger) {            //Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Starting fillBank Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module);            long bankSize = defaultBankSize;            if (stagger > 1) {                // NOTE: could use staggerMax for this, but if that is done it would be easier to guess a valid next id without a brute force attack                bankSize = stagger * defaultBankSize;            }                        // no need to get a new bank, SeqIds available            if ((curSeqId + stagger) <= maxSeqId) return;                            long val1 = 0;            long val2 = 0;            // NOTE: the fancy ethernet type stuff is for the case where transactions not available            Transaction suspendedTransaction = null;            try {                //if we can suspend the transaction, we'll try to do this in a local manual transaction                suspendedTransaction = TransactionUtil.suspend();                                boolean beganTransaction = false;                try {                    beganTransaction = TransactionUtil.begin();                    Connection connection = null;                    Statement stmt = null;                    ResultSet rs = null;                    try {                        connection = ConnectionFactory.getConnection(parentUtil.helperName);                    } catch (SQLException sqle) {                        Debug.logWarning("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database... Error was:" + sqle.toString(), module);                        throw sqle;                    } catch (GenericEntityException e) {                        Debug.logWarning("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database... Error was: " + e.toString(), module);                        throw e;                    }                                        if (connection == null) {                        throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database, connection was null...");                    }                    String sql = null;                    try {                        // we shouldn't need this, and some TX managers complain about it, so not including it: connection.setAutoCommit(false);                        stmt = connection.createStatement();                        int numTries = 0;                        while (val1 + bankSize != val2) {                            if (Debug.verboseOn()) Debug.logVerbose("[SequenceUtil.SequenceBank.fillBank] Trying to get a bank of sequenced ids for " +                                    this.seqName + "; start of loop val1=" + val1 + ", val2=" + val2 + ", bankSize=" + bankSize, module);                                                        sql = "SELECT " + parentUtil.idColName + " FROM " + parentUtil.tableName + " WHERE " + parentUtil.nameColName + "='" + this.seqName + "'";                            rs = stmt.executeQuery(sql);                            boolean gotVal1 = false;                            if (rs.next()) {                                val1 = rs.getInt(parentUtil.idColName);                                gotVal1 = true;                            }                            rs.close();                                                        if (!gotVal1) {                                Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] first select failed: will try to add new row, result set was empty for sequence [" + seqName + "] \nUsed SQL: " + sql + " \n Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module);                                sql = "INSERT INTO " + parentUtil.tableName + " (" + parentUtil.nameColName + ", " + parentUtil.idColName + ") VALUES ('" + this.seqName + "', " + startSeqId + ")";                                if (stmt.executeUpdate(sql) <= 0) {                                    throw new GenericEntityException("No rows changed when trying insert new sequence row with this SQL: " + sql);                                }                                continue;                            }                            sql = "UPDATE " + parentUtil.tableName + " SET " + parentUtil.idColName + "=" + parentUtil.idColName + "+" + bankSize + " WHERE " + parentUtil.nameColName + "='" + this.seqName + "'";                            if (stmt.executeUpdate(sql) <= 0) {                                throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank] update failed, no rows changes for seqName: " + seqName);                            }                            sql = "SELECT " + parentUtil.idColName + " FROM " + parentUtil.tableName + " WHERE " + parentUtil.nameColName + "='" + this.seqName + "'";                            rs = stmt.executeQuery(sql);                            boolean gotVal2 = false;                            if (rs.next()) {                                val2 = rs.getInt(parentUtil.idColName);                                gotVal2 = true;                            }                            rs.close();                                                        if (!gotVal2) {                                throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank] second select failed: aborting, result " + "set was empty for sequence: " + seqName);                                                            }                            if (val1 + bankSize != val2) {                                if (numTries >= maxTries) {                                    throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank] maxTries (" + maxTries + ") reached, giving up.");                                }                                                                // collision happened, wait a bounded random amount of time then continue                                int waitTime = (new Double(Math.random() * (maxWaitMillis - minWaitMillis))).intValue() + minWaitMillis;                                Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Collision found for seqName [" + seqName + "], val1=" + val1 + ", val2=" + val2 + ", val1+bankSize=" + (val1 + bankSize) + ", bankSize=" + bankSize + ", waitTime=" + waitTime, module);                                try {                                    this.wait(waitTime);                                } catch (Exception e) {                                    Debug.logWarning(e, "Error waiting in sequence util", module);                                    throw e;                                }                            }                            numTries++;                        }                        curSeqId = val1;                        maxSeqId = val2;                        if (Debug.infoOn()) Debug.logInfo("Got bank of sequenced IDs for [" + this.seqName + "]; curSeqId=" + curSeqId + ", maxSeqId=" + maxSeqId + ", bankSize=" + bankSize, module);                    } catch (SQLException sqle) {                        Debug.logWarning(sqle, "[SequenceUtil.SequenceBank.fillBank] SQL Exception while executing the following:\n" + sql + "\nError was:" + sqle.getMessage(), module);                        throw sqle;                    } finally {                        try {                            if (stmt != null) stmt.close();                        } catch (SQLException sqle) {                            Debug.logWarning(sqle, "Error closing statement in sequence util", module);                        }                        try {                            if (connection != null) connection.close();                        } catch (SQLException sqle) {                            Debug.logWarning(sqle, "Error closing connection in sequence util", module);                        }                    }                } catch (Exception e) {                    String errMsg = "General error in getting a sequenced ID";                    Debug.logError(e, errMsg, module);                    try {                        TransactionUtil.rollback(beganTransaction, errMsg, e);                    } catch (GenericTransactionException gte2) {                        Debug.logError(gte2, "Unable to rollback transaction", module);                    }                } finally {                    try {                        TransactionUtil.commit(beganTransaction);                    } catch (GenericTransactionException gte) {                        Debug.logError(gte, "Unable to commit transaction", module);                    }                }            } catch (GenericTransactionException e) {                Debug.logError(e, "System Error suspending transaction in sequence util", module);            } finally {                if (suspendedTransaction != null) {                    try {                        TransactionUtil.resume(suspendedTransaction);                    } catch (GenericTransactionException e) {                        Debug.logError(e, "Error resuming suspended transaction in sequence util", module);                    }                }            }            //Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Ending fillBank Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module);        }    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -