Java 实现sequence

Java实现的Sequence工具
 
Sequence是数据库应用中很重要的一个特性,可是有些数据库没有这个特性,比如很流行的开源数据库MySQL就没有Sequence,利用自增主键感觉很不爽,每个表的ID都要设置,通用性也不好。因此考虑为这些不支持Sequence的数据做一个Sequence工具。自动为整个系统提供主键生成策略。
 
下面是一个Sequence实现,以数据库MySQL为平台。源代码如下:
 
一、Sequence工具类
package sequence;

import java.util.HashMap;
import java.util.Map;
import java.sql.SQLException;

/**
* @des: Java实现的Sequence工具
*/

public class SequenceUtils {
    private static SequenceUtils _instance = new SequenceUtils();
    private Map keyMap = new HashMap(20); //Sequence载体容器
    private static final int POOL_SIZE = 10;      //Sequence值缓存大小

    /**
     * 禁止外部实例化
     */

    private SequenceUtils() {
    }

    /**
     * 获取SequenceUtils的单例对象
     * @return SequenceUtils的单例对象
     */

    public static SequenceUtils getInstance() {
        return _instance;
    }

    /**
     * 获取下一个Sequence键值
     * @param keyName Sequence名称
     * @return 下一个Sequence键值
     */

    public synchronized long getNextKeyValue(String keyName) {
        KeyInfo keyInfo = null;
        Long keyObject = null;
        try {
            if (keyMap.containsKey(keyName)) {
                keyInfo = keyMap.get(keyName);
            } else {
                keyInfo = new KeyInfo(keyName, POOL_SIZE);
                keyMap.put(keyName, keyInfo);
            }
            keyObject = keyInfo.getNextKey();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return keyObject;
    }
}
 
二、Sequence载体
package sequence;

import java.sql.*;

/**

* @des: Sequence载体
*/

public class KeyInfo {
    private long maxKey;        //当前Sequence载体的最大值
    private long minKey;        //当前Sequence载体的最小值
    private long nextKey;       //下一个Sequence值
    private int poolSize;       //Sequence值缓存大小
    private String keyName;     //Sequence的名称
    private static final String sql_update = "UPDATE KEYTABLE SET KEYVALUE = KEYVALUE + ? WHERE KEYNAME = ?";
    private static final String sql_query = "SELECT KEYVALUE FROM KEYTABLE WHERE KEYNAME = ?";

    public KeyInfo(String keyName, int poolSize) throws SQLException {
        this.poolSize = poolSize;
        this.keyName = keyName;
        retrieveFromDB();
    }

    public String getKeyName() {
        return keyName;
    }

    public long getMaxKey() {
        return maxKey;
    }

    public long getMinKey() {
        return minKey;
    }

    public int getPoolSize() {
        return poolSize;
    }

    /**
     * 获取下一个Sequence值
     *
     * @return 下一个Sequence值
     * @throws SQLException
     */

    public synchronized long getNextKey() throws SQLException {
        if (nextKey > maxKey) {
            retrieveFromDB();
        }
        return nextKey++;
    }

    /**
     * 执行Sequence表信息初始化和更新工作
     *
     * @throws SQLException
     */

    private void retrieveFromDB() throws SQLException {
        System.out.println("");
        Connection conn = DBUtils.makeConnection();
        //查询数据库
        PreparedStatement pstmt_query = conn.prepareStatement(sql_query);
        pstmt_query.setString(1, keyName);
        ResultSet rs = pstmt_query.executeQuery();
        if (rs.next()) {
            maxKey = rs.getLong(1) + poolSize;
            minKey = maxKey - poolSize + 1;
            nextKey = minKey;
            rs.close();
            pstmt_query.close();
        } else {
            System.out.println("执行Sequence数据库初始化工作!");
            String init_sql = "INSERT INTO KEYTABLE(KEYNAME,KEYVALUE) VALUES('" + keyName + "',10000 + " + poolSize + ")";
            Statement stmt = conn.createStatement();
            stmt.executeUpdate(init_sql);
            maxKey = 10000 + poolSize;
            minKey = maxKey - poolSize + 1;
            nextKey = minKey;
            stmt.close();
            return;
        }

        //更新数据库
        conn.setAutoCommit(false);
        System.out.println("更新Sequence最大值!");
        PreparedStatement pstmt_up = conn.prepareStatement(sql_update);
        pstmt_up.setLong(1, poolSize);
        pstmt_up.setString(2, keyName);
        pstmt_up.executeUpdate();
        pstmt_up.close();
        conn.commit();

        rs.close();
        pstmt_query.close();
        conn.close();
    }
}
 
三、简单的数据库连接工具
package sequence;

import java.sql.*;

/**
* 简单的数据连接工具
*/

public class DBUtils {
    public static final String url = "jdbc:mysql://127.0.0.1:3306/testdb";
    public static final String username = "root";
    public static final String password = "leizhimin";
    public static final String driverClassName = "com.mysql.jdbc.Driver";

    /**
     * 获取数据库连接Connection
     *
     * @return 数据库连接Connection
     */

    public static Connection makeConnection() {
        Connection conn = null;
        try {
            Class.forName(driverClassName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            conn = DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public static void main(String args[]) {
        testConnection();
    }

    /**
     * 测试连接方法
     */

    public static void testConnection() {
        Connection conn = makeConnection();
        try {
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM mysql.user");
            while (rs.next()) {
                String s1 = rs.getString(1);
                String s2 = rs.getString(2);
                System.out.println(s1 + "\t" + s2);
            }
            rs.close();
            stmt.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
 
四、测试类(客户端)
package sequence;

/**
* Sequence测试(客户端)
*/

public class TestSequence {
    /**
     * 测试入口
     * @param args
     */

    public static void main(String args[]) {
        test();
    }

    /**
     * 测试Sequence方法
     */

    public static void test() {
        System.out.println("----------test()----------");
        for (int i = 0; i < 20; i++) {
            long x = SequenceUtils.getInstance().getNextKeyValue("sdaf");
            System.out.println(x);
        }
    }
}
 
五、Sequence表的代码(for MySQL5)
-- SQL for MySQL5

-- 创建数据库testdb
create database if not exists testdb character set gbk collate gbk_chinese_ci;

-- 创建Sequence表
DROP TABLE IF EXISTS keytable;
CREATE TABLE keytable (
  KEYNAME varchar(24) NOT NULL COMMENT 'Sequence名称',
  KEYVALUE bigint(20) DEFAULT '10000' COMMENT 'Sequence最大值',
  PRIMARY KEY (KEYNAME)
) ENGINE=MyISAM DEFAULT CHARSET=gbk;
 
数据库操作的截屏:
 
六、运行测试类输出结果:
----------test()----------

更新Sequence最大值!
10061
10062
10063
10064
10065
10066
10067
10068
10069
10070

更新Sequence最大值!
10071
10072
10073
10074
10075
10076
10077
10078
10079
10080

Process finished with exit code 0
 
说明:这个Sequence工具很智能,当请求一个不存在的Sequence时,会自动生成一个Sequence,保存到数据库。当请求一个已经存在的Sequence时,会从Sequence载体的缓存中获取一个Sequence值返回,当Sequence载体的缓存值达到最大时,会自动重新初始化Sequence载体信息,并更新数据库记录信息。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值