DRP之id生成器及锁的思考

写这篇博文的背景,是发生在前段时间的评教系统,评教系统出现瘫痪,为了找出问题,大家加班加点,找出的问题就是一个字:“锁”,由于评教系统会频繁的出现学生对数据库的查询,修改,查询,修改,这样就产生了一个进程资源不够,产生死锁!

在进行DRP项目中,id生成器的原理与我原先评教系统的机制是大致相同的,id加1,然后接着查询id,反复进行此操作,如果一个人,小数据量的在进行,系统不会报错,但是,米老师一直提出“大数据”,我们做出的软件不是一个人在使用。如何避免这样的问题。看下面的代码:

package com.bjpowernode.drp.util;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

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

	/**
	 * 根据表名生成该表的序列
	 * @param tableName
	 * @return 返回生成的序列
	 */
	<span style="color:#ff0000;">//public static synchronized int generate(String tableName) {
	//public synchronized int generate(String tableName) {
		//synchronized(this) {</span>
	public static int generate(String tableName) {
		//使用数据库的悲观锁for update
		<span style="color:#ff0000;">String sql = "select value from t_table_id where table_name=? for update";</span>
		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);
		}
	} 

	public static void main(String[] args) {
		int retValue = IdGenerator.generate("t_client");
		System.out.println(retValue);
	}
}

请看上面代码中红色部分,static synchronized与synchronized以及synchronized(this)的区别(如果大家想看详细的介绍请看柳波师哥的博客点击打开链接):

1.synchronized static是某个类的范围,synchronized static 防止多个线程同时访问这个 类中的synchronized static 方法。它可以对类的所有对象实例起作用。 synchronized 是某实例的范围,synchronized 防止多个线程同时访问这个实例中的synchronized 方法。

2.synchronized方法与synchronized(this)代码快的区别

synchronized methods(){} 与synchronized(this){}之间没有什么区别,只是synchronized methods(){} 便于阅读理解,而synchronized(this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。

3.synchronized关键字是不能继承的

这里我想说一下关于死锁出现的情况以及解决的方案,大家看我的代码中红色的查询语句,

我在cmd窗口中实验了一下:

回车以后是没有提交数据的!

在另一个cmd窗口中,看看在红色区域是没有任何数据的!

出现上面的原因是在第一个窗口中锁住了数据库

那么第二个cmd窗口如何访问数据呢,在第一个窗口中提交事务或者回滚实务如下图:

当提交完成后在第二个窗口中就会自动出现下图:

上面在查询语句中加入了一个for update 这叫做悲观锁。

锁的概念在软考,操作系统,进程,线程和我们最近的评教系统中,都运用到了,如果将来以后做大数据,我相信锁的运用更是必不可少的!

				
时间: 2024-08-29 12:23:36

DRP之id生成器及锁的思考的相关文章

Jedis使用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】(转)

前段时间细节的了解了Jedis的使用,Jedis是redis的java版本的客户端实现.本文做个总结,主要分享如下内容: [pipeline][分布式的id生成器][分布式锁[watch][multi]][redis分布式]好了,一个一个来.一. Pipeline官方的说明是:starts a pipeline,which is a very efficient way to send lots of command and read all the responses when you fin

业务系统需要什么样的ID生成器

业务系统需要什么样的ID生成器 ID 生成器在微博我们一直叫发号器,微博就是用这样的号来存储,而我微博里讨论的时候也都是以发号器为标签.它的主要目的确如平常大家理解的“为一个分布式系统的数据object产生一个唯一的标识”,但其实在一个真实的系统里可能也可以承担更多的作用.概括起来主要有以下几点: 唯一性 时间相关 粗略有序 可反解 可制造 下面我会分别讲每个作用后面的考虑和权衡,也会对比介绍一下业界已知的几种 ID 设计. 要唯一性,是否需要全局唯一? 说起全局唯一,通常大家都会在想到发号器服

分布式全局ID生成器设计

项目是分布式的架构,需要设计一款分布式全局ID,参照了多种方案,博主最后基于snowflake的算法设计了一款自用ID生成器.具有以下优势: 保证分布式场景下生成的ID是全局唯一的 生成的全局ID整体上是呈自增趋势的,也就是说整体是粗略有序的 高性能,能快速产生ID,本机(I7-6400HQ)单线程可以达到每秒生成近40万个ID 只占64bit位空间,可以根据业务需求扩展在前缀或后缀拼接业务标志位转化为字符串. UUID方案 UUID:UUID长度128bit,32个16进制字符,占用存储空间多

分布式ID生成器 zz

简介 这个是根据twitter的snowflake来写的.这里有中文的介绍. 如上图所示,一个64位ID,除了最左边的符号位不用(固定为0,以保证生成的ID都是正数),还剩余63位可用. 下面的代码与图中的位数分配略有不同,除了中间部分10bit工作机器id不变,时间戳和序列号的位数是可以根据自己的需求变化的,就是说,你可以把中间的工作机器ID往左挪一挪,或往右挪一挪. 代码 /// <summary> /// 64位ID生成器,最高位为符号位,始终为0,可用位数63. /// 实例编号占10

全局唯一ID生成器(Snowflake ID组成)

Snowflake ID组成 Snowflake ID有64bits长,由以下三部分组成: time—42bits,精确到ms,那就意味着其可以表示长达(2^42-1)/(1000360024*365)=139.5年,另外使用者可以自己定义一个开始纪元(epoch),然后用(当前时间-开始纪元)算出time,这表示在time这个部分在140年的时间里是不会重复的,官方文档在这里写成了41bits,应该是写错了.另外,这里用time还有一个很重要的原因,就是可以直接更具time进行排序,对于twi

分布式唯一id生成器的想法

0x01 起因 前端时间遇到一个问题,怎么快速生成唯一的id,后来采用了hashid的方法.最近在网上读到了美团关于分布式唯一id生成器的解决方案, 其中提到了三种生成法:(建议看一下这篇文章,写得很详细,分析到位) UUID 数据库生成 类snowflake方案 0x02 问题 文中提到了如下几个问题 1.全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求. 2.趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数

高并发场景下System.currentTimeMillis()的性能问题的优化 以及SnowFlakeIdWorker高性能ID生成器

package xxx; import java.sql.Timestamp; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicLong; /** * 高并发场景下System.currentTimeMillis()的性能问题的优化 * <p><p> * System.currentTimeMillis()的调用比new一个普通对象要耗时的多(具体耗时高出多少我还没测试过,有人说是100

分布式唯一ID生成器Twitter

分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成. /** * Twitter_Snowflake<br> * SnowFlake的结构如下(每部分用-分开):<br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 -

zookeepeer ID生成器 (一)

目录 写在前面 1.1. ZK 的分布式命名服务 1.1.1. 分布式 ID 生成器的类型 UUID方案 1.1.2. ZK生成分布式ID 写在最后 疯狂创客圈 亿级流量 高并发IM 实战 系列 疯狂创客圈 Java 分布式聊天室[ 亿级流量]实战系列之 -25[ 博客园 总入口 ] 写在前面 ? 大家好,我是作者尼恩.目前和几个小伙伴一起,组织了一个高并发的实战社群[疯狂创客圈].正在开始高并发.亿级流程的 IM 聊天程序 学习和实战 ? 前面,已经完成一个高性能的 Java 聊天程序的四件大