zoukankan      html  css  js  c++  java
  • 【MySQL】MySQL的Sequence

    Oracle的Sequence用爽了,发现MySQL没有Sequence,那么,自己写一个呗。

    > 最简单的实现

    先建一个表存储当前值:

    CREATE TABLE `t_sequence` (
    `sequence_name`  varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '序列名称' ,
    `value`  int(11) NULL DEFAULT NULL COMMENT '当前值' ,
    PRIMARY KEY (`sequence_name`)
    )
    ENGINE=InnoDB
    DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
    ROW_FORMAT=COMPACT
    ;

    获取当前值的函数:

    CREATE DEFINER = `root`@`localhost` FUNCTION `currval`(sequence_name varchar(64))
     RETURNS int(11)
    BEGIN
        declare current integer;
        set current = 0;
        select t.value into current from t_sequence t where t.sequence_name = sequence_name;
        return current;
    end;

    获取下一个值:

    CREATE DEFINER = `root`@`localhost` FUNCTION `nextval`(sequence_name varchar(64))
     RETURNS int(11)
    BEGIN
        declare current integer;
        set current = 0;
        
        update t_sequence t set t.value = t.value + 1 where t.sequence_name = sequence_name;
        select t.value into current from t_sequence t where t.sequence_name = sequence_name;
    
        return current;
    end;

    写一个多线程程序测试下并发:

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class JDBCTools {
        
        public static void main(String[] args) throws Exception {
            JDBCTools.execute("update t_balance t set t.balance = 300 where t.user_id = 2");
            JDBCTools.query("select * from t_balance t");
        }
        
        public static String HOST = "localhost";
        public static String PORT = "3306";
        public static String DATABASE_NAME = "demo";
        public static String USER_NAME = "root";
        public static String PASSWORD = "123456";
        
        /**
         * 获取数据库连接
         * @return 数据库连接
         */
        public static Connection getConn() throws Exception {
            Class.forName("com.mysql.jdbc.Driver");
            
            String url = "jdbc:mysql://" + HOST + ":" + PORT + "/" + DATABASE_NAME + "?user=" + USER_NAME + "&password=" + PASSWORD + "&useUnicode=true&characterEncoding=UTF8";
            Connection connection = DriverManager.getConnection(url);
            return connection;
        }
        
        /**
         * 关闭资源
         */
        public static void closeResource(Connection conn, Statement st, ResultSet rs) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO 处理异常
                    e.printStackTrace();
                }
            }
            if (st != null) {
                try {
                    st.close();
                } catch (SQLException e) {
                    // TODO 处理异常
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO 处理异常
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 查询SQL
         * @param sql 查询语句
         * @return 数据集合
         * @throws SQLException
         */
        public static List<Map<String, String>> query(String sql) throws Exception {
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
            List<Map<String, String>> resultList = null;
            
            try {
                connection = JDBCTools.getConn();
                
                statement = connection.createStatement();
                resultSet = statement.executeQuery(sql);
                
                ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
                int columnCount = resultSetMetaData.getColumnCount();
                String[] columnNames = new String[columnCount + 1];
                for (int i = 1; i <= columnCount; i++) {
                    columnNames[i] = resultSetMetaData.getColumnName(i);
                }
    
                resultList = new ArrayList<Map<String, String>>();
                Map<String, String> resultMap = new HashMap<String, String>();
                resultSet.beforeFirst();
                while (resultSet.next()) {
                    for (int i = 1; i <= columnCount; i++) {
                        resultMap.put(columnNames[i], resultSet.getString(i));
                    }
                    resultList.add(resultMap);
                }
                // System.out.println("成功查询数据库,查得数据:" + resultList);
            } catch(Throwable t) {
                // TODO 处理异常
                t.printStackTrace();
            } finally {
                JDBCTools.closeResource(connection, statement, resultSet);
            }
            
            return resultList;
        }
        
        /**
         * 执行SQL
         * @param sql 执行的SQL
         * @return 操作条数
         */
        public static int execute(String sql) throws Exception {
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
            int num = 0;
            
            try {
                connection = JDBCTools.getConn();
                
                statement = connection.createStatement();
                num = statement.executeUpdate(sql);
                
            } catch(Throwable t) {
                // TODO 处理异常
                t.printStackTrace();
            } finally {
                JDBCTools.closeResource(connection, statement, resultSet);
            }
            
            return num;
        }
        
    }
    View Code
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    
    public class Call {
        
        public static ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
    
        public static void main(String[] args) {
            ExecutorService es = Executors.newCachedThreadPool();
            
            for (int i = 0; i < 100; i++) {
                es.execute(new Runnable() {
                    
                    @Override
                    public void run() {
                        String key = getSequence();
                        if (!map.contains(key)) {
                            System.out.println("put " + key);
                            map.put(key, key);
                        } else {
                            System.out.println(key + " is exists.");
                        }
                    }
                });
            }
    
        }
        
        public static String getSequence() {
            List<Map<String, String>> list = null;
            try {
                list = JDBCTools.query("select nextval('user_code') as current");
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            String temp = list.get(0).get("current");
            return temp;
        }
    
    }

    > 用排他锁的方式

    上面的程序虽然测试并无发现问题(有可能测试程序写得不好),理论上高并发会出现重复值,用排他锁重写了一下,不过效率会比较低:

    CREATE DEFINER = `root`@`localhost` FUNCTION `nextval_safe`(sequence_name varchar(64))
     RETURNS int(11)
    BEGIN
        declare current integer;
        set current = 0;
        
        select t.value into current from t_sequence t where t.sequence_name = sequence_name for update;
        update t_sequence t set t.value = t.value + 1 where t.sequence_name = sequence_name;
        set current = current + 1;
    
        return current;
    end;
  • 相关阅读:
    【InnoDB】插入缓存,两次写,自适应hash索引
    【InnoDB】缓冲池
    P3371 【模板】单源最短路径(弱化版) 题解
    P1463 [POI2002][HAOI2007]反素数 题解
    CF701B Cells Not Under Attack 题解
    P1120 小木棍 [数据加强版] 题解
    P3951 小凯的疑惑 题解
    P1135 奇怪的电梯 题解
    P1748 H数 题解
    P3388 【模板】割点(割顶) 题解
  • 原文地址:https://www.cnblogs.com/nick-huang/p/5641977.html
Copyright © 2011-2022 走看看