Весенняя задача загрузки для обновления внешнего ключа в БД - PullRequest
2 голосов
/ 22 апреля 2019

Я работаю над REST API, используя Spring boot, который будет управлять аукционом предметов.

Пользователи, участвующие в аукционе, будут находиться в отдельной Таблице пользователей

Предметы, подлежащие аукциону, будут в Таблице Auction_items вместе с временем начала и окончания аукциона, ноль победителя, если аукцион все еще продолжается.

Все ставки, сделанные пользователями на соответствующие позиции, содержатся в Таблица предложений

Я уже пробовал разные способы (cron, fixedRate, fixedDelay) для планирования задачи, получил похожую ошибку для всех из них, Я подозреваю, что может быть проблема с БД, из-за которой это происходит.

Ниже приведены таблицы и соответствующий класс модели, а также интерфейс службы и хранилища.

ТАБЛИЦА ПОЛЬЗОВАТЕЛЕЙ:

CREATE TABLE USERS
(
USER_ID SERIAL,
NAME VARCHAR(200),
EMAIL VARCHAR(200),
PASSWORD VARCHAR(200),
PRIMARY KEY(USER_ID)
);

AUCTION_ITEMS TABLE:

CREATE TABLE AUCTION_ITEMS
(
ITEM_ID SERIAL,
ITEM_NAME VARCHAR(200),
ITEM_DESCRIPTION TEXT,
START_TIME TIMESTAMP,
END_TIME TIMESTAMP,
STARTING_AMOUNT INT,
WINNER INT,
PRIMARY KEY(ITEM_ID),
FOREIGN KEY(WINNER) REFERENCES USERS(USER_ID) ON DELETE CASCADE
);

TIDS TABLE:

CREATE TABLE BIDS
(
BID_ID SERIAL,
ITEM_ID INT,
USER_ID INT,
AMOUNT INT,
PRIMARY KEY(BID_ID),
FOREIGN KEY(ITEM_ID) REFERENCES AUCTION_ITEMS(ITEM_ID) ON DELETE 
CASCADE,
FOREIGN KEY(USER_ID) REFERENCES USERS(USER_ID) ON DELETE CASCADE
);

Ниже приведены классы моделей для вышеперечисленных таблиц:

User.java:

@Entity
@Table(name="USERS")
public class User {

@Id
private Integer user_id;
private String name;
private String email;
private String password;

//getter setter methods
}

Item.java:

@Entity
@Table(name="AUCTION_ITEMS")
public class Item {

@Id
private Integer item_id;
private String item_name;
private String item_description;
private Timestamp start_time;
private Timestamp end_time;
private int starting_amount;
@ManyToOne
@JoinColumn(name="winner")
private User user;

//getter setter methods
}

Bid.java:

@Entity
@Table(name="BIDS")
public class Bid {

@Id
private Integer bid_id;
@ManyToOne
@JoinColumn(name="item_id")
private Item item;
@ManyToOne
@JoinColumn(name="user_id")
private User user;
private int amount;
//getter setter nethods
}

Ниже приведен класс обслуживания, где я определяю метод scheduleTask () для запуска и расчета победителя Предмета, выставленного на аукцион после прохождения времени окончания аукциона:

ItemService.java:

@Service
public class ItemService {

    @Autowired
    private ItemRepository itemRepository;

    @Autowired
    private UserRepository userRepository;


    public List<Item> getAllItems(){
        return (List<Item>) itemRepository.findAll();
    }

    public Object getItem(Integer id) {
        Item i = itemRepository.findById(id).orElse(null);
        if(i.getUser()!=null) {
            return i.getUser();
        }
        else {
            //will be returning highest bid amount for that particular item
            return itemRepository.getMaxBid(id);
        }
    }

    @Scheduled(cron="20 36 17 * * ?")
    public void scheduledTask() {
        List<Item> listOfItems = (List<Item>)itemRepository.findAll();
        System.out.println("going to update DB");
        for(Item i : listOfItems) {
            Timestamp time = new Timestamp(System.currentTimeMillis());
            if(time.equals(i.getEnd_time()) || time.after(i.getEnd_time())) {
                if(i.getUser() == null) {
                    Integer item_id = i.getItem_id();
                    Integer winner_id = itemRepository.findWinner(item_id);
                    User u= userRepository.findById(winner_id).orElse(null);

                    i.setUser(u);
                    System.out.println("updated");
                }
            }
        }
    }

}

ItemRepository.java:

public interface ItemRepository extends CrudRepository<Item,Integer>{

@Query(value="select max(b.amount) from bids as b where b.item_id=?1", 
nativeQuery=true )
public Integer getMaxBid(Integer item_id);

@Query(value="select b.user_id from bids as b where b.item_id=?1 AND 
b.amount = (select max(amount) from bids);", nativeQuery=true)
public Integer findWinner(Integer id);

Ниже приведена ошибка, которую я получаю один раз, приходит время обновить данные в таблице:

2019-04-22 12: 55: 30.123 INFO 9100 --- [scheduling-1]> o.h.h.i.QueryTranslatorFactoryInitiator: HHH000397: Использование> ASTQueryTranslatorFactory собираюсь обновить БД 2019-04-22 12: 55: 30.464 ОШИБКА 9100 --- [scheduling-1]?> O.s.s.s.TaskUtils $ LoggingErrorHandler: В> запланированной задаче произошла непредвиденная ошибка.

org.springframework.dao.InvalidDataAccessApiUsageException:> org.hibernate.QueryException: позиционный параметр в стиле JPA не является целочисленным> порядковым; вложенным исключением является java.lang.IllegalArgumentException:> org.hibernate.QueryException: позиционный параметр в стиле JPA не был целым> порядковым at> org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExcepti> onIfPossible (EntityManagerFactoryUtils.java:373) ~ [spring-orm-> 5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPo> ssible (HibernateJpaDialect.java:255) ~ [spring-orm ->]> 5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExcepti> onIfPossible (AbstractEntityManagerFactoryBean.java:527) ~ [spring-orm-> 5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.dao.support.ChainedPersistenceExceptionTranslator.transla> teExceptionIfPossible (ChainedPersistenceExceptionTranslator.java:61) ~ [Пружинно-ТХ-5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.dao.support.DataAccessUtils.translateIfNeeded (DataAcce> ssUtils.java:242) ~ [spring-tx-5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.in> voke (PersistenceExceptionTranslationInterceptor.java:153) ~ [spring-tx-> 5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (Reflecti> veMethodInvocation.java:186) ~ [spring-aop-5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcess> или $ CrudMethodMetadataPopulatingMethodInterceptor.invoke (CrudMethodMetadataPos> -Processor.jEL.6.-2.1.6. РЕЛИЗ] at> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (Reflecti> veMethodInvocation.java:186) ~ [spring-aop-5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke (Expose> InvocationInterceptor.java:93) ~ [spring-aop-5.1.6.RELEASE.jar: 5.1.6.RELEASE]at> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (Reflecti> veMethodInvocation.java:186) ~ [spring-aop-5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.d.repository.core.support.SurroundingTransactionDetect> orMethodInterceptor.invoke (SurroundingTransactionDetectorMethodInterceptor.ja> va: 61) ~ [spring-data-commons-2.1.6.RELEASE.jar: 2.1.6.RELEASE] at> orgframework.ReflectiveMethodInvocation.proceed (Reflecti> veMethodInvocation.java:186) ~ [spring-aop-5.1.6.RELEASE.jar: 5.1.6.y.java:212) ~ [spring-aop-5.1.6.RELEASE.jar: 5.1.6.RELEASE] на com.sun.proxy. $ Proxy91.findUser (Неизвестный источник) ~ [na: na] на аукционе.demo.service.ItemService.scheduledTask (ItemService.java:55)> ~ [classes /: na] at sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) ~ [na: 1.8.0_121] at> sun.reflect.NativeMethodAccessormpl.invoke (NativeMethodAccessorImpl.java:62)> ~ [na: 1.8.0_121] at> sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.> java: 43) ~ [na: 1.8.0_121] at java.lang.reflect.Method.invoke (Method.java:498) ~ [na: 1.8.0_121] at> org.springframework.scheduling.support.ScheduledMethodRunnable.run (ScheduledM> ethodRunnable.java:84) ~ [spring-context-5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run (De> legatingErrorHandlingRunnable.java:54) ~ [spring-context-> 5.1.6.RELEASE.jar: 5.1.6.RELEASE] в> org.springframework.scheduling.concurrent.ReschedrunRescheduli> ngRunnable.java:93) [spring-context-5.1.6.RELEASE.jar: 5.1.6.RELEASE] at> java.util.concurrent.Executors $ RunnableAdapter.call (Executors.java:511) [na:1.8.0_121] в java.util.concurrent.FutureTask.run (FutureTask.java:266) [na: 1.8.0_121] в> java.util.concurrent.ScheduledThreadPoolExecutor $ ScheduledFutureTask.access $ 2> 01 (ScheduledThreadJoExec:) [na: 1.8.0_121] at> java.util.concurrent.ScheduledThreadPoolExecutor $ ScheduledFutureTask.run (Sche> duledThreadPoolExecutor.java:293) [na: 1.8.0_121] at> java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:114> 2) [na: 1.8.0_1>java.util.concurrent.ThreadPoolExecutor $ Worker.run (ThreadPoolExecutor.java:61> 7) [na: 1.8.0_121] в java.lang.Thread.run (Thread.java:745) [na: 1.8.0_121]

Вопрос: Создайте запланированное задание, которое запускается по окончании аукциона предмета, и определяет победителя этого предмета из таблицы ставок и сохраняет идентификатор этого пользователя в Победителе.столбец таблицы Auction_items.

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

Даже если это причина, я не уверен, как ее решить, также , если это не причина, приложение автоматически сохранит правильный user_id в столбце победителя, если должный пользователь instance устанавливается с помощью setUser ().

Обратите внимание, что я использовал @EnabledScheduling в классе с методом main ().

ОБНОВЛЕНИЕ: Вставлен новыйItemService.java, Item.java В Item.java я использовал тип данных User для переменной member, так как преобразование в Integer не работало

Ответы [ 2 ]

2 голосов
/ 22 апреля 2019
  1. хранилище должно управлять одним типом домена (сущностью), в вашем случае вы используете ItemRepository для извлечения сущностей пользователей, что является неправильным использованием.
  2. вам не нужно реализовывать findUser метод, так как репозитории уже имеют реализацию для findById.
  3. Я бы рекомендовал вам использовать JPA Query Methods для таких простых запросов вместо того, чтобы прибегать к нативным SQL-запросам.

Итак, краткий ответ, создайте отдельный UserRepository, переместите туда метод findWinner и используйте существующий findById из UserRepository вместо findUser из ItemRepository

1 голос
/ 23 апреля 2019

Хорошо, поэтому в методе scheduleTask () ItemService.java контроль достигал каждой части, и экземпляр элемента 'i' также обновлялся, я думаю, мне просто нужно было сохранить это в БД с помощью itemRepository.save (i) Ниже приведена полная реализация метода scheduleTask ()

@Scheduled(cron="0 17 11 * * ?")
    public void scheduledTask() {
        List<Item> listOfItems = (List<Item>)itemRepository.findAll();
        System.out.println("going to update DB");
        for(Item i : listOfItems) {
            Timestamp time = new Timestamp(System.currentTimeMillis());
            if(time.equals(i.getEnd_time()) || time.after(i.getEnd_time())) {
                if(i.getUser() == null) {
                    Integer item_id = i.getItem_id();
                    Integer winner_id = itemRepository.findWinner(item_id);
                    User u= userRepository.findById(winner_id).orElse(null);

                    i.setUser(u);
                    itemRepository.save(i);//change in code, which seems to work now
                    System.out.println("printing item:");
                    System.out.println(i.getItem_description()+", "+i.getItem_name()+", "+i.getStarting_amount()+", "+i.getItem_id()+", "+i.getEnd_time()+", "+i.getStart_time()+", "+i.getUser().getUser_id());
                    System.out.println("updated");
                }
            }
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...