#java #google-app-engine
#java #google-app-engine
Вопрос:
У меня есть довольно простое Java-приложение App Engine, в котором есть учетные записи, заказы и элементы заказа — ничего сумасшедшего.
Только за последние 12 часов я начал получать исключения из некоторого довольно простого кода, который добавляет заказы в учетные записи, а затем сохраняет их.
Я создал тривиальный тестовый сервлет для репликации проблемы, он выглядит следующим образом:
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String key = req.getParameter("key");
PersistenceManager pm = PMF.get().getPersistenceManager();
Account account = pm.getObjectById(Account.class, KeyFactory.stringToKey(key));
Order order = new Order();
order.setExternalOrderID("ASHLEY-TESTING");
Item item = new Item();
item.setSku("ASHLEY-WIDGET-A");
item.setQuantity(2);
Item item2 = new Item();
item2.setSku("ASHLEY-WIDGET-B");
item2.setQuantity(2);
order.addItem(item);
order.addItem(item2);
account.addOrder(order);
order.setAccount(account);
pm.makePersistent(order);
pm.close();
}
addOrder is implemented as a pretty standard lazy init:
public void addOrder(Order order) {
if (getOrders() == null) {
setOrders(new ArrayList<Order>());
}
getOrders().add(order);
}
The relevant parts of the entities:
@PersistenceCapable
public class Account {
//...
@Persistent(mappedBy="account")
@javax.jdo.annotations.Order(extensions = @Extension(vendorName="datanucleus", key="list-ordering", value="orderDate desc"))
private List<Order> orders;
//...
}
and the Order has an account field:
@Persistent
private Account account;
Этот код завершается ошибкой в account.addOrder()
строке. если она запускается непосредственно в браузере, она завершается с ошибкой DeadlineExceededException (через 30 секунд), и если я ставлю ее в очередь для запуска через очередь задач, она завершается с ошибкой DatastoreTimeoutException через минуту или две. В процессе используется слишком большая загрузка процессорного времени.
Я бы оценил, что в учетной записи будет менее 2000 дочерних элементов Orders, в каждом заказе будет 1-3 дочерних элемента OrderItem.
Мой вопрос в том, почему это внезапно начало давать сбой, если это сработало, чтобы добавить 1000 заказов, которые уже есть. И я пропустил что-то важное? нужно ли добавлять индексы? действительно ли хранилище данных может быть таким медленным? Я злоупотребляю этим, не должен ли я иметь дочерние отношения с таким количеством дочерних элементов — возможно, набор ключей был бы лучшим подходом?
Ответ №1:
На одном из слайдов Google App Engine упоминается, что для свойства list производительность хранилища данных будет низкой, если номер элемента больше «500». Этот слайд очень старый, я не уверен, что ограничение осталось прежним, но это может быть проблемой в вашем случае. И имеет смысл не хранить слишком много элементов в свойстве list. На этом слайде пользователю предлагается использовать класс extend для этой ситуации. Например:
class Orders:
Account account // the account these order belong to.
List<Order> orders // the orders, limit to 500 items
если у вас более 500 заказов, просто добавьте другой экземпляр Orders.
Ответ №2:
Я прекратил использовать GetOrders () в пользу интерфейса запроса, подобного этому:
Query query = pm.newQuery(Order.class);
query.setFilter("account == accountKey");
query.declareParameters(Key.class.getName() " accountKey");
query.setOrdering("orderDate desc");
query.setRange(0, numOrders);
И для добавления заказов в учетные записи я просто устанавливаю родительское свойство для нового заказа и сохраняю его, GAE обрабатывает создание ключа и связывает его с родительским.
order.setAccount(account);
pm.makePersistent(order);
Я получил несколько советов от GAE / J Group здесь:
http://groups.google.com/group/google-appengine-java/browse_thread/thread/6011d08025398254 #
Кроме того, предложение lucemia сработало бы, но я думаю, что управлять кодом сложнее.