Нужно решить проблему с кешем запросов - PullRequest
2 голосов
/ 10 августа 2010

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

import org.hibernate.*;

public class JournalService {    
    private static Object journalLock = new Object();    
    private Session session;

    public JournalService(Session session) {
        this.session = session;
    }

    public void insertJournalEntry(JournalEntry journalEntry) {
        Set<PostEntry> entries = journalEntry.getEntries();

        double total = 0;

        for (PostEntry entry : entries) {
            total += entry.getAmount();
        }

        if(total != 0)
            throw new InvalidParameterException("Journal entry is invalid. The sum of all entries must be zero.");

        Criteria criteria = session.createCriteria(PostEntry.class);
        criteria.setMaxResults(1);
        criteria.addOrder(Order.desc("id"));
        //here I add some other criteria
        synchronized(journalLock) {            
            PostEntry lastEntry = criteria.uniqueResult();
            long currentId = lastEntry.getId();

            for (PostEntry entry : entries) {
                entry.setId(currentId++)
                session.save(entry);
            }            
            session.save(journalEntry);
        }
    }
}

В двух словах, срок службы этой службы связан с текущим httprequestуправляется пружинным контейнером, кроме того, я проверяю, что вся транзакция фиксируется в конце запроса.Синхронизированный блок позаботится о любом параллелизме, поэтому в последовательности идентификаторов не будет пробелов.Большая проблема здесь - это дополнительные издержки доступа к базе данных для выбора последней вставленной записи, которая соответствует определенным критериям.Я не хочу, чтобы это произошло, поэтому я предполагаю, что решение здесь заключается в использовании кэша, который будет хранить последнюю вставленную запись при первом ее выборе, поэтому для создания идентификатора не требуется доступ к базе данных.Мой вопрос: есть ли какой-нибудь спящий способ решения этой проблемы?Я новичок в спящем режиме и слышал о кеше запросов, но я не уверен, как его использовать.Я не хочу, чтобы в кеше хранились все значения, которые я сохраняю с помощью этого сервиса, мне просто нужно, чтобы он сохранял последнюю вставленную запись, которая соответствует определенным критериям.Например, если я выполнил пять вставок, две из которых соответствуют одинаковым критериям «X», а остальные три соответствуют критерию «Y», в кэше будут храниться только два объекта (последний вставленный объект, который соответствует каждому критерию).Я мог бы легко реализовать это сам, но я бы предпочел использовать решение, которое интегрируется с Hibernate API.

1 Ответ

1 голос
/ 10 августа 2010

Кэширование лучше подходит для хранения часто используемых , но редко изменяемых объектов . что это не то, что вы пытаетесь сделать. Вы можете использовать сериализуемую транзакцию, которая предотвращает потерянные обновления и несогласованные чтения , чего вы пытаетесь избежать. Но вы должны иметь в виду его накладные расходы.

// Hibernate Transaction isolation level settings
// Serializable isolation level
hibernate.connection.isolation=8

Вот что говорит SessionFactory API:

Поведение SessionFactory контролируется свойствами, предоставленными во время конфигурации . Эти свойства определены в среде.

В качестве обходного пути вы можете установить два отдельных SessionFactory, где один из них сериализуем, как показано выше.

Поскольку вы извлекаете последнюю вставленную сущность PostEntry, я думаю, что пессимистическая блокировка не применяется должным образом, потому что ваша база данных просто блокирует извлеченную PostEntry.

...