求java数据库大神乱入!
本帖最后由 我想我会 于 2016-11-26 14:59 编辑工作中碰到一个难题,求java数据库高手和大神解惑!
任务需求:
1. 数据库:
数据库里有一个表,表里只有一个列,这个列是主键,同时是自增的
每次存入一个entity的时候,主键自动增加1
2. 业务层:
每当用户打开一个业务的时候,就会有一个entity 被保存到数据库里,然后立即返回这个entity的主键,应该是当前主键最大值,发送给客户,类似下面的情形:
....
speichereAktenziechen(entity);//存入数据库,主键自增1
int zahl = ermittleAktenzeichenZahl(); // 从数据库里取出该entity的主键值,也就是当前最大主键值
publischerEvent.schicke(zhal); // 发送回客户 ... 这个不重要
....
一句话概括就是: 每次打开业务用户都要获得一个当前最大的ankenzeichenzhal!
3. 这里不关心具体使用哪种数据库,Oracle or mysql or db2 or serversql , 因为上面的操作都是在 上层 ORM 层进行(ORM框架使用的是 apache cayenne,使用哪种orm框架也不重要), 所以这个问题不能通过具体的数据库操作和设置解决
4. 项目要求高并发,可能同1秒有几百到几千个用户在执行上面的操作
5. 问题:
1. 数据库只有一个列,该列是主键,而且是自增的,这个可行吗? 如何插入entity呢?
insert 直接 插入 空的 entity,总报错说sql 的 insert 格式不正确,出现这种情况: insert into GWA_AKTENZEICHEN values();values() 里面是空的,所以报错.
entity 应该带有一个属性 (attribute) id ?这个属性id 是否是主键? 主键自增的话,怎么能随便插入值?
2.
int zahl = ermittleAktenzeichenZahl(); // 从数据库里取出该entity的主键值,也就是当前最大主键值
如何取出最后一次插入的主键值呢(自动新增的主键值,last insert)? 不在数据库层面如何解决这个问题?
3.
speichereAktenziechen(entity);//存入数据库,主键自增1
int zahl = ermittleAktenzeichenZahl(); // 从数据库里取出该entity的主键值,也就是当前最大主键值
这两个操作在高并发的情况下,如何保证得到正确的 aktenzeichenZahl ?
保证一个entity存入数据库之后,立即从数据库里得到这个entity的主键值? 这个Transaktion 的问题怎样解决呢?
大家都懂的,在高并发的情况下,int zahl = ermittleAktenzeichenZahl();不一定能取得正确的最后一次插入值 last insert, ,那么分配给用户的 zahl 可能是错误的!
两个操作直接写在一起应该不对吧?应该如何解决呢?
感觉这问题挺有难度的,不知道如何解决,工版藏龙卧虎,能让无数,所以求java数据库高手和大神指点一下!
本帖最后由 我想我会 于 2016-11-26 12:18 编辑
保存和取出在高并情况下可能出现的问题:
1.
java 方面已经执行了 3 次 speichen 操作
假设数据库方面 自增操作能快点,已经完成3 speichen, 但 ermittle 取出操较慢,才完成第一次取出操作,开始第二次取出,那么第2个用户得到的 aktenzeichenzhal 就不是2 而是错误的 3!
2. 另外一个更显而易见的错误
保存1个 entity,数据库方面自增较慢,还没来的及存入,java 方面已经开始执行 ermittleAktenzeichenZahl 方法, 数据库开始 取出操作,这时候取出的可能是0!
晕啊,这个问题到底应该如何解决呢????头疼求高手和大神指点! 阿卵。 本帖最后由 leelight 于 2016-11-26 19:46 编辑
这种情况下,你用什么数据库区别非常的大:
1.如果是mysql,那么LAST_INSERT_ID满足上述的高并发条件,因为mysql是根据每个连接来返回相应的值
For LAST_INSERT_ID(), the most recently generated ID is maintained in the server on a per-connection basis. It is not changed by another client. It is not even changed if you update another AUTO_INCREMENT column with a nonmagic value (that is, a value that is not NULL and not 0). Using LAST_INSERT_ID() and AUTO_INCREMENT columns simultaneously from multiple clients is perfectly valid. Each client will receive the last inserted ID for the last statement that client executed.
2.如果是mssql,放狗 scope_identity
3. oracle 的获取sequence的确有些隐患,可以预先自己给出id,放狗twitter的IdWorker(snowflake),生成同一时空下唯一的自增id.
当然snowflake算法适合所有非自增数据结构
论坛里有其它db大神,等其他人
Lucky2013 发表于 2016-11-26 12:28
阿卵。
一起呼唤卵哥 {:5_383:} leelight 发表于 2016-11-26 18:40
这种情况下,你用什么数据库区别非常的大:
1.如果是mysql,那么LAST_INSERT_ID满足上述的高并发条件, ...
谢谢回复!
我狗狗了一下,看到过这个LAST_INSERT_ID,但需求上说,数据库类型是不确定的,可能是任何一种数据库,问题要在上一层解决,通过设置具体的数据库或者数据库操作,好像不行的
能不能在上一层通过简单的Transaktion设置解决呢? 把两个操作设置成一个transaktion内,保证每次两步操作作为一个单元执行,执行完了再处理下一个 entity? 这个transaktion应该在orm层上设置?
本帖最后由 leelight 于 2016-11-27 00:46 编辑
我想我会 发表于 2016-11-26 22:28
谢谢回复!
我狗狗了一下,看到过这个LAST_INSERT_ID,但需求上说,数据库类型是不确定的,可能是任何 ...
上层解决, 那就预给id,你们上层框架无非ssh或ssm
transaction atom不能保证多连接唯一性。
1:数据库一张表里面只有定义为key的行能设置为自增.一张表你可以定义多个key,但是一张表只能设置一个子增列.一般是设置到id(默认设置为primary key)上. 如果一张表只有一个列主键列id,先不说这么设计表有没有意义,你每次可以插入一个空项,id每次递增.你说数据库报错,那么需要更多信息,数据库版本,测试环境,具体报的什么错来进一步分析.
2:既然是用的orm框架,那么基本上在保存数据的时候会有返回值的吧,一般用法就是在程序里面创建一个对象,比如你想像1里面这样创建一个表,对应的对象实体比如档案编号只带一个值 id .那么你需要保存一个新的就可以建立一个新的空档案编号对象,然后保存以后返回的就是带当前id值的了.看了看apache cayenne文档,新增一条更简单,大概就是这么个写法 Artist artist = (Artist) context.newObject(Artist.class);不过既然你们是用java,那么java规范的jpa不是更好用么.还有看你提到主键插入值,你可以创建一个实体带你想要的id值,当然这个id是数据库里面没有分配过的,然后保存,但是这样的话下一个自动插入的对象,获得的id是从你刚刚保存的值开始自增的,不会自动填满系统原来最大id值和你刚刚保存的那个之间的部分.
3:同上,既然是用orm框架,那么一次persitent操作就是原子的啊,既然可以保存对象以后在返回的值里面拿到自动生成的id值,没必要再另外去尝试读取了.
另外你们这个设计谁做的啊,你们做项目有没有安排一个架构师跟进呢.看你问题里面描述的,又要高并发,高可用,那么把这么一个关键操作放到这样一张表里面来,这张表就存一个id,越简单那么其它表对它的依赖就越强,以后新增业务带来的复杂度增加有估算过没有呢.还有你们的系统部署是单实例的么,现在就在考虑每秒几k的访问操作,发展下去很快一台主机就抗不住了吧,有计划然后怎么办么,如果演变成多主机,那么数据库之间的同步还有协调准备怎么做,系统必须相应更新吧,到那时候再来做的话,业务量和发布新版本时间的压力就是山大了啊 leelight 发表于 2016-11-26 23:44
上层解决, 那就预给id,你们上层框架无非ssh或ssm
transaction atom不能保证多连接唯一性。
谢谢回复,我们不用SS,这两个框架或者相似功能部分用的是自己开发的,orm用的cayenne
头说不能用预给id,比如在上层 id + 1, 就用主键自增,然后还不让在数据库层设置,我真不知道怎么弄了 本帖最后由 我想我会 于 2016-11-27 23:04 编辑
gaokx 发表于 2016-11-27 22:01
1:数据库一张表里面只有定义为key的行能设置为自增.一张表你可以定义多个key,但是一张表只能设置一个子增列 ...
谢谢回复
1. 我测试用的数据库是Oracle, 我试过1. 插入空entity,entity没有任何属性, 出现上面的错误, 2. entity带一个id 属性,结果出现 数据库运行期错误,但是好像跟orm框架有关, 3. entity 带一个 localDate属性,文件号对于的年份,成功插入,主键自增,但需求要求entity应该是空的,不带任何属性!
2. 我们orm用的是 cayenne, cayenne 这个东西很烦,用的少所以文档和资料非常少,cayenne 使用起来远没那么简单, 它们文档提供的存取命令一点用没有,实际中必须用 map.xml 和 mapper (需要自己为每一个java Objekt写mapper, mapper里实现各种具体的映射)来映射存取数据, 非常繁琐和恶劣,而且出现问题跟本狗不到答案! 如通过cayenne设置主键自增需要在 map.xml里给主键分配属性 isGenerade=true, 1里的问题,我都不知道到底是数据库的原因,还是cayenne的问题?
我们不用jpa,直接用cayenne, 狗了一下,这个问题如果在数据库层面挺好解决的,oralce 用 sequence: Select CASE_SEQ.currval from dual, mysql 用 last_insert_id, 都能得到最新插入的自增主键, 而且能保证多用户高并发条件下反回正确ID,不同用户不同ID
而且像oracle 设置了自增主键以后,即便你插入一个id mit einem beliebigen wert,或者 id = null, 都不会破坏主键自增,因为主键自增来自于sequence,而用了cayenne 之后,我给entity中设置一个属性id, 无论插入null或者一个值,都发生 1里 2 的错误! 我不知道到底是谁的原因?
所以明天我只能去问问头,这问题能不能放到数据库层解决
我们的头就是架构,不知道他怎么想的,把这么一个本来属于他的任务让我做,有故意为难我的感觉?!{:5_383:}目前的任务就是这个,其它的我不清楚,也不关心,那些本来是他该做的!
本帖最后由 我想我会 于 2016-11-27 23:30 编辑
gaokx 发表于 2016-11-27 22:01
1:数据库一张表里面只有定义为key的行能设置为自增.一张表你可以定义多个key,但是一张表只能设置一个子增列 ...
还有一个3:
等我明天去看看是不是可以直接返回得到保存的值,关键如果你entity是空的,得到entity也没用啊,怎么得到主键啊,没有对应的属性,如何得到zahl呢?
本帖最后由 雪候鸟 于 2016-11-28 00:54 编辑
无需考虑任何数据库,无需虑任何orm, 直接告诉你们架构,只要保持max+1而且还要高并发的主键,直接在任何数据库都不行。因为递增主键是顺序排列,直接导致b+树数据块上的强烈竞争,一般每个数据块上的事务数量是受限制的。如果要做,你需要在application这层加个queue,事物提交只是写入queue种,然后在批量写入到数据库中,一些国内的”秒杀“的业务模式都是这么做,用queue来”消峰“。 如果递增主键没有特殊含义的话,可以考虑给这个表加一列uuid,前端拿uuid当key使用,后端慢慢保存,早点晚点就无所谓了。 雪候鸟 发表于 2016-11-28 01:39
无需考虑任何数据库,无需虑任何orm, 直接告诉你们架构,只要保持max+1而且还要高并发的主键,直接在任何数 ...
如果这么做,楼主首先哭倒在厕所,因为他要完成这个模块 adgjl 发表于 2016-11-28 09:47
如果递增主键没有特殊含义的话,可以考虑给这个表加一列uuid,前端拿uuid当key使用,后端慢慢保存,早点晚 ...
我也是这个方案 leelight 发表于 2016-11-28 15:07
如果这么做,楼主首先哭倒在厕所,因为他要完成这个模块
因为架构没脑,最基础的数据库知识都没有,还做架构,其实大部分编程也很差。不过做架构的大多都这样,不过还是拿高薪。
我深深记得我上个公司,脑袋一热架构大伽门就要把财务系统数据库从oracle迁移到db2, 结果可想而知。事物模型两个数据库就很不同,结果错账一堆,当然最后还会骂,数据库多烂多烂,程序员多差多差编程时不考虑兼容性。{:2_238:} adgjl 发表于 2016-11-28 08:47
如果递增主键没有特殊含义的话,可以考虑给这个表加一列uuid,前端拿uuid当key使用,后端慢慢保存,早点晚 ...
你这个答案不对,正确答案是:SAP。{:2_227:} 我想我会 发表于 2016-11-27 22:59
谢谢回复
1. 我测试用的数据库是Oracle, 我试过1. 插入空entity,entity没有任何属性, 出现上面的错 ...
很久不关心底层数据库的事,所以如果不切合现在的数据库技术表笑哈
就个人意见,如果要求高并发,你把这个类似uid之类的事情依赖于transaction不现实吧,你不能在内存的层面自己做一个cache吗?每一个有请求返回一个自增的id,然后你后台怎么把cache写数据库可以单独实现,你所有别的问题都可以在内存cache的层面很容易解决 小辣椒这个orm 其实还是有他自身的特点的, 轻量级的解决方案, 同时还是数据库的连接池。同时它还自己有个UI 你能通过那个生成xml。xml文件是必须的, 你无论用什么orm的framework都是有不同的xml.
当然很多都不用你自己写,通过ui 就能生成。
不过我记的cayenne的framework, 在主键递增上似乎好像是你要从code上给值,具体的我忘了,好几年前用过这个orm 其实用多了你就会发现都是差不多的。
对于并发性, 这个在数据库的层面都会解决,你要做的是看好用那个数据库, 然后查查他的并发是如何配置的。。。
感觉你想的问题不大到点上, 使用framework的目的就是为了解决一写重复性的问题,你提的问题在不同的层都有解决, 只是要看你具体用什么技术,然后去查他是怎么做的。 谢谢上面各位高人和大神!
问题已经解决了!-------今天找头儿讨论了一下,说了下我的看法,结果这货挠着脑袋想了半天,然后告诉我说--------其实他也还没想好该怎么做,这个任务不重要,还有很多更重要和紧急的任务要做,这个任务先放到一边去,等以后再说吧................
X他奶奶的, 这货真是个搅屎棍!平常工作态度就是马马虎虎的,就在那混,你都没想好的东西就让别人做,还告诉人家这不行那不行的,你这不是搞笑吗,你叫别人怎么做,浪费别人的时间?! 所以一开始我就觉得他在坑我!!
我们这个头儿,工作态度真的很差劲!经常在领导面前装的忙前忙后,其实一点都不认真!经常闹这种自相矛盾的笑话,而且经常推翻自己说的,好几次按他的思路开发,大家辛辛苦苦做好了,结果他又推翻了之前的思路重做,搞的有的同事忍不住跟他发火,真是浪费我时间!!
要说他水平还可以的,数据库可能不是强项,因为目前这个系统并发方面要求并不高,他的强项在模块整合和通讯,但这货真是个搅屎棍,明明是他没计划乱分派任务,结果成了我浪费2天时间nichts schaffen了,黑锅让我背,真是CTNND! jackylover1314 发表于 2016-11-28 17:31
小辣椒这个orm 其实还是有他自身的特点的, 轻量级的解决方案, 同时还是数据库的连接池。同时它还自己有个 ...
你真的用过cayenne吗? 如果你真的用过和了解cayenne就不会这么说了,cayenne的用法跟你说的完全不同的
那个破ui一点用处没有,指望那简陋的ui能生成什么简陋的xml? 跟你说的恰恰相反,我们是自己写map.xml,那个破ui只用来validieren一下,检查下错误,再别无它用!
orm框架当然本质上是一样的,但具体使用起来区别还是蛮大的, cayenne 跟 hibernate不能比的,除了轻型之外,cayenne在xml里设置entity关系的时候非常繁琐和另类,哪像hibernate用annotation就可以轻松搞定,在xml里设置关系也非常简变,除此之外cayenne还要自己写mapper klasse,每个java objekt 都要写,非常另类和繁琐! 这跟hibernate在用法上有很大区别的,如果你不知道写xml 和 mapper的话,那你可能没真正用过cayenne,
但我现在知道了,这个问题不在cayenne的原因,真正的原因是我们头儿是个bug!
我也觉得这个问题应该在数据库层解决,oracle和mysql都提供现成的功能,结果我们的头儿说不行,因为数据库是不确定的,要在上层orm层统一解决,这货说话估计都没过脑子.......
adgjl 发表于 2016-11-28 08:47
如果递增主键没有特殊含义的话,可以考虑给这个表加一列uuid,前端拿uuid当key使用,后端慢慢保存,早点晚 ...
{:9_526:} 本帖最后由 @Deutschland 于 2016-11-28 22:12 编辑
这样高并发的events直接数据库读写,不会照成数据库表格死锁吗?如果每小时千万次并发如何用数据库存储? 之后数据生成,模拟效率绝对是灾难。并且千万次并发也可能只有 比如 百万 unique user。感觉数据存入数据库前要aggregation。
分布式in memory(key : uuid)real time data storage。 import data into DB - batch job
或者 streaming : kafka + zookeeper ; spark/flink (real time or batch - data processing)
雪候鸟 发表于 2016-11-28 00:39
无需考虑任何数据库,无需虑任何orm, 直接告诉你们架构,只要保持max+1而且还要高并发的主键,直接在任何数 ...
今天头和上级还有一个负责数据库的同事讨论这问题,我在一旁听着,弄半天他们连这个aktenzeichenzahl的定义还没搞清楚,还没有明确定义,到底有什么意义 {:5_383:}
不过最后一个大概的思路是,上层需要给aktenzeichenzahl写一个service, service负责生成和分配zahl,然后再存入数据库,也就是说如果数据库不定的话,不能在数据库和orm层解决,跟你和adij 说的差不多
这种情况下,表里可能还需要有另外一个列..... 总之,乱七八糟的,他们到现在都没确定这个aktenzeichenzahl的含义是什么,这货就开始布置任务叫我做了,这不是搞笑吗! @Deutschland 发表于 2016-11-28 22:04
这样高并发的events直接数据库读写,不会照成数据库表格死锁吗?如果每小时千万次并发如何用数据库存储?...
我们这个系统系统刚开始开发,很多东西这货心里根本没谱,并发方面要求应该没那么高,系统更注重的是模块整合和通讯,要求把公司以前开发的好几个不同的系统整合进新系统,这货这方面比较强,所以找他来做架构 我想我会 发表于 2016-11-28 22:07
今天头和上级还有一个负责数据库的同事讨论这问题,我在一旁听着,弄半天他们连这个aktenzeichenzahl的定义还没搞清楚,还没有明确定义,到底有什么意义
不过最后一个大概的思路是,上层需要给aktenzeichenzahl写一个service, service负责生成和分配zahl,然后再存入数据库,也就是说如果数据库不定的话,不能在数据库和orm层解决,跟你和adij 说的差不多
这种情况下,表里可能还需要有另外一个列..... 总之,乱七八糟的,他们到现在都没确定这个aktenzeichenzahl的含义是什么,这货就开始布置任务叫我做了,这不是搞笑吗!别把自己想太重要了,开始布置任务叫你做,那是Kapazitätsplanung,当然得指定个人做,又不是教你各人负责到底。你想自己随便定方案,公司还不干呢。Pause你的,等负责人讨论明白了再动手,锅也不用你背。就算架构智商需要充值,也会有其他参与讨论的说No的,如果决策层全体智商需要充值,那反正你们公司也活不多久了…… 我想我会 发表于 2016-11-28 21:32
你真的用过cayenne吗? 如果你真的用过和了解cayenne就不会这么说了,cayenne的用法跟你说的完全不同的
...
感觉你是没有认真的研究一下这个framework,
http://www.ibm.com/developerworks/cn/java/j-lo-cayenne1/
这是我记得我最初用它时看得材料, 还有后一篇,中级应用。
当然还有他的api,网站文档。
我记得他的设置很简单啊,关系关系之间只是需要反向的设置, mapper 和Java class 还有数据库的配置都会自动生成。我大概是在2012到2013 年做项目的时候用过, 没向你说的如此复杂。
有些时候不是技术的问题是人的问题。 adgjl 发表于 2016-11-29 10:12
别把自己想太重要了,开始布置任务叫你做,那是Kapazitätsplanung,当然得指定个人做,又不是教你各人 ...
表吓唬楼主么
我估计和你想的差不多,架构有一个需求,然后觉得也许可以通过数据库解决,当然因为底层数据库没有指定,或者他希望decouple底层数据库的实现,所以想在orm解决,更想一个feasibility的question,如果没有好的解决,其实简单的回答不行,理由是如下abc,根据dev的反馈他需要修改他的解决方案 jackylover1314 发表于 2016-11-29 10:22
感觉你是没有认真的研究一下这个framework,
http://www.ibm.com/developerworks/cn/java/j-lo-cayenne1/ ...
呵呵 我没话可说,imb网站上这种入门级的demo也拿来说事,但凡学IT的都懂的,这上面的东西都给初学者用的,也就是三天入门的水平,跟实际中相差太远.
是我们公司用cayenne,而不是我自己用,怎么用也是跟公司学的,公司开发的几种产品已经投放市场多年了,其中有好几个用的是cayenne,数据库和配置有专门的同事负责,工作20多年了,敢情水平还赶不上你,还赶不上IMB网站这种入门教程? 呵呵,歇歇吧 adgjl 发表于 2016-11-29 10:12
别把自己想太重要了,开始布置任务叫你做,那是Kapazitätsplanung,当然得指定个人做,又不是教你各人 ...
你们可能不了解情况,我们这个架构确实混工作,他水平还是可以的,强项在模块组合,就因为有这个在手,所以平时工作就是混,关键的地方他上来给弄好了,其它的工作就马马虎虎,公司也不敢拿他怎么样,经常自相矛盾,出尔反尔,说话和布置任务都不过脑子
我们team不大,所以一个人一个坑,每个人的时间都挺宝贵,像这个任务,他连aktenzeichenzahl的定义都没明确,到底是什么含义,有没有实际意义,这都属于定义的问题,这都没搞明白就叫别人做,这肯定是白做,更别说其它方面了,如果aktenzeichzahl有意义,应该用uuid,不可能表里只有一个主键列还自增,布置任务的时候可没说他还没想好
去找他,经常碰见他在偷偷的打游戏或者浏览其它网站,这个货的工作态度就是吊儿郎当,有时候自己出错了,就找别人背黑锅
页:
[1]
2