ID生成器

       在一个关系数据库中,所有的数据都是存储在表里的,每一个表都有一个主键(Primary Key)。对大多数的用户输入数据来讲,主键需要由系统以序列号的方式产生(大多数),而不是由操作人员给出。

      某些关系数据库引擎提供某种序列键生成机制。如SQL Server允许每一个表内可以有一个自动编号列。Oracle提供Sequence对象,可以提供序列键值。

      主键:它的值用于惟一地标识表中的某一条记录

      但某些数据库引擎则没有相应的机制,如Sybase。这时就需要我们自己去生成主键序列号。通常的做法是使用一个表来存储所有的主键最大值。这个表包含两个列,一个列存放键名,另一个列存放键值.

      主键生成器的使用环境

       1.主键自动增长序列,这时需要一个主键生成器

       2.大数据量表中,查询主键最大值,我们需要一个主键生成器跟踪数据表中的主键状态,当需要查询数据表中的记录数时,只需要查询一下主键维护表就可以迅速得出结果.

       主键生成器的代码(Java)实现

/**
 * id生成器
 * @author Administrator
 *
 */
public class IdGenerator {

	/**
	 * 根据表名生成该表的序列
	 * @param tableName
	 * @return 返回生成的序列
	 */
	public static int generate(String tableName) {
		//使用数据库的悲观锁for update
		String sql = "select value from t_table_id where table_name=? for update";
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		int value = 0;
		try {
			conn = DbUtil.getConnection();
			//开始事务
			DbUtil.beginTransaction(conn);
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, tableName);
			rs = pstmt.executeQuery();
			if (!rs.next()) {
				throw new RuntimeException();
			}
			value = rs.getInt("value");
			value++; //自加
			modifyValueField(conn, tableName, value);
			//提交事务
			DbUtil.commitTransaction(conn);
		}catch(Exception e) {
			e.printStackTrace();
			//回滚事务
			DbUtil.rollbackTransaction(conn);
			throw new RuntimeException();
		}finally {
			DbUtil.close(rs);
			DbUtil.close(pstmt);
			DbUtil.resetConnection(conn); //重置Connection的状态
			DbUtil.close(conn);
		}
		return value;
	}
	
	/**
	 * 根据表名更新序列字段的值
	 * @param conn
	 * @param tableName
	 * @param value
	 */
	private static void modifyValueField(Connection conn, String tableName, int value) 
	throws SQLException {
		String sql = "update t_table_id set value=? where table_name=?";
		PreparedStatement pstmt = null;
		try {
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, value);
			pstmt.setString(2, tableName);
			pstmt.executeUpdate();
		}finally {
			DbUtil.close(pstmt);
		}
	} 

}

   上述代码中,需要注意的是,主键生成器的多线程问题使用了"for updat"悲观锁来解决.悲观锁是采用数据库机制实现的,数据被锁住之后其他用户将无法查看,直到锁释放,只有提交或回滚事务锁才会释放.for update语句只能放到select语句中,因为查询时把数据锁住才有意义.悲观锁的使用仅是将查询的一条数据锁住,而不是整个主键维护表.

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值