HIbernate 批量插入或更新在 Spring Boot 中不起作用

Posted

技术标签:

【中文标题】HIbernate 批量插入或更新在 Spring Boot 中不起作用【英文标题】:HIbernate batch insert or update not working in spring boot 【发布时间】:2017-12-31 18:06:48 【问题描述】:

我需要在我的 mysql 数据库中进行批量插入(近 10000 次)。我正在使用 JPA/hibernate 和 spring boot。我从休眠文档中阅读了在休眠中执行批量插入/更新,我认为我的代码无法正常工作,因为它是按顺序插入休眠查询而不是在批量插入中执行它们。下面是我的代码。我错过了什么吗?

这是我的数据源配置。

@Component
public class Datasource 

    @Autowired 
    EnvConfiguration configuration;
    
    private static final Logger logger = LoggerFactory.getLogger(Datasource.class);
    
    @Bean
    public DataSource dataSource()
        logger.info("DataSource Bean creation...");
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(configuration.getDBDriver());
        dataSource.setUrl("jdbc:mysql://"+configuration.getDBIp()+":"+configuration.getDBPort()+"/"+configuration.getDBName()+"?autoReconnect=true&useSSL=false");
        dataSource.setUsername(configuration.getDBUser());
        dataSource.setPassword(configuration.getDBPass().trim());
        return dataSource;
    
    @Bean
    public HibernateJpaSessionFactoryBean sessionFactory() 
        return new HibernateJpaSessionFactoryBean();
    

我的角色域的代码

//Role.java

    @Entity
    @Table(name = "Role",uniqueConstraints = @UniqueConstraint(
            columnNames =  "roleName"))
    public class Role 
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long roleId;
        @NotNull
        private String roleName;
        public Role()
    
        public Role(String roleName)
            this.roleName = roleName;
        
    
        public Long getRoleId() 
            return roleId;
        
    
        public void setRoleId(Long roleId) 
            this.roleId = roleId;
        
    
        public String getRoleName() 
            return roleName;
        
    
        public void setRoleName(String roleName) 
            this.roleName = roleName;
        
    
    
    

以下是我的服务代码。在这里,我手动刷新会话。我添加了一个睡眠功能,以查找插入查询是一个一个执行,还是像 JDBC 批处理那样以 10 个为一组执行。

@Service
public class RoleService
    
    
    @Autowired
    private SessionFactory factory;
    
    @Autowired
    private DataSource source;

    private static final Logger logger =  LoggerFactory.getLogger(WalletService.class);


    public void insertRole(Collection<RegisterWallet> walletMetaCollection)

            if(factory==null)
                    System.out.println("factory is null");
                else
                    System.out.println("factory is working");
                    Session session = factory.openSession();
                    Transaction tx = session.beginTransaction();
        
                    for ( int i=0; i<100000; i++ ) 
                    Role role=new Role(""+i);
                    session.persist(role);
                System.out.println("this is the role id "+role.getRoleId());
   
                    try 
                        Thread.sleep(1000);
                     catch (InterruptedException e)
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    
   

 

            if ( i % 10 == 0 )  //20, same as the JDBC batch size
  
                //flush a batch of inserts and release memory:
                    session.flush();
                    session.clear();
                
            
  

      
                    tx.commit();
                    session.close();
                   
               
        

根据我对批处理操作的理解,应该一次插入 10 个角色,减少使用的 jdbc 往返次数。但是上面代码的输出是出乎意料的。每个 session.persist(..) 调用执行一次插入。

//This is log of the above code.


     Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 14
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 15
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 16
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 17
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 18
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 19
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 20
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 21
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 22
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 23
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 24
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 25
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 26
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 27
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 28
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 29
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 30
    Hibernate: insert into role (active, role_description, role_name) values (?, ?, ?)
    this is the role id 31
    </pre>

-------------------------------------------------------------

以下是我的 application.properties 配置

spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
spring.jpa.properties.hibernate.jdbc.batch_size=10

我错过了什么吗?

请帮忙。

【问题讨论】:

可能会有帮助:***.com/a/35794220/4754790 Thanx M.Deinum 确实很有帮助。再次感谢。你使我免于许多麻烦。自从过去 3 天以来,我一直对这个问题感到困惑。干杯快乐编码 【参考方案1】:

您没有遗漏任何东西。您的输出很正常。您可以通过此链接获取更多信息:[1]http://www.dineshonjava.com/2012/06/hibernate-batch-processing_10.html

【讨论】:

感谢 Anzor 的回复,我在您发布的链接中阅读了教程,但即使在该教程中,休眠也是按顺序插入而不是批量插入。但是该链接很有帮助,因为它解释了在休眠中批量更新用于清除会话缓存和批量执行类似的 sql 查询的两件事。它只提供第一个功能而不是第二个。 尝试将这两行添加到您的应用程序属性文件中。 spring.jpa.properties.hibernate.order_inserts=true spring.jpa.properties.hibernate.order_updates=true 如果有人遇到同样的问题,解决方案是将主键的生成类型从Identity类型表更改为Generation类型表或通过setter方法手动添加主键,只有这样你才能获得批量插入/更新的好处。

以上是关于HIbernate 批量插入或更新在 Spring Boot 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用 Hibernate 和 Spring 进行批量插入

Spring Data JPA HIbernate 批量插入速度较慢

Spring JPA - Hibernate:批量插入执行太多选择 nextval('sequence')

批量更新从更新返回了意外的行数(Spring/Hibernate)

Spring - 无法使用JPA更新或插入任何值到MySQL

Spring Data JPA - 并发批量插入/更新