hibernate自增主键的并发问题

先准备环境,mysql新建test表有一个自增主键叫id,并且有一记录当前时间的日期字段。如下:


测试代码:


        Configuration configuration = new Configuration();
        configuration.configure("/hibernate.cfg.xml");
        SessionFactory sessionFactory = configuration.buildSessionFactory();
         Session session = sessionFactory.getCurrentSession();
         Transaction tr=session.beginTransaction();
         Test t=new Test();
        
         t.setName("23");
         Serializable id=session.save(t);
         System.out.println("incId:"+id);
         tr.commit();

 
hibernate自增主键的实现的两种方案
1.increment方式

<id name="id" type="java.lang.Integer">
            <column name="id" length="11">               
            </column>          
            <generator class="increment" />
</id>


执行测试代码可看到日志:
Hibernate: select max(id) from test
incId:12
Hibernate: insert into test (name, id) values (?, ?)
这说明该方式是在save方法执行后,事务提交前用max(id)方式获取自增id的,并发测试结果会发生重复主键情况
2.native方式

<id name="id" type="java.lang.Integer">
            <column name="id" length="11">               
            </column>          
            <generator class="native" />
</id>

执行测试代码可看到日志:
Hibernate: insert into test (name) values (?)
测试:
线程1:在提交事务之前(commit前一行)加入较长时间执行的程序.
线程2:代码不变(会比线程1早提交)
可以发现,线程1的id是比线程2的id小的。但是时间字段值线程1比线程2的值大,说明是后提交到数据库的。

由上述例子可以看出:使用native的方式,在事务开启时分配id,多线程时可以避免重复主键问题

3.最后再debug看一下hibernate是怎么取得返回主键值的。
保存对象时使用的代码是org.hibernate.Session.save(obj);
Session的实现类是SessionImpl,如下图堆栈所示,最后进入了GetGeneratedKeysHelper.的getGeneratedKey方法:


再看这个方法的实现:


这里可看出他是使用了java.sql.Statement.getGeneratedKeys方法取得自增主键的。
文/程忠 浏览次数:0次   2015-03-16 09:16:07

相关阅读


评论:
点击刷新

↓ 广告开始-头部带绿为生活 ↓
↑ 广告结束-尾部支持多点击 ↑