You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate中Session.persist()与Session.save()的差异困惑及测试解析请求

关于Hibernate Session.persist()与Session.save()的测试疑问及解析

问题描述

我想明确Hibernate中Session.persist()与Session.save()的区别。根据资料,persist()在执行flush或commit操作前不会立即向数据库发起请求;而当实体主键由数据库自动生成时,save()会立即执行插入操作。但通过测试代码验证后,发现两者表现一致,特此附上代码及测试结果,希望得到原因解析。


测试代码与结果

测试persist()的场景

DAO代码

@Transactional
@Repository
@EnableTransactionManagement
class myclass{
                @Autowired
                SessionFactory sf;
                @Transactional
                public List<Object> list(ApplicationContext ctx){
                        Session session=sf.getCurrentSession();
                        Query query=session.createQuery("select i from ilyass i");
                        List<Object> list=query.getResultList();
                        return list;
                }
                public ilyass save(ilyass ily)throws InterruptedException {
                        Session session=sf.getCurrentSession();
                        session.persist(ily);
                        for(int i=0;i<10;i++){
                                System.out.println("iliawait!");
                                Thread.sleep(2000);
                        }
                        System.out.println("ID:+ "+ily.id);
                        return ily;
                } 
                public Saiidd saveSaid(Saiidd ily)throws InterruptedException{
                        Session session=sf.getCurrentSession();
                        session.persist(ily);
                        for(int i=0;i<10;i++){
                                System.out.println("sawait!");
                                Thread.sleep(2000);
                        }
                        System.out.println("ID:+ "+ily.it);
                        return ily;
                } 
}

测试代码

AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext(demo.class);
        ilyass ilias=new ilyass();
        ilias.name="af";
        Saiidd said=new Saiidd();
        said.username="az";
        said.it=229;
        myclass mydao=ctx.getBean(myclass.class);
       mydao.save(ilias);
       System.out.println("id: "+ilias.id);

         mydao.saveSaid(said);
        System.out.println("id: "+said.it);

测试结果

Hibernate: 
    /* insert entities.ilyass
        */ insert 
        into
            ilyass
            (id, name) 
        values
            (default, ?)
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
ID:+ 30
id: 30
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
ID:+ 229
Hibernate: 
    /* insert entities.Saiidd
        */ insert 
        into
            Saiidd
            (username, it) 
        values
            (?, ?)
id: 229

测试save()的场景

DAO代码

@Transactional
@Repository
@EnableTransactionManagement
class myclass{
                @Autowired
                SessionFactory sf;
                @Transactional
                public List<Object> list(ApplicationContext ctx){
                        Session session=sf.getCurrentSession();
                        Query query=session.createQuery("select i from ilyass i");
                        List<Object> list=query.getResultList();
                        return list;
                }
                public ilyass save(ilyass ily)throws InterruptedException {
                        Session session=sf.getCurrentSession();
                        session.persist(ily);
                        for(int i=0;i<10;i++){
                                System.out.println("iliawait!");
                                Thread.sleep(2000);
                        }
                        System.out.println("ID:+ "+ily.id);
                        return ily;
                } 
                public Saiidd saveSaid(Saiidd ily)throws InterruptedException{
                        Session session=sf.getCurrentSession();
                        session.save(ily);
                        for(int i=0;i<10;i++){
                                System.out.println("sawait!");
                                Thread.sleep(2000);
                        }
                        System.out.println("ID:+ "+ily.it);
                        return ily;
                } 
}

测试结果

Mar 23, 2025 6:41:38 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate: 
    /* insert entities.ilyass
        */ insert 
        into
            ilyass
            (id, name) 
        values
            (default, ?)
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
iliawait!
ID:+ 32
id: 32
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
sawait!
ID:+ 228
Hibernate: 
    /* insert entities.Saiidd
        */ insert 
        into
            Saiidd
            (username, it) 
        values
            (?, ?)
id: 228

原因解析

1. 主键生成策略是核心影响因素

  • 对于ilyass实体,它的主键采用数据库自增策略(比如IDENTITY):Hibernate要把数据库生成的主键值赋值给实体的id字段,必须立即执行INSERT语句去数据库获取这个值。这种情况下,不管调用persist()还是save(),都会触发立即插入,这就是你看到两者表现一致的原因。
  • 对于Saiidd实体,测试中手动指定了主键值(said.it=229):此时Hibernate不需要从数据库获取主键,调用persist()时会延迟插入,直到事务flush或commit阶段才执行INSERT,这和测试结果中Saiidd的插入语句在等待循环结束后执行的表现完全吻合。

2. persist()的延迟特性有前提

persist()的延迟插入并非绝对,只有当实体主键生成策略不需要立即和数据库交互时(比如手动赋值、SEQUENCE配合HiLo策略),才会延迟到flush/commit时执行插入。如果主键依赖数据库自增,persist()也会立即触发插入,和save()行为一致。

3. 事务上下文的作用

你的DAO类被@Transactional修饰,Session处于事务上下文,但这不是立即插入的直接原因,核心还是主键生成策略要求Hibernate必须立即获取主键值。


内容的提问来源于stack exchange,提问作者samh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 17:34:55