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
相关产品推荐
相关产品推荐

