hibernate 批量插入的测试

Hibernate 批量插入的测试:
最近在项目中做了一个充值卡的模块,用到了批量插入:我一开始用hibernate插入五十万条数据:选说一下我的记算机配置:
内存:1G,CPU:Pentium(R) 4 CPU 3.20GHz. 配置应该算是过时的了,
我的数据库是:oracle10G,数据库服务器在外地,我测试插入到十万条的时候用了二十五分钟,后来我把程序放到外网服务器:配置:酷睿2代 2.0,4G内存,
插入十万条是五分钟,速试是大大的提升,但是我还是感觉有点慢,后来我用JDBC的批处理:还是在我本地插入:10万条用时:不到1分钟,如果放到外网服务器就更快。
下面贴一下我的代码:hibernate批量导入代码:(只是部分代码,不能运行。)
 public boolean addCardList( final SysCardImport sysCardImport,final Date date){
  boolean bool =(Boolean) hibernateTemplate.execute(new HibernateCallback() {
   public Object doInHibernate(Session session) throws HibernateException, SQLException {
   boolean flag=true;
   try {  
    int i=0;
    
    String temp=sysCardImport.getCardSymbol();  //卡代号
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
    //取得充值卡类型值和面额值
    SysPublictype cardType = (SysPublictype)session.get(SysPublictype.class, sysCardImport.getCardType());
    SysPublictype cardMoney = (SysPublictype)session.get(SysPublictype.class, sysCardImport.getCardMoney());
    temp+=cardType.getVchvalue();
    temp+=cardMoney.getVchvalue();
    
    String templeng[]=sysCardImport.getPasswordChar();
    for(int len=0;len<templeng.length;len++){   //循环遍历充值卡加密字符串
     String temparray[]=templeng[len].split(":");     
     String temps=temp+temparray[0]; //加密字符串代码
     long cardnum=0;
     List list= session.createQuery(" from SysCard t where t.vchcode like ? order by t.vchcode desc")
        .setString(0, ""+temps+"%").list();
     if(list.size()>0){
      SysCard card=(SysCard)list.get(0);
      cardnum = Long.valueOf(card.getVchcode().substring(10));
     }
     for(int num=0;num<sysCardImport.getCardAmount();num++){ //生成充值卡卡号
      String cardroand="000000000"+(++cardnum);
      cardroand=cardroand.substring(cardroand.length()-10);     
      SysCard sysCard=new SysCard();
      SysPassword sysPassword=new SysPassword();
      
      String password=BJFYSystemUtil.getRandomString(sysCardImport.getCardPasswordLength(),2);
      
      sysCard.setVchcode(temps+cardroand);
      sysCard.setNummoney(sysCardImport.getCardMoneys());
      sysCard.setCstate("10");
      sysCard.setDatcreate(date);
      sysCard.setDatavailability(sdf.parse(sysCardImport.getCardDate()));
      sysCard.setVchremark(sysCardImport.getCardRemark());
      sysCard.setVchpassword(BJFYSystemUtil.getMD5(password+temparray[1]));
      sysCard.setNumscale(sysCardImport.getCardScale());
      sysCard.setVarkey(temparray[1]);
      sysCard.setVchtype(cardType.getId());
      
      sysPassword.setVchcode(temps+cardroand);
      sysPassword.setVchpassword(password);
      sysPassword.setVchpasschar(temparray[1]);
      session.save(sysPassword);
      session.save(sysCard);
      if ((i + 1) % 1000 == 0) {
       session.flush();
       session.clear();
      }
      i++;
     }
    }
    
   } catch (Exception e) {
    log.error(e);
    e.printStackTrace();
    flag = false;
   }
   return flag;
  }
 });
  return bool;
 }
下面是JDBC批处理的代码:
public boolean addCardListByJdbc( final SysCardImport sysCardImport,final Date date){
   boolean flag=true;
   Connection con= this.hibernateTemplate.getSessionFactory().openSession().connection();
   PreparedStatement  stm=null;
   PreparedStatement  stm2=null;
   try {  
    int i=0;
    String temp=sysCardImport.getCardSymbol();  //卡代号
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
    //取得充值卡类型值和面额值
    SysPublictype cardType = (SysPublictype)hibernateTemplate.get(SysPublictype.class, sysCardImport.getCardType());
    SysPublictype cardMoney = (SysPublictype)hibernateTemplate.get(SysPublictype.class, sysCardImport.getCardMoney());
    temp+=cardType.getVchvalue();
    temp+=cardMoney.getVchvalue();
    
    con.setAutoCommit(false);
          
    stm=con.prepareStatement("insert into sys_card values(?,?,?,?,?,?,?,?,?,?)");
    stm2=con.prepareStatement("insert into sys_password values(?,?,?)");
    
    String templeng[]=sysCardImport.getPasswordChar();    
    for(int len=0;len<templeng.length;len++){   //循环遍历充值卡加密字符串
     String temparray[]=templeng[len].split(":");     
     String temps=temp+temparray[0]; //加密字符串代码
     long cardnum=0;
     List list= hibernateTemplate.find(" from SysCard t where t.vchcode like ? order by t.vchcode desc", temps+"%");
        
     if(list.size()>0){
      SysCard card=(SysCard)list.get(0);
      cardnum = Long.valueOf(card.getVchcode().substring(10));
     }
     
     for(int num=0;num<sysCardImport.getCardAmount();num++){ //生成充值卡卡号
      String cardroand="000000000"+(++cardnum);
      cardroand=cardroand.substring(cardroand.length()-10);     
      SysCard sysCard=new SysCard();
      SysPassword sysPassword=new SysPassword();      
      String password=BJFYSystemUtil.getRandomString(sysCardImport.getCardPasswordLength(),2);
      
      
      
      
      stm.setString(1,temps+cardroand);
      stm.setString(2, BJFYSystemUtil.getMD5(password+temparray[1]));
      stm.setLong(3, sysCardImport.getCardMoneys());
      stm.setLong(4, sysCardImport.getCardScale());
      stm.setString(5,cardType.getId() );
      stm.setDate(6, new java.sql.Date(System.currentTimeMillis()));
      stm.setDate(7, new java.sql.Date(date.getTime()));
      stm.setString(8, "10");
      stm.setString(9, temparray[1]);
      stm.setString(10, sysCardImport.getCardRemark());
      stm.addBatch();

      stm2.setString(1, temps+cardroand);
      stm2.setString(2, password);
      stm2.setString(3,temparray[1]);
      stm2.addBatch();
      if ((i + 1) % 1000 == 0) {
       stm.executeBatch();
       stm2.executeBatch();
       con.commit();
      }
      i++;
     }
    }
    
    if(stm!=null) {
     stm.executeBatch();
     stm2.executeBatch();
     con.commit();
    }
    
    
   } catch (Exception e) {
    log.error(e);
    e.printStackTrace();
    flag = false;
   }finally{
    try {
     con.close();
     stm=null;
     stm2=null;
    } catch (SQLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    
   }
  
  
  return flag;
 }

综上所述,hibernate的批量更新和插入要创建和销毁大量的对象,尤其是带有复杂业务逻辑的,所以本人建议在大批量导入和更新时,最好使用JDBC的批处理.在批处理上hibernate和jdbc Batch不是一个等级的。

<think>好的,我现在需要帮用户解决在Spring Boot中配置多数据源并实现Hibernate批量插入的问题。首先,我得回忆一下多数据源的配置方法。记得在Spring Boot中,通常需要为每个数据源创建独立的配置类,定义不同的DataSource、EntityManagerFactory和TransactionManager。用户提到的Hibernate批量插入,可能需要设置Hibernate的相关属性,比如hibernate.jdbc.batch_size和hibernate.order_inserts等。 接下来,我需要查看用户提供的引用内容,看看是否有相关的配置可以参考。引用[1]和[3]中提到了JDBC的配置,包括依赖项和application.yml中的基本数据源配置,但都是单数据源的例子。用户的需求是多数据源,所以需要扩展这些配置。引用[4]中的Redis配置虽然不同,但展示了如何使用@Configuration和@Bean来定义多个Bean,这可能对多数据源配置有帮助。 首先,多数据源的配置需要排除Spring Boot的自动配置,通常使用@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})。然后为每个数据源定义配置类,比如PrimaryDataSourceConfig和SecondaryDataSourceConfig。每个配置类需要提供DataSource、EntityManagerFactory和TransactionManager的Bean,并指定不同的包扫描路径,以避免冲突。 然后是关于Hibernate批量插入的配置。在application.yml中,需要为每个数据源设置Hibernate属性,如jdbc.batch_size和order_inserts。这些设置可以优化批量插入的性能,减少数据库交互次数。同时,可能需要在实体类上使用@DynamicInsert和@DynamicUpdate来进一步优化。 用户可能还需要在代码中使用这两个数据源,比如在Service层通过@Transactional注解指定使用哪个事务管理器。此外,需要注意事务管理的隔离,避免跨数据源的事务问题,可能需要使用分布式事务解决方案,但基础配置中可能暂时不需要。 需要检查用户提供的引用中是否有关于多数据源的部分。引用[3]提到了Docker中MySQL的配置,但可能不直接相关。引用[4]中的Java配置示例展示了如何根据条件配置不同的RedisTemplate,这可能启发多数据源的条件化配置,但主要还是要依靠Spring Boot的多数据源标准配置方法。 最后,确保代码示例的正确性,比如配置类的注解、Bean的定义方法,以及application.yml中的属性设置。需要提醒用户配置多个数据源的url、username、password等信息,并注意包扫描路径的不同,避免实体和Repository的冲突。同时,测试批量插入时,建议使用原生SQLHibernate批量操作,并启用相关配置参数。</think>在Spring Boot中配置多数据源并实现Hibernate批量插入功能,可通过以下步骤实现: --- ### 一、多数据源配置 #### 1. 排除自动配置 ```java @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class Application {} ``` #### 2. 主数据源配置 ```java @Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = "com.example.primary.repository", entityManagerFactoryRef = "primaryEntityManager", transactionManagerRef = "primaryTransactionManager" ) public class PrimaryDataSourceConfig { @Primary @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Primary @Bean(name = "primaryEntityManager") public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("primaryDataSource") DataSource dataSource ) { return builder .dataSource(dataSource) .packages("com.example.primary.entity") .persistenceUnit("primary") .properties(hibernateProperties()) .build(); } @Primary @Bean(name = "primaryTransactionManager") public PlatformTransactionManager transactionManager( @Qualifier("primaryEntityManager") EntityManagerFactory entityManagerFactory ) { return new JpaTransactionManager(entityManagerFactory); } private Map<String, Object> hibernateProperties() { Map<String, Object> props = new HashMap<>(); props.put("hibernate.jdbc.batch_size", 50); // 批量插入优化 props.put("hibernate.order_inserts", true); return props; } } ``` #### 3. 次数据源配置 ```java @Configuration @EnableTransactionManagement @EnableJpaRepositories( basePackages = "com.example.secondary.repository", entityManagerFactoryRef = "secondaryEntityManager", transactionManagerRef = "secondaryTransactionManager" ) public class SecondaryDataSourceConfig { @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryEntityManager") public LocalContainerEntityManagerFactoryBean entityManagerFactory( EntityManagerFactoryBuilder builder, @Qualifier("secondaryDataSource") DataSource dataSource ) { return builder .dataSource(dataSource) .packages("com.example.secondary.entity") .persistenceUnit("secondary") .properties(hibernateProperties()) .build(); } @Bean(name = "secondaryTransactionManager") public PlatformTransactionManager transactionManager( @Qualifier("secondaryEntityManager") EntityManagerFactory entityManagerFactory ) { return new JpaTransactionManager(entityManagerFactory); } private Map<String, Object> hibernateProperties() { Map<String, Object> props = new HashMap<>(); props.put("hibernate.jdbc.batch_size", 50); props.put("hibernate.order_updates", true); return props; } } ``` --- ### 二、application.yml配置 ```yaml spring: datasource: primary: url: jdbc:mysql://192.168.15.22:3306/primary_db?useSSL=false&rewriteBatchedStatements=true username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver secondary: url: jdbc:mysql://192.168.15.23:3306/secondary_db?useSSL=false&rewriteBatchedStatements=true username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver jpa: properties: hibernate: dialect: org.hibernate.dialect.MySQL8Dialect jdbc: batch_size: 50 batch_versioned_data: true ``` --- ### 三、批量插入实现 #### 1. 在实体类添加优化注解 ```java @Entity @DynamicInsert // 仅插入非空字段 @DynamicUpdate @Table(name = "user") public class User { // 实体字段定义 } ``` #### 2. 服务层实现 ```java @Service public class BatchInsertService { @Transactional(transactionManager = "primaryTransactionManager") public void batchInsertPrimary(List<User> users) { for (User user : users) { entityManager.persist(user); } entityManager.flush(); entityManager.clear(); } @Transactional(transactionManager = "secondaryTransactionManager") public void batchInsertSecondary(List<Order> orders) { for (Order order : orders) { entityManager.persist(order); } entityManager.flush(); entityManager.clear(); } } ``` --- ### 四、关键优化点 1. **JDBC参数**: URL中添加`rewriteBatchedStatements=true`以启用MySQL批量插入优化[^3] 2. **Hibernate配置**: - `hibernate.jdbc.batch_size`: 控制每批次提交数量 - `hibernate.order_inserts`: 对插入操作排序以提升批量效率 3. **事务管理**: 使用`@Transactional`明确指定事务管理器 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值