Как управлять транзакцией (которая включает в себя File IO), когда IOException выбрасывается из метода close file - PullRequest
6 голосов
/ 09 марта 2011

Я недавно начал использовать диспетчер транзакций источника данных Spring. У меня сейчас проблема. Моя транзакция включает в себя обновления таблицы БД и операцию записи в файл.

Работает нормально, но у меня есть некоторые сомнения по поводу файлового ввода / вывода. Как вы видите ниже, я настроил методы openFile и closeFile для моего bean-компонента как init-метод и destroy-метод соответственно, что, в свою очередь, обеспечивает вызовы этих методов точно так же, как constuructor и destructor. Если файл не закрыт должным образом, возможно, некоторые записи не были успешно записаны в файл output.txt, что означает, что я также не смог правильно обработать управление транзакциями.

Однако я бы хотел откатить те обновления БД, которые не были добавлены в плоский файл. С моим решением кажется невозможным добавить метод fileClose к транзакции. Кто-нибудь знает, как правильно выполнить это желаемое действие?

Любые предложения будут с благодарностью

<!--XML CONFIGURATION -->
<bean id="myFileWriter" class="com.job.step.ItemFileWriter"  init-method="openFile" destroy-method="closeFile">
    <property name="jdbcTemplate" ref="jdbcTemplateProduct"/>   
</bean> 

public class ItemFileWriter implements ItemWriter<Item> {
private static final Logger log = Logger.getLogger(ItemFileWriter.class);   
private BufferedWriter bw = null;
public void openFile() throws IOException {
    try {
        bw = new BufferedWriter(new FileWriter("C:\\output.txt"));
    } catch (IOException e) {           
        //log.error(e);
        throw e;
    }       
}
public void closeFile() throws IOException {
    if (bw != null) {
        try {
            bw.close();
        } catch (IOException e) {
            log.error(e);
            throw e;
        }
    }
}

@Transactional(rollbackFor = IOException.class)
public void write(List<? extends Item> itemList) throws IOException 
{               
    for (Iterator<? extends Item> iterator = itemList.iterator(); iterator.hasNext();) {
        Item item = (Item) iterator.next();

        String updateRtlnOutbound = "UPDATE SAMPLESCHEMA.SAMPLETABLE SET STATUS='TRANSFERRED' WHERE ID = ?";
        jdbcTemplate.update(updateRtlnOutbound, new Object[]{item.getID()});

        String item = String.format("%09d\n", item.customerNumber);
        bw.write(item);
    }                           
}
}   

Ответы [ 2 ]

4 голосов
/ 09 марта 2011

Вообще говоря, файловый ввод-вывод не является транзакционным (за исключением некоторых специфических для ОС функций).

Итак, лучшее, что вы можете сделать, - это переместить операцию открытия и закрытия к методу write(), чтобывыполнить их внутри транзакции и откатить транзакцию, если закрытие не удалось.

Обратите внимание, однако, что вы не можете откатить файловый ввод-вывод в случае отката транзакции, так что при некоторых обстоятельствах вы можете получить правильный файлс элементами, тогда как в базе данных эти элементы не помечены как TRANSFERRED.

. Чтобы решить эту проблему, вы можете попробовать использовать низкоуровневую поддержку управления транзакциями и попытаться удалить файл.в случае отката, но я думаю, что он все еще не может обеспечить сильные гарантии согласованности:

@Transactional(rollbackFor = IOException.class)
public void write(List<? extends Item> itemList) throws IOException 
{                
    openFile();
    TransactionSynchronizationManager().registerSynchronization(new TransactionSynchronizationAdapter() {
        public void afterCompletion(int status) {
            if (status = STATUS_ROLLED_BACK) {
                // try to delete the file
            }
        }
    });

    try {
        ...
    } finally {
        closeFile();                        
    }
}
2 голосов
/ 10 февраля 2012

Вы выполняете операции над двумя разными системами: файловой системой и базой данных. Как правило, транзакции XA позволяют нам легко объединять различные транзакционные системы в одну транзакцию.

Большинство баз данных могут быть созданы для участия в транзакциях XA. Для файловой системы вы можете использовать XADisk для включения XA. Если вы включите XA как для базы данных (с помощью правильной настройки источника данных), так и для файловой системы (с помощью xadisk), вы можете быть уверены, что операции как с файлом, так и с базой данных зафиксированы, или оба они отката.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...