public class User {
private List<Achievement> achievements;
get...
set...
}
public class Achievement {
private User user;
private Date createDate;
private DicAchievementType type;//справочник типов достижений
get...
set...
}
<bag name="achievements" inverse="true" cascade="all,delete-orphan" order-by="CREATE_DATE">
<key column="user_id"/>
<one-to-many class="Achievement"/>
</bag>
<many-to-one name="user" column="user_id" class="User"/>
<many-to-one name="type" column="achievement_type_id" class="DicAchievementType"/>
когда первая копия create_task считала данные,создала поток но еще не изменила статус записи, а вторая копия уже считала данныеЛично я уже много лет в таких случаях использую конструкцию SELECT ... FOR UPDATE - т.е. считывание с одновременной блокировкой, которое осуществляется в пределах открытой транзакции. Первый поток считывает запись и блокирует ее на уровне СУБД. При этом любой другой поток(и), попытавшийся считать запись также с модификатором FOR UPDATE будет ожидать своей очереди до тех пор, пока первый не завершит транзакцию (изменив при этом статус обработки). Только после этого следующий поток продолжит исполнение, и завершит операцию чтения. При этом надо не забыть проверить статус - если после захвата блокировки мы видим, что статус "обработано", то текущий поток "опоздал" и должен завершиться без дальнейшей обработки записи.
SELECT books.title,
GROUP_CONCAT(distinct CONCAT(authors.surname, ' ', authors.name) SEPARATOR ', ') as autors,
GROUP_CONCAT(distinct topics.title ORDER BY topics.title ASC SEPARATOR ', ') as titles
FROM books
LEFT JOIN book_author ON book_author.book_id = books.id
LEFT JOIN book_topic ON book_topic.book_id = books.id
LEFT JOIN authors ON book_author.author_id = authors.id
LEFT JOIN topics ON book_topic.topic_id = topics.id
group by books.id
CREATE TRIGGER wc_terms_unique_slug
BEFORE INSERT ON wc_terms FOR EACH ROW
BEGIN
declare
countDoubles int;
select count(*) into @countDoubles from wc_terms
where slug = NEW.slug or slug REGEXP CONCAT('(^', NEW.slug, ')([\-])([0-9]+)$');
if(@countDoubles > 0) then
SET NEW.slug = CONCAT_WS('-', NEW.slug, @countDoubles + 1);
end if;
END;
Способы хранения и чтения больших объемов данныхЭто именно то, ради чего и разрабатываются СУБД, и именно их и следует использовать.
Единственным приемлемым на данный момент способом хранения и работы с данными выбрал для себя XML-файлыНепонятно, причем тут вообще XML. Стандарт разрабатывался для унификации форматов при обмене информацией, с уклоном в человекочитаемость, в связи с чем избыточен, ресурсоемок и абсолютно не приспособлен для оптимального хранения данных. Даже если решили велосипед изобретать, то XML, пожалуй, худший из всех возможных вариантов. Тогда уж сливайте все в файл с разделителями и пишите собственные механизмы сохранения и выборки. Работать будет быстрее, чем XML, и ресурсов потребует во много раз меньше. При этом, что XML, что файлы с разделителями, что угодно — если вы не используете СУБД для "хранения и чтения больших объемов данных", то с 90% вероятностью можно предположить, что вы делаете что-то не так (если только вы не Гугл, конечно).
Да и сервер нагружать такими процедурами нельзя, так как работают с ним порядка 150 устройств с этим приложением. Представьте, сколько ему придется в сутки делать таких пачек инсерт-запросов, если для каждого их по 10-30 тысяч и по 3-5 раз в деньБольшинство современных СУБД, будучи установлены на средний современный сервер, с легкостью проглотят пару миллионов инсертов в сутки. Да что там в сутки, буквально позавчера у меня Oracle за час отработал 15 млн инсертов в таблицу с тремя десятками полей, причем в тестовом окружении.
на планшете…… по 10-30 тысяч и по 3-5 раз в деньЕсли это планшет, значит данные генерирует пользователь, а не какой-нибудь автоматизированный датчик. Тут вопрос, что же там такого может нагенерить пользователь? Может вам следует пересмотреть архитектуру приложения? Или нормализовать сохраняемые данные? Это я так, на всякий случай спрашиваю, а то мало ли… У вас ведь грамотный архитектор на проекте есть, да?