Java实现的Sequence工具 - 2

Sequence是数据库系统按照一定规则自动增加的数字序列。这个序列一般作为代理主键(因为不会重复),没有其他任何意义。 

Sequence是数据库系统的特性,有的数据库实现了Sequence,有的则没有。比如Oracle、DB2、PostgreSQL数据库实现Sequence, 而MySQL、SQL Server、Sybase等数据库没有Sequence。

那么如何给一个不支持Sequence的数据库增加支持呢?

下面将给出Java版本的代码。这个代码还实现了对 Sequence ID的高效缓存,并不是每一次调用都会对数据库进行访问,在高并发环境下性能优异。

1. SequenceId.java

package uuid;
 
public class SequenceId {
    public static final long NOT_FOUND = 0;
    private static final long STEP = 100;
    private final SequenceIdProvider provider;
    private final String name;
    private final long beginValue;
    private long value;
 
    protected SequenceId(SequenceIdProvider provider, String name, long beginValue) {
        this.provider = provider;
        this.name = name;
        this.beginValue = beginValue;
        this.value = -1;
 
        if (beginValue <= 0) {
            throw new IllegalArgumentException("begin value must be great than zero.");
        }
    }
 
    public String getName() {
        return name;
    }
 
    public synchronized long nextVal() {
        if (value < 0) {
            value = provider.load(name);
            if (value <= NOT_FOUND) {
                value = beginValue - 1;
            }
            provider.store(name, value + STEP);
        }
 
        value++;
 
        if (value % STEP == 0) {
            provider.store(name, value + STEP);
        }
 
        return value;
    }
}


?

2. SequenceIdProvider.java

package uuid;
 
public interface SequenceIdProvider {
     
    public SequenceId create(String name);
     
    public SequenceId create(String name, long begin);
     
    public long load(String name);
 
    public void store(String name, long value);
     
}

?
3. JdbcSequenceIdProvider.java

?
package uuid;
 
import java.sql.*;
import javax.sql.DataSource;
 
public class JdbcSequenceIdProvider implements SequenceIdProvider {
 
    private static final String TABLE_NAME = "_SEQUENCE_";
    private final DataSource dataSource;
 
    public JdbcSequenceIdProvider(DataSource dataSource) {
        this.dataSource = dataSource;
 
        confirmTableExists();
    }
 
    @Override
    public SequenceId create(String name) {
        return new SequenceId(this, name, 1);
    }
 
    @Override
    public SequenceId create(String name, long begin) {
        return new SequenceId(this, name, begin);
    }
 
    private void confirmTableExists() {
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
 
            ResultSet rs = conn.getMetaData().getTables(null, null, TABLE_NAME, null);
            boolean found = rs.next();
            rs.close();
 
            if (!found) {
                Statement stmt = conn.createStatement();
                String sql = "create table " + TABLE_NAME + " (name varchar(50) not null, next_val long not null, primary key(name))";
                stmt.execute(sql);
                stmt.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            close(conn);
        }
    }
 
    private void close(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
 
    @Override
    public long load(String name) {
        long value = SequenceId.NOT_FOUND;
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            String sql = "select next_val from " + TABLE_NAME + " where name=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, name);
            ResultSet rs = ps.executeQuery();
            if (rs.next()) {
                value = rs.getLong(1);
            }
            rs.close();
            ps.close();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            close(conn);
        }
        return value;
    }
 
    @Override
    public void store(String name, long value) {
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            String sql = "update " + TABLE_NAME + " set next_val=? where name=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setLong(1, value);
            ps.setString(2, name);
            int updated = ps.executeUpdate();
            ps.close();
 
            if (updated == 0) {
                sql = "insert into " + TABLE_NAME + " (name, next_val) values (?,?)";
                ps = conn.prepareStatement(sql);
                ps.setString(1, name);
                ps.setLong(2, value);
                ps.executeUpdate();
                ps.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            close(conn);
        }
    }
}


4. GlobalSequenceIdProvider.java

package uuid;
 
import javax.sql.DataSource;
 
public class GlobalSequenceIdProvider {
 
    private static final SequenceId global;
    private static final SequenceId table1;
    private static final SequenceId table2;
 
    static {
        SequenceIdProvider provider = new JdbcSequenceIdProvider(getDataSource());
        global = provider.create("global");
        table1 = provider.create("table1");
        table2 = provider.create("table2", 1000);
    }
 
    public static long nextVal() {
        return global.nextVal();
    }
 
    public static long nextVal_table1() {
        return table1.nextVal();
    }
 
    public static long nextVal_table2() {
        return table2.nextVal();
    }
 
    private static DataSource getDataSource() {
        // TODO:
        return null;
    }
 
}


?
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值