使用递归唯一性验证的方式生成主键

标签: 递归 唯一性 验证 | 发表时间:2013-03-09 01:11 | 作者:wj800
出处:http://blog.csdn.net

JadePool作为简化JDBC编程工具,提供 主键生成方法是必须的。在JadePool中,ProcessVO用于事务型数据库的DML操作,Access用于非事务型数据库的DML操作,Access参照ProcessVO实现。

目前,JadePool只提供了单主键的键值生成方法,没有提供复合主键的生成方法。这里以ProcessVO为例。ProcessVO提供了三个插入主键的方法,分别是:

public Long insertKey(String tableName);
public Object insertAutoKey(String tableName);
public String insertKey(String tableName, String keyValue);


参数tableName是表的名称,虽然没有提供XML映射、注入映射,但创建ProcessVO对象时,通过实例化DbCenter的某一个实例,数据库的结构信息已经被保存在该实例的相关属性中。在tableName表中,哪一个字段是主键,该字段有哪些属性,这些信息均可以通过访问DbCenter的实例得到。



一、长整形主键键值生成策略
调用insertKey(String tableName)插入长整形键值。

insertKey在多例模式的某一个实例中实现,取值范围是系统时间*10000+[0~9999]。在这个取值范围内,按照从小到大的方向,通过递归唯一性验证的方式获取第一个符合条件的值。用户在使用JadePool时,应当注意,一个数据库只使用DbCenter的一个实例。

一个数据库只使用DbCenter的一个实例,这同使用单例模式的效果是相同的。

插入主键的过程是这样的,ProcessVO的对象向DbCenter的实例请求插入主键键值,DbCenter的实例通过调用自身管理的Table对象的方法makeLongKeyValue()计算唯一性的主键值, 将结果返回给DbCenter的实例,逐步返回给ProcessVO对象。
在Table对象中,makeLongKeyValue()方法调用了一个递归方法onlyLongValue(),用于确保返回的键值是唯一的。


ProcessVO		DbCenter		
   |                   |                   
   |                   |                   
   |                   |                   
insertKey------------->|                   
   |                   |
   |         getTable(tableName).makeLongKeyValue()
   |                   |                   
   |<------------------|                   
   |                   |                   
   |                   |                   

具体的实现,参阅源代码
    /**
     * Make long KeyValue
     *
     * @return System.currentTimeMillis*10000+Num, the Num is between 0 and
     * 9999;for example :2012-11-01 HH:mm:ss as
     * 1351749144390,getting:13517491443897256
     */
    synchronized public long makeLongKeyValue() {
        long t = System.currentTimeMillis();
        return onlyLongValue(t, 0);//only value//递归,直到不等
    }

    private long onlyLongValue(long time, long add) {
        long v;
        long len = 10000;
        long k = time * len + add;
        if (k > lastMakeLongKeyValue) {
            lastMakeLongKeyValue = k;
            v = k;
        } else {
            add++;
            if (add > 9999) {
                v = onlyLongValue(time + 1, 0);
            } else {
                v = onlyLongValue(time, add);
            }
        }
        return v;
    }


有关主键生成策略的话题很多,较有代表性的提法是用系统时间加随机数作为键值,这种方式产生的结果会导致键值不能按照时间的先后排列,如果按照主键键值的大小顺序排队买火车票,这种方式就不合理了。

二、通用键值生成器
调用insertAutoKey(String tableName)可以插入Long、Integer、Short、Double、Float以及String类型的主键键值。除了String类型有一定的条件限制外,其它类型的主键键值均是在原表中最大主键值得基础上加1或更大的数所得。生成过程与长整形主键生成的过程相同,同样经过递归唯一性验证。

具体的实现,参阅源代码

    /**
     * @param field
     * @param fieldValue 从数据库中查询的最大值 生成各种类型的第一个主键值
     */
    synchronized public Object makeObjectKeyValue(Field field, Object fieldValue) throws SQLException {
        String className = field.getTypeClassName();
        Object nextValue = null;
        if (fieldValue != null && !"".equals(fieldValue.toString())) {
            if (className.equals("java.lang.Long")) {
                if (((Long) fieldValue).longValue() == Long.MAX_VALUE) {
                    throw new SQLException("Long value must less than Long.MAX_VALUE " + Long.MAX_VALUE);
                }
                nextValue = new Long(((Long) fieldValue).longValue() + 1);
            }
            if (className.equals("java.lang.Integer")) {
                if (((Integer) fieldValue).intValue() == Integer.MAX_VALUE) {
                    throw new SQLException("Integer value must less than Integer.MAX_VALUE " + Integer.MAX_VALUE);
                }
                nextValue = new Integer(((Integer) fieldValue).intValue() + 1);
            }
            if (className.equals("java.lang.Short")) {
                if (((Short) fieldValue).shortValue() == Short.MAX_VALUE) {
                    throw new SQLException("Short value must less than Short.MAX_VALUE " + Short.MAX_VALUE);
                }
                short v = ((Short) fieldValue).shortValue();
                v++;
                nextValue = new Short(v);
            }
            if (className.equals("java.lang.Float")) {
                if (((Float) fieldValue).floatValue() == Float.MAX_VALUE) {
                    throw new SQLException("Float value must less than Float.MAX_VALUE " + Float.MAX_VALUE);
                }
                Float v = new Float(((Float) fieldValue).floatValue() + 1);
                long l = (long) v.floatValue();
                nextValue = new Float(l);

            }
            if (className.equals("java.lang.Double")) {
                if (((Double) fieldValue).doubleValue() == Double.MAX_VALUE) {
                    throw new SQLException("Double value must less than Double.MAX_VALUE " + Double.MAX_VALUE);
                }
                Double v = new Double(((Double) fieldValue).doubleValue() + 1);
                long l = (long) v.floatValue();
                nextValue = new Double(l);
            }
        } else {
            if (className.equals("java.lang.Long")) {
                nextValue = new Long(0);
            }
            if (className.equals("java.lang.Integer")) {
                nextValue = new Integer(0);
            }
            if (className.equals("java.lang.Short")) {
                short v = 0;
                nextValue = new Short(v);
            }
            if (className.equals("java.lang.Float")) {
                nextValue = new Float(0);
            }
            if (className.equals("java.lang.Double")) {
                nextValue = new Double(0);
            }
        }
        return onlyObjectValue(field, nextValue);//唯一性验证
    }

    private Object onlyObjectValue(Field field, Object keyValue) throws SQLException {
        Object v;
        if (!keyValue.equals(lastMakeObjectKeyValue)) {
            lastMakeObjectKeyValue = keyValue;
            v = keyValue;
        } else {
            v = onlyObjectValue(field, makeObjectKeyValue(field, keyValue));//递归,直到不等
        }
        return v;
    }


三、插入用户指定的主键键值
调用insertKey(String tableName, String keyValue)方法,用来将用户指定的键值keyValue插入到tableName表中。调用Table中的makeStringKeyValue(keyField, keyValue)方法验证主键键值的唯一性、合法性。

具体的实现,参阅源代码

    /**
     * Make String KeyValue 检查用户输入的字段是否存在、其值是否合法和是否唯一
     *
     * @param keyValue 给定键值
     * @return 字段存在,且合法唯一,则返回keyValue本身;否则,返回null
     */
    synchronized public String makeStringKeyValue(String keyField, String keyValue) throws SQLException {
        JadeTool tool = new JadeTool();
        if (keyValue == null) {
            throw new SQLException("the key field value must not be null. ");
        }
        String v = null;
        if (tool.isInFields(fields, keyField) && !keyValue.equals(lastStringKeyValue)) {
            lastStringKeyValue = keyValue;
            v = keyValue;
        }
        if (v == null) {
            throw new SQLException("the key field value already being existence. ");
        }
        return v;//可能返回null值,返回null时,用户应当重新输入新值
    }


作者:wj800 发表于2013-3-9 1:11:42 原文链接
阅读:122 评论:0 查看评论

相关 [递归 唯一性 验证] 推荐:

使用递归唯一性验证的方式生成主键

- - CSDN博客数据库推荐文章
JadePool作为简化JDBC编程工具,提供 主键生成方法是必须的. 在JadePool中,ProcessVO用于事务型数据库的DML操作,Access用于非事务型数据库的DML操作,Access参照ProcessVO实现. 目前,JadePool只提供了单主键的键值生成方法,没有提供复合主键的生成方法.

如何将递归转换为非递归 - coderkian

- - 博客园_首页
递归函数具有很好的可读性和可维护性,但是大部分情况下程序效率不如非递归函数,所以在程序设计中一般喜欢先用递归解决问题,在保证方法正确的前提下再转换为非递归函数以提高效率. 函数调用时,需要在栈中分配新的帧,将返回地址,调用参数和局部变量入栈. 所以递归调用越深,占用的栈空间越多. 如果层数过深,肯定会导致栈溢出,这也是消除递归的必要性之一.

PHP正则之递归匹配

- KnightE - 风雪之隅
作者: Laruence(. 本文地址: http://www.laruence.com/2011/09/30/2179.html. 我记得早前有同事问, 正则是否能处理括号配对的正则匹配. 比如, 对于如下的待匹配的字符串:. 在以前, 这种情况, 正则无法处理, 最多只能处理固定层数的递归, 而无法处理无线递归的情况… 而在perl 5.6以后, 引入了一个新的特性: Recursive patterns, 使得这种需求可以被正确的处理..

java 验证码

- - ITeye博客
// 创建字体,字体的大小应该根据图片的高度来定. // 随机产生160条干扰线,使图象中的认证码不易被其它程序探测到. // randomCode用于保存随机产生的验证码,以便用户登录后进行验证. // 随机产生codeCount数字的验证码. // 得到随机产生的验证码数字. // 产生随机的颜色分量来构造颜色值,这样输出的每位数字的颜色值都将不同.

递归算法与优化后的算法对比

- - 博客园_首页
前段时间看了《 【面试】——反应迟钝的递归》中的三个递归算法,斐波那契数列优化后的算法思路确实不错,但是后面2个数列用递归的话,个人感觉有点得不偿失. 能不用递归的话,尽量不用,因为有些算法完全可以用数学来解决. 因此,本文中将这三个数列的最终算法总结如下. 1、计算数组1,1,2,3,5,8,13...第30位的值.

AngularJS表单验证

- - JavaScript - Web前端 - ITeye博客
        通过AngularJS我们不仅可以隐藏/显示错误提示消息,高亮输入框,还可以通过编写指令来随心所欲的控制表单验证方式. $scope.reset=function(){ //表单重置. 表单验证.
表单验证
.

SQLserver, Oracle 限制层数 递归查询和反向查询父记录

- - Oracle - 数据库 - ITeye博客
以前使用Oracle,觉得它的递归查询很好用,就研究了一下SqlServer,发现它也支持在Sql里递归查询. SqlServer2008版本的Sql如下:. 比如一个表,有id和pId字段,id是主键,pid表示它的上级节点,表结构和数据:. --下面的Sql是查询出1结点的所有子结点. select * from my1 --结果包含1这条记录,如果不想包含,可以在最后加上:where id <> 1.

谷歌验证:Google Authenticator

- loverty - 移动应用观察
  谷歌验证(Google Authenticator)通过两个验证步骤,在登录时为您的谷歌帐号提供一层额外的安全保护. 使用谷歌验证可以直接在用户的设备上生成动态密码,无需网络连接. 特点:自动生成QR码;支持多帐户;支持通过time-based和counter-based生成.   当用户在Google帐号中启用“两步验证”功能后,就可以使用Google Authenticator来防止陌生人通过盗取的密码访问用户的帐户.

js验证图片大小

- - JavaScript - Web前端 - ITeye博客
var ie=!-[1,];   //区分ie. var img=new Image();//动态创建img. if(img.readyState=='complete'){//当图片load完毕. alert(img.fileSize);//ie获取文件大小. document.body.removeChlid(img);//获取大小结束,移除图片.

CXF WEBSERVICE 安全验证

- - 企业架构 - ITeye博客
CXF 封装的接口,不希望对外暴露 WSDL结构,找到的CXF安全认证技术都是基于拦截器,在调用的时候返回认证错误信息, 不能保护WSDL不被看到,后来看到别人的一个实现方式最简单有效,基于URL拦截的安全保护,用FILTER. 现在把这2种安全保护都记录下来,备用. 参考: http://www.myexception.cn/open-source/1505475.html.