2017-01-17 7 views
1

Созданное весеннее пакетное задание для чтения из файла и записи в БД, программа принимает динамические столбцы, то есть может использоваться для любой таблицы. Утилит работает нормально, но для загрузки 1 миллиона записей требуется более 1 часа. Пожалуйста, помогите исправить это!Проблема с производительностью: Слишком длинное задание на весу для вставки строк в БД

<bean id="FileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" 
       scope="step"> 
       <!-- Read a csv file --> 
       <property name="resource" 
        value="file:#{stepExecutionContext['file']}" /> 
       <property name="lineMapper"> 
        <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"> 
         <!-- split it --> 
         <property name="lineTokenizer"> 
          <bean class="com.mypack.LineTokenizer"> 
           <property name="delimiter" value="|" /> 
           <property name="tableName" value="#{stepExecutionContext['tablename']}" /> 
           <property name="dataSource" ref="dtsoruce" /> 
          </bean> 
         </property> 
         <property name="fieldSetMapper" ref="mapper" /> 
        </bean> 
       </property> 

       <property name="linesToSkip" value="0" /> 
      </bean> 

      <bean id="mapper" class="com.mypack.MapFieldSetMapper" scope="step"/> 

     <bean id="DbItemWriter" class="com.mypack.Filewrtr" scope="step"> 
       <property name="dataSource" ref="dtsoruce" /> 
       <property name="tableName" value="#{stepExecutionContext['tablename']}" /> 
      </bean> 
     </beans> 

     public class LineTokenizer extends DelimitedLineTokenizer implements InitializingBean { 

      private String columnNames = "SELECT COLUMN_NAME FROM ALL_TAB_COLS WHERE TABLE_NAME ="; 
      private String tableName; 
      private JdbcTemplate jdbcTemplate; 

      protected JdbcTemplate createJdbcTemplate(DataSource dataSource) { 
       return new JdbcTemplate(dataSource); 
      } 
      public final void setDataSource(DataSource dataSource) { 
       if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) { 
        this.jdbcTemplate = createJdbcTemplate(dataSource); 
        initTemplateConfig(); 
       } 
      } 
      protected void initTemplateConfig() { 
      } 
      public final JdbcTemplate getJdbcTemplate() { 
        return this.jdbcTemplate; 
       } 

      public void afterPropertiesSet() throws Exception { 
       jdbcTemplate.execute("TRUNCATE TABLE "+tableName); 
       logger.debug("TABLE TRUNCATED SUCCESSFULLY :"+tableName); 
       String[] names; 
       int i=0; 
       List<Map<String,Object>> columns=jdbcTemplate.queryForList(columnNames+"'"+tableName+"' ORDER BY COLUMN_ID"); 
       names=new String[columns.size()]; 
       for(Map<String,Object> convert:columns){ 
        for(String key:convert.keySet()){ 
         names[i]=(String) convert.get(key); 
         i++; 
        } 
       } 
       this.names = names==null ? null : Arrays.asList(names).toArray(new String[names.length]); 
       logger.debug("FIELDS NAME => "+names); 
       Filewrtr.columnNames=names; 

      } 
     } 
     public class Filewrtr extends JdbcDaoSupport implements ItemWriter<Map<String, String>>{ 

      private String tableName; 
      private String sql; 
      private Object[] data; 
      public static String columnNames[]; 

      public void write(final List<? extends Map<String, String>> items) 
        throws Exception { 
       String columntype = "INSERT INTO " + tableName + "("; 
       String value = ") VALUES("; 
       int i = 0; 
       for (String key : columnNames) { 
        if (i != (columnNames.length - 1)) { 
         columntype = columntype + key + ","; 
         value = value + "?,"; 

     logger.info("column type"+columntype+"value"+value); 
        } else { 
         columntype = columntype + key; 
        } 
        i++; 
       } 

       sql = columntype + value + "?)"; 
       this.getJdbcTemplate().batchUpdate(sql, new BatchPreparedStatementSetter() { 
        public void setValues(PreparedStatement ps, int i) throws SQLException { 
         int j = 1; 
         for (String tradeColumn : columnNames) { 
          if(isValid(items.get(i).get(tradeColumn))) 
          { 
           SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); 
           try 
           { 
            Date time = df.parse(items.get(i).get(tradeColumn)); 

            ps.setDate(j, new java.sql.Date(time.getTime())); 
           }catch(Exception e) 
           { 
            ps.setTimestamp(j, null); 
           } 
          } 
          else 
          { 
            ps.setString(j , items.get(i).get(tradeColumn)); 

          } 
          j++; 
         } 
        } 
        public int getBatchSize() { 
         return items.size(); 
        } 
       }); 
      } 
     } 
+1

Профилируйте свой код, чтобы узнать, где узкое место? –

+0

Is LineTokenizer # afterPropertiesSet() выполняется один или несколько раз? Возможно, усечение занимает слишком много времени, и в этом случае вы можете использовать прослушиватель шагов –

+0

только один раз. и это не занимает много времени. –

ответ

0

Oracle предоставляет утилиту SQL Loader Express для загрузки CSV-файла без необходимости писать сложный код.

+0

Привет, bobC, мне нужно сделать это, используя Spring-пакет, его требование к проекту –

+0

Вы используете неправильный инструмент для работы. Используя правильный инструмент, вы сможете загружать за считанные секунды. Возможно, я помогу вам сделать некоторые предложения, чтобы сделать это немного быстрее; но что происходит, когда вы получаете файл с миллиардной строкой? Или 10 из них? Я бы посоветовал вам оспорить эти требования к проекту. – BobC

+0

мы уже сделали .. используя весеннюю партию .. но это для статических столбцов .. но это для динамических столбцов. Конечным пользователям известно только запустить весеннее пакетное задание –