在编写基于数据库的应用时,有一个常见的需求:某一张表有个编码字段,需要按照一定的规则生成,例如:某订单编号的生成规则是:部门编号+yyyyMMdd+四位流水号,中间部分代表当前的年月日。难点就是如何生成流水号,并且能够保证在多用户并发的情况下,保证流水号不重复。
得到流水号的方法比较简单:select max(theColumn) from theTable where theColumn like “BBXXXXXXX%”,即在该表中查询具有相同前缀(编码流水号之前的部分)的编码最大值,然后再将流水号部分+1就可以得到新的编码了。为了保证流水号不重复,我们需要锁定数据,但是如果锁定该表的话,开销太大,针对该表的增、删、改操作都不能进行。这里采用一个小技巧:我们单独建立一张新的表格,SQL语句如下:
create table LOCK_TABLE (
TABLE_NAME VARCHAR(20) not null
constraint PK_ LOCK_TABLE primary key (TABLE_NAME)
)
这个表只有一个字段,数据即需要我们生成编号的表名。我们在计算某个表的当前最大流水号之前,首先锁定LOCK_TABLE表中数据为该表名的那条数据(具体方法后文有介绍),然后再执行上面的select max(**) …… 操作,得到新的编码。请注意:上面的锁定LOCK_TABLE表中一行数据;查询最大编码是在一个事务中完成的。
锁定LOCK_TABLE表中数据为该表名的那条数据的方法:就是在普通的SQL语句中加入锁定的关键字,对于Oracle来说是: for update ;对于SQLServer来说是 with (holdlock)。
具体实现代码如下:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.apache.log4j.Logger;
public class KeyGenerator{
private Logger logger = Logger.getLogger(KeyGenerator.class);
private Connection conn;
private String tableName;
private String columnName;
private String head;
private int numCount;
private String lockString;
/**
* @param tableName - 表名
* @param columnName - code 对应 字段名
* @param head - 缺少最后流水号的 code 前端
* @param numCount - 最后流水号数字的个数
* @param lockString - 对应于 LOCK_TABLE表中的字符串名
*/
// example used in xxxCreateBO
// KeyGenerator keyGenerator= new KeyGenerator(getSession().connection(),"TS_GXCPRD","APP_ID","2005210204A",4,"TS_GXCPRD");
// String key=keyGenerator.getKey();
public KeyGenerator(Connection conn,String tableName,String columnName,String head,int numCount,String lockString) {
this.conn=conn;
this.tableName=tableName;
this.columnName=columnName;
this.head=head;
this.numCount=numCount;
this.lockString=lockString;
}
private String computeNewCode(String maxCode,String head,int numCount){
String newCode="";
if(maxCode!=null){
int i=head.length();
int j=maxCode.length();
int k=j-i;
String numPart=maxCode.substring(i,j);
int theInt= new Integer(numPart).intValue();
theInt++;
String numString =new Integer(theInt).toString();
k=k-numString.length();
String temp0="";
for(;k>0;k--){
temp0=temp0+"0";
}
numString=temp0+numString;
newCode=head+numString;
}
else{
String temp0="";
for(int k=numCount-1;k>0;k--){
temp0=temp0+"0";
}
newCode=head+temp0+"1";
}
return newCode;
}
public String getKey() {
String oracleLockStr=" for update ";
String sqlServerLockStr=" with (holdlock) ";
String sql1 = " SELECT * FROM " + "LOCK_TABLE ";
// 用来锁定表中记录
// 如果是SQLServer数据库用 with (holdlock),放在where条件前面
// SQLServer 例子:select * from LOCK_TABLE with (holdlock) where TABLE_NAME like 'aaa%';
// 如果是oracle数据库用 for update,放在where条件后面
// Oracle 例子: select * from LOCK_TABLE where TABLE_NAME like 'aaa%' for update;
sql1 = sql1+sqlServerLockStr;
sql1 = sql1+" WHERE " + "TABLE_NAME" + " LIKE '" + lockString.trim() + "'";
String sql2 = " SELECT MAX(" + columnName+ ") AS A FROM "+ tableName ;
sql2 = sql2+" WHERE " + columnName + " LIKE '" + head.trim() + "%' ";
PreparedStatement pstm1 = null;
PreparedStatement pstm2 = null;
Statement stmt = null;
ResultSet rset1 = null;
String maxCode="";
String newCode="";
try {
pstm1 = conn.prepareStatement(sql1);
pstm1.executeQuery();
pstm2 = conn.prepareStatement(sql2);
rset1 = pstm2.executeQuery();
rset1.next();
maxCode=rset1.getString("A");
newCode=computeNewCode(maxCode,head,numCount);
logger.info("newCode:"+newCode);
System.out.println("newCode:"+newCode);
return newCode;
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
return null;
}
finally{
try {
if (rset1 != null)
rset1.close();
} catch (SQLException e1) {
}
try {
if (pstm1 != null)
pstm1.close();
if (pstm2 != null)
pstm2.close();
if (stmt != null)
stmt.close();
} catch (SQLException e1) {
}
}
}
}
分享到:
相关推荐
IMEI批量生成器是一款工具软件,主要用于快速生成大量IMEI(国际移动设备识别码)号码。IMEI是每个移动通信设备如手机、平板电脑等独一无二的标识符,由15位数字组成,用于区分全球范围内的移动设备。下面将详细阐述...
《C++实现彩票生成器详解》 在编程领域,C++是一种强大且广泛应用的编程语言,尤其在系统软件、游戏开发、嵌入式系统等领域有着广泛的应用。本篇将深入探讨一个C++编写的彩票生成器项目,它是在DOS环境下运行的,...
订单号随机生成器是一种软件工具,它主要用于生成唯一的、随机的订单编号,这对于团购商家或者电商平台来说至关重要。在处理大量订单时,一个清晰且独特的订单号可以帮助商家有效地追踪和管理交易,避免混淆或遗漏。...
二维码软件生成器是一种工具,它能够将各种类型的数据,如文本、网址、联系信息等,编码成二维条形码——即我们熟知的二维码。在现代生活中,二维码的应用日益广泛,从商业广告到个人资料分享,从支付接口到产品追溯...
条形码生成器是一种软件工具,它允许用户创建和打印各种类型的条形码,以便用于产品标识、库存管理、物流追踪等应用场景。在本案例中,我们关注的是一个使用C++编程语言编写的条形码生成器源程序。C++是一种强类型、...
双色球通用号码更新器 注意事项: 1.绿色版无需安装。 2.运行前请修改app.config文件的数据库路径。路径中不要包含中文!!! 3.双击“LotteryCaptureTool.exe”运行程序。 详细:...
6. **自定义编号生成器** 如果标准的自动编号机制不能满足特定需求,开发者可以编写自定义函数或存储过程来生成编号。例如,可以创建一个包含序列号、日期或字母前缀的复杂编号系统。 7. **数据库设计** 设计...
EAN13(欧洲物品编号13位码)是一种全球通用的商品条形码系统,由国际物品编码协会(GS1)制定,是EAN(欧洲物品编号)系统的组成部分。它由13位数字组成,分为前缀码、厂商识别码、商品项目代码和校验码四个部分: ...
public class编号生成器 { public static String 时间戳编号() { long currentTimeMillis = System.currentTimeMillis(); return String.valueOf(currentTimeMillis); } public static String UUID编号() { ...
《手机通讯录VCF文件生成器-易语言详解》 在现代生活中,手机通讯录的重要性不言而喻,它存储着我们与外界联系的关键信息。然而,当我们需要将大量通讯录信息从Excel表格转移到手机时,手动操作既耗时又容易出错。...
条形码技术主要基于国际标准,如EAN(欧洲物品编号)和UPC(通用产品代码),以及更先进的二维条码如QR码。这些标准确保了全球范围内的互操作性,使得任何支持条形码阅读器的设备都能读取和解码信息。条形码通常包含...
一维二维通用条码扫描器是本站发布的第一个条码扫描项目,条码扫描器在您的手机上使用摄像头读取条形码,查询产品的信息,如价格和评论。此外,还可以读取QR吗和Data Matrix二维条码。传统的条形码,如产品包装上...
EAN-13条形码是一种国际通用的商品条形码编码标准,全称为欧洲物品编号,主要用于标识零售商品、非零售商品以及物流单元。在EAN-13条形码中,数字通常由13位组成,分为前缀码、制造商代码、产品代码和校验码四个部分...
内部具有LCD偏置生成器,并且拥有电压跟随缓冲器。它可以驱动80个段,支持多达40个7段字母数字字符,21个14段字母数字字符,以及最多320个任意图形元素。 PCA85133拥有80×4位RAM用于显示数据存储,支持自动增量式...
4. 内置LCD偏置生成器,配备电压跟随缓冲器。 5. 可驱动32个段,支持最多16个7段字母数字字符,最多8个14段字母数字字符,或任何高达128个元素的图形。 6. 拥有32×4位RAM用于存储显示数据。 7. 支持设备子地址边界...
CIGI是一种开放的接口规范,旨在提供一个通用的接口标准,用于连接图像生成器与模拟器。该规范由The Boeing Company维护和更新。CIGI的主要目标是提供一个统一的接口标准,以便于图像生成器和模拟器之间的通信和交互...
在数据库设计方面,本系统包含了序列产生器表(Base_Sequence),用于生成各种序列号,以保证数据的唯一性。序列产生器表中包含了序列号前缀、序列号分隔符、升序序列、倒序序列以及步骤描述等字段。序列产生器的创建...
利用CPU ID、MAC地址等硬件信息,结合随机数生成器,可以创建与特定设备关联的唯一编码。但这可能引发隐私问题,不适用于所有场景。 在测试这些方法时,需要关注以下指标: - **唯一性**:确保在所有测试条件下,...
2. **公平随机性**:通过高质量的随机数生成器,保证每个参与者的中奖概率一致,避免结果的偏颇。 3. **实时显示**:程序应实时展示抽奖过程,如滚动名单、中奖结果等,增加活动的紧张感和观赏性。 4. **结果记录*...
.NET和.NET Core生成器的GeneXus标准类。 建造状态 科 状态 主 贝塔 模组 名称 描述 包裹编号 Gx加密 与.NET和.NET Core通用的与基于Twofish算法的加密相关的类 GeneXus加密 GxEncryptCMD 允许对数据进行加密和...