晕了我呀 发表于 2009-3-17 08:14:28

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;
    /**
    * Created by IntelliJ IDEA.<br>
    * <b>User</b>: leizhimin<br>
    * <b>Date</b>: 2008-4-2 15:21:30<br>
    * <b>Note</b>: Java实现的Sequence工具
    */
    public class SequenceUtils {
      private static SequenceUtils _instance = new SequenceUtils();
      private Map<String, KeyInfo> keyMap = new HashMap<String, KeyInfo>(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.*;
    /**
    * Created by IntelliJ IDEA.<br>
    * <b>User</b>: leizhimin<br>
    * <b>Date</b>: 2008-4-2 15:24:52<br>
    * <b>Note</b>: 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.*;
    /**
    * 简单的数据连接工具
    * File: DBUtils.java
    * User: leizhimin
    * Date: 2008-3-18 15:19:12
    */
    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;
    /**
    * Created by IntelliJ IDEA.
    * User: leizhimin
    * Date: 2008-4-2 15:31:30
    * Company: LavaSoft(http://lavasoft.blog.51cto.com)
    * 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
    -- http://lavasoft.blog.51cto.com
    -- 2008年4月3日
    -- 创建数据库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;   
    数据库操作的截屏:上一页    
                  

www.ad119.cn/bbs/attachments/basic/20090317/20093178133275077801.png

    六、运行测试类输出结果:





   ----------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载体信息,并更新数据库记录信息。
    上一页
页: [1]
查看完整版本: Java实现的Sequence工具