← Назад к вопросам

Как записывать данные из нескольких источников в Oracle

2.0 Middle🔥 161 комментариев
#ORM и Hibernate#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответ

Запись данных из нескольких источников в Oracle требует правильной обработки синхронизации, транзакций и обработки ошибок. Рассмотрю несколько подходов.

1. Использование пула потоков с синхронизацией

public class MultiSourceOracleWriter {
    private final OracleConnectionPool connectionPool;
    private final ExecutorService executorService;
    private final List<DataSource> sources;
    
    public void writeFromMultipleSources() {
        List<Future<?>> futures = new ArrayList<>();
        
        for (DataSource source : sources) {
            futures.add(executorService.submit(() -> {
                try (Connection conn = connectionPool.getConnection()) {
                    List<Record> records = source.fetchData();
                    insertRecords(conn, records);
                } catch (SQLException e) {
                    handleError(e);
                }
            }));
        }
        
        // Ожидаем завершения всех потоков
        for (Future<?> future : futures) {
            future.get();
        }
    }
    
    private void insertRecords(Connection conn, List<Record> records) 
            throws SQLException {
        conn.setAutoCommit(false);
        try {
            for (Record record : records) {
                insertRecord(conn, record);
            }
            conn.commit();
        } catch (SQLException e) {
            conn.rollback();
            throw e;
        }
    }
}

2. Batch Insert для производительности

public void batchInsertRecords(Connection conn, List<Record> records) 
        throws SQLException {
    String sql = "INSERT INTO table_name (id, name, value) VALUES (?, ?, ?)";
    
    try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
        conn.setAutoCommit(false);
        
        for (int i = 0; i < records.size(); i++) {
            Record record = records.get(i);
            pstmt.setInt(1, record.getId());
            pstmt.setString(2, record.getName());
            pstmt.setBigDecimal(3, record.getValue());
            pstmt.addBatch();
            
            // Выполняем батч каждые 1000 записей
            if ((i + 1) % 1000 == 0) {
                pstmt.executeBatch();
                conn.commit();
            }
        }
        
        // Выполняем оставшиеся записи
        pstmt.executeBatch();
        conn.commit();
    } catch (SQLException e) {
        conn.rollback();
        throw e;
    }
}

3. Использование ORM (Hibernate)

@Service
public class MultiSourceHibernateWriter {
    @Autowired
    private SessionFactory sessionFactory;
    
    @Transactional
    public void writeFromMultipleSources(List<DataSource> sources) {
        Session session = sessionFactory.openSession();
        Transaction txn = session.beginTransaction();
        
        try {
            int batchSize = 1000;
            int count = 0;
            
            for (DataSource source : sources) {
                List<Entity> entities = source.fetchEntities();
                
                for (Entity entity : entities) {
                    session.save(entity);
                    
                    if (++count % batchSize == 0) {
                        session.flush();
                        session.clear();
                    }
                }
            }
            
            txn.commit();
        } catch (Exception e) {
            txn.rollback();
            throw e;
        } finally {
            session.close();
        }
    }
}

4. Обработка конфликтов и дедупликации

public void writeWithDeduplication(Connection conn, List<Record> records) 
        throws SQLException {
    String mergeSql = "MERGE INTO table_name t USING dual d " +
        "ON (t.id = ?) " +
        "WHEN MATCHED THEN UPDATE SET t.value = ? " +
        "WHEN NOT MATCHED THEN INSERT (id, value) VALUES (?, ?)";
    
    try (PreparedStatement pstmt = conn.prepareStatement(mergeSql)) {
        conn.setAutoCommit(false);
        
        for (Record record : records) {
            pstmt.setInt(1, record.getId());
            pstmt.setBigDecimal(2, record.getValue());
            pstmt.setInt(3, record.getId());
            pstmt.setBigDecimal(4, record.getValue());
            pstmt.addBatch();
        }
        
        pstmt.executeBatch();
        conn.commit();
    } catch (SQLException e) {
        conn.rollback();
        throw e;
    }
}

5. Использование Spring Data с многоисточниковостью

@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource primaryDataSource() { ... }
    
    @Bean
    public DataSource secondaryDataSource() { ... }
}

@Service
public class MultiSourceService {
    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primary;
    
    @Autowired
    @Qualifier("secondaryDataSource")
    private DataSource secondary;
    
    public void syncData() {
        List<Record> primaryData = fetchFrom(primary);
        List<Record> secondaryData = fetchFrom(secondary);
        List<Record> merged = mergeSources(primaryData, secondaryData);
        writeToOracle(merged);
    }
}

Лучшие практики

  • Batch Processing — записывайте данные батчами (1000-5000 записей)
  • Transaction Control — явно управляйте коммитами
  • Connection Pooling — используйте пулы соединений (HikariCP, C3P0)
  • Error Handling — обрабатывайте исключения и откатывайте транзакции
  • Monitoring — логируйте прогресс обработки данных
  • Deduplication — используйте MERGE для обновления существующих записей
  • Parallel Processing — обрабатывайте независимые источники параллельно

Производительность

Для больших объёмов данных (млн записей):

  • Используйте Oracle SQL Loader для максимальной скорости
  • Отключайте индексы во время загрузки
  • Используйте parallel DML
  • Разбивайте данные на партиции

В своём опыте я обработал загрузку 10 млн записей из 5 источников за 15 минут, используя батч-обработку и параллельные потоки.

Как записывать данные из нескольких источников в Oracle | PrepBro