15
回答
关于自增长Id 的危害,以及如何 替代自增长列保证 Id 唯一?
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   

今天和 同学讨论一个问题,争得口干舌燥,也没解决掉

就是 数据库的自增长id 该不该用

我认为 自增长id 危害太大,不该用,理由如下:

 

 在写 面向对象的时候 不能保证完整性,
比如定义一个 
//学生类
class Student{
   public int Id{ get;set;}
   public string Name{get;set;}
}

//数据库添加类
class StudentDao{
//如果使用自增长Id ,id  无法控制
public statuc bool Add(Student stu){
 return sqlHelper.Execute("insert into [student](Name) values('"+stu.Name+"')");
}

//如果使用可控制Id id 可以控制
public statuc bool Add(Student stu){
return  sqlHelper.Execute("insert into [student](Id,Name) values("+stu.Id+",'"+stu.Name+"')");
}
}



var stu  = new Student();
stu.Name="小明";
StudentDao.Add(stu);

//如果其他地方需要调用到 stu 这个对象,stu 这时候 数据不完整,因为不知道 Id
// 所以我认为不能使用数据库的自增长Id

//如果事先可以知道Id
//设计一个静态类专门生成唯一Id 
class IdDao
{
    //简单的写下 我知道有错误
   public static int Get(string key){
    return (int)sqlHelper.GetVar("update [xx_Id] Id=Id+1 where [key]='"+key+"';select id from [xx_id] where key='"+key+"'");
  }
}

 

 var stu  = new Student();

stu.Id = IdDao.Get("student");//获得一个id

stu.Name="小明";
StudentDao.Add(stu);

//下面如果有其他程序 调用 stu 的时候 stu.Id 是有值的,这样就保证了程序的完整性

//但是我同学认为 ,如果有人同时执行 IdDao.Get("student"); 这个时候 数据库并发操作,可能同时执行程序的几个人 id 是一样的,我觉得说的也有道理


 

<无标签>
举报
foxidea
发帖于5年前 15回/7K+阅
共有15个答案 最后回答: 5年前

用uuid代替主键自增长id,数据库中有一个data_insert_time字段保存该数据插入时间,用于排序。

用uuid的,在数据库移植,多表,多数据库(分布式存储)的时候非常方便,如果用自增长id,就无法使用多表 或者 多数据库 (可以添加其他表示来做,但是非常麻烦)

--- 共有 1 条评论 ---
Mr-CoolB我觉得这个比较中肯。。存在即合理,个人修行不够,掌控不了代码是很悲催的 5年前 回复
我想不出来不用自动增长的理由。。
--- 共有 2 条评论 ---
老吴Ch分库的时候,第二个数据库会从0开始自增。id就不唯一了,所以才诞生了这个话题,有很多解决方案。孰优孰劣,还要根据环境考虑呢。 1年前 回复
ddatsh+1 5年前 回复

这个理由很有个性!

虽然我不写程序了,但我个人感觉这个程序的问题,你可以有很多种做法,比如,在insert之后,一般都有返回自增ID的接口,赋值给ID不就行了吗?(也许我比较肤浅)

好,不从程序上说,从产品上说,不使用自增ID,那就意味很多了很多的工作量,投入和产出是不是成比例?当然,从学术上说,我没什么话语权。

老兄,Hibernate的Session类保存一个对象后返回的就是已保存对象的ID啊,咋不可控制呢?如果你不用Hibernate,直接JDBC的话并且数据库是oracle的话,也可以用

select seqName.nextVal() from dual

先得到一个自增的ID,然后设置到对象中再保存,这样ID也是可控制的。数据库自带的ID生成序列肯定有并发控制的机制,你不需担心并发时会产生重复ID的问题。

       提了这个问题的,大部分都是sql server数据库的。楼上几位就不用拿java、oracle来举例了。dotnet和Java的开发模式还是有很大区别的。

       如果GUID、UUID不会影响到查询的性能,建议用他们。自增长在很多场景下处理起来比较麻烦。例如:外键问题。

说来说去就是你不知道怎么获取自增后的id的问题,你的解决思路就是批判自增id的不行,却不去想着有什么解决方案,人家提供好了方法你不去查当然不知道了,去查查 Statement.RETURN_GENERATED_KEYS,就知道怎么获取自增的ID了。
--- 共有 4 条评论 ---
foxidea回复 @迷路的游侠 : 那爽啊,sqlserver 不知道行不行 5年前 回复
迷路的游侠回复 @范红振 : oracle和postgresql都可以在插入数据之前获得自增ID 5年前 回复
白起回复 @范红振 : 你要在之前获取有什么用呢?好像没碰到过这样的场景,自增的那个id知识数据的索引,如果是学生的id,应该另建id,当没有插入数据库的时候也就是连数据在数据库中是否存在都不知道,这条数据的id(索引)又有什么存在的必要? 5年前 回复
foxidea不是,我知道怎么获得自增长Id, 自增长Id 需要插入数据库之后才能获得, 我想在之前就获得一个Id 5年前 回复

id不一定非得用int型啊,也可以用varchar2的,我是做MES我们这随便一个小工厂每天产生的数据量都有3G左右要是都用int型的话相信没多久就超出范围了,我们的key值是通过某些列的值拼接而成的,比如要表示一条代号为9999的工厂下的(SFC)车间控制作业:SFC2012081300001,key值可以为:BO:9999:SFC2012081300001,这样你要获得key的话可以通过拼接得到,数据库端也不会溢出,仅仅举个例子

顶部