浏览 11329 次
该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2003-09-16
capitain write: 我们的数据库定义mapping使用了 <id name="id" column="ID" type="long"> <generator class="sequence"> <param name="sequence">seq_somename</param> </generator> </id>但是这样做 我发现 hibernate会取得一次sequence, 同时数据库还有一个triger会取得一次sequence, 这样实际的sequence会加2了!! 而且create返回的对象的主键id也是错误的, 因为还被triger加了1, 数据库里面的记录全面是双数, 2,4,6,8 create返回主键却是1,3,5,7 请问 这样问题怎么解决, 因为triger不能删除, 能让hibernate利用triger生成的取值吗? 我查看了hibernate的文档和源代码, 发现generator 为 sequence时候 它最后会调用这个方法 dialect下面的Oracle9Dialect中的 public String getSequenceNextValString(String sequenceName); { return "select " + sequenceName + ".nextval from dual"; } triger再这么走一遍 sequence必然是加入2次 我使用native,发现工作结果和sequence一样, 难道没有办法解决了吗? robbin write: 我有一个最简单的解决办法: 看Hibernate2.0.3源代码的net.sf.hibernate.dialect.Oracle9Dialect第78行: public String getSequenceNextValString(String sequenceName); { return "select " + sequenceName + ".nextval from dual"; } 只要我们把它改成下面这个样子,就行了: public String getSequenceNextValString(String sequenceName); { return "select " + sequenceName + ".currval + 1 from dual"; } 也就是说Hibernate去取序列值的时候,不让序列加1,只取当前值然后加1返回,插入的时候让trigger来给序列加1 因此你可以这样来做,写一个新的Dialect: package net.sf.hibernate.dialect; public class OracleMyDialect extends OracleDialect { public String getSequenceNextValString(String sequenceName); { return "select " + sequenceName + ".currval + 1 from dual"; } } 编译好以后放在CLASSPATH里面,配置Hibernate hibernate.dialect net.sf.hibernate.dialect.OracleMyDialect 这样就行了,解决掉你那个问题了。 capitain write: 谢谢, 我对oracle很不熟悉, 不知道,这样只加一 如果在多个连接向数据库内插入记录的时候, 会不会有问题, 换句话说,不知道hibernate里面这个getSequenceNextValString()和triger发生之间时间内如果有插入会有问题吗? 不知道oracle的驱动能不能保证这是一个原子操作? robbin write: 不能够保证原子性,可能会有并发访问的冲突。不过目前来说你也只能如此了,说实话这个办法只能算是权宜之计。 由于session.save() 需要返回主键,所以当你使用trigger来创建id的时候,Hibernate是无法知道trigger当前创建的主键是什么,不论你用 select sequ.currval from dual; 还是 select max(id); from table_name; 在插入数据之后来获得主键,都有并发冲突的可能性。唯一的避免并发冲突的办法是: insert into table_name ... returning :id; 用Oracle特有的这个sql来插入数据,返回主键,让Hibernate知道主键的值,不过Hibernate目前并不能够支持这个sql语句,如果要让Hibernate支持这个sql,需要对源代码做相当大的改动。看看以后会不会加吧。 这个问题我不是第一次和别人讨论了,确实没有好的解决办法,除非对Hibernate进行大面积修改。但是话说回来,我用Oracle那么多年了,从来都不使用trigger实现Auto increment字段,我个人认为这种方式不好。本来Oracle已经把sequence从字段里面解放出来了,你还要在把它放回去。不用trigger一样可以生成主键,看两个例子: 插入单条数据: insert table_name(id, name,...); values(sequ.nextval, ....);; 批量插入数据: insert table_name(id, name,...); select sequ.nextval, name,... from table2_name; richart write: 这么做的话,最好是用一下nvl()函数(oracle自带),而且只能改动oracle相关的一个类。如果使用的是别的数据库,不知道有没有相似的问题存在? robbin write: oldma 写道 呵呵,谁能给解释一下?
看下面的PL/SQL: create trigger y before insert on bob for each row when (new.a is null); begin select x.nextval into :new.a from dual; end; 用trigger来读sequence,插入表的主键字段,模拟SQL Server中的Auto Increment 字段 capitain write: 那oracle还有什么标准的办法实现Auto Increment 字段? 我们目前的程序插入的时候是按照auto increment字段来的, 就是不写id那个字段, 让数据库操作, 请问其他办法可以适用吗? mikeho write: 是的,oracle是不必再写sp了,我们以前是在SQL server里面写了个sp来生成seq,没有用自增长,因为自增长在方法调用后返回id比较麻烦。现在都使用模拟UUID了(只有50位,理论上有重复建的危险,呵呵)。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |