春季启动任务,用于更新数据库中的外键

时间:2019-04-22 09:30:57

标签: java spring-boot jpa

我正在使用Spring Boot开发REST API,它将用于管理物品拍卖。

参加拍卖的用户将在单独的用户表

要拍卖的物品将在 Auction_items表中,以及拍卖的开始和结束时间,如果拍卖仍在进行中,则获胜者为空。

用户为各个项目完成的所有出价都在出价表

我已经尝试了不同的方式(cron,fixedRate,fixedDelay)来计划任务,所有这些都遇到了类似的错误,我怀疑可能是由于发生数据库问题。 / strong>

下面是表和相应的模型类以及服务和存储库接口。

用户表:

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

AUCTION_ITEMS表:

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
);

出价表:

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
}

下面是服务类,其中我定义了 scheduledTask()方法,以便在经过拍卖品的结束时间后运行并计算拍卖品的赢家:

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 --- [调度-1]> o.h.h.i.QueryTranslatorFactoryInitiator:HHH000397:使用> ASTQueryTranslatorFactory   要更新数据库   2019-04-22 12:55:30.464错误9100 --- [schedule-1]?> o.s.s.s.TaskUtils $ LoggingErrorHandler:>计划任务发生意外错误。

     

org.springframework.dao.InvalidDataAccessApiUsageException:> org.hibernate.QueryException:JPA样式的位置参数不是整数>常规;嵌套异常是java.lang.IllegalArgumentException:> org.hibernate.QueryException:JPA样式的位置参数不是整数> ordinal     在> org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExcepti> onIfPossible(EntityManagerFactoryUtils.java:373)〜[spring-orm-> 5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPo> ssible(HibernateJpaDialect.java:255)〜[spring-orm->]> 5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExcepti> onIfPossible(AbstractEntityManagerFactoryBean.java:527)〜[spring-orm-> 5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.dao.support.ChainedPersistenceExceptionTranslator.transla> teExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)〜   [spring-tx-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAcce> ssUtils.java:242)〜[spring-tx-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.in> voke(PersistenceExceptionTranslationInterceptor.java:153)〜[spring-tx-> 5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflecti> veMethodInvocation.java:186)〜[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcess>或$ CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPos> tProcessor.java:138)〜[spring-data-jpa-2.1.6.RELEASE.jar:2.1.6。发布]     在> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflecti> veMethodInvocation.java:186)〜[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(Expose> InvocationInterceptor.java:93)〜[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflecti> veMethodInvocation.java:186)〜[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.data.repository.core.support.SurroundingTransactionDetect> orMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.ja> va:61)〜[spring-data-commons-2.1.6.RELEASE.jar:2.1.6.RELEASE]     在> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflecti> veMethodInvocation.java:186)〜[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProx> y.java:212)〜[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在com.sun.proxy。$ Proxy91.findUser(未知来源)〜[na:na]     at auction.demo.service.ItemService.scheduledTask(ItemService.java:55)>〜[classes /:na]     在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)〜   [na:1.8.0_121]     在> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)>〜[na:1.8.0_121]     在> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl。> java:43)〜[na:1.8.0_121]     在java.lang.reflect.Method.invoke(Method.java:498)〜[na:1.8.0_121]     在> org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledM> ethodRunnable.java:84)〜[spring-context-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> 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.ReschedulingRunnable.run(Rescheduli> ngRunnable.java:93)[spring-context-5.1.6.RELEASE.jar:5.1.6.RELEASE]     在> 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(ScheduledThreadPoolExecutor.java:180)[na:1.8.0_121]     在> java.util.concurrent.ScheduledThreadPoolExecutor $ ScheduledFutureTask.run(Sche> duledThreadPoolExecutor.java:293)[na:1.8.0_121]     在> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:114> 2)[na:1.8.0_121]     在> 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]

问题:创建一个计划任务,该任务在某项物品的拍卖结束时运行,并从Bids表中确定该项目的胜者,并将该用户的ID存储在Auction_items表的Winner列中

我认为上述错误背后的原因是,我在模型类中创建了一个User成员变量,但是在表端,它仅期望User的ID而不是完整的User实例。< / p>

即使这是原因,我也不确定如何解决它,如果这不是原因,如果使用setUser设置了正确的用户实例,应用程序会自动将适当的user_id存储在获奖者列中()。

请注意,我已经在类中通过main()方法使用了@EnabledScheduling。

更新:粘贴新的ItemService.java,Item.java 在Item.java中,我已将数据类型User用作成员变量,因为将其设置为Integer不起作用

2 个答案:

答案 0 :(得分:1)

  1. 如果您使用ItemRepository来获取用法不正确的用户实体,则存储库应该管理一种域类型(实体)。
  2. 您不需要实现findUser方法,因为存储库已经具有findById的实现。
  3. 我建议您尝试对此类简单查询使用JPA查询方法,而不要求助于本机SQL查询。

答案很简短,请创建一个单独的UserRepository,在其中移动findWinner方法,然后使用findById中现有的UserRepository而不是{ {1}}

答案 1 :(得分:0)

好的,因此,在ItemService.java的ScheduledTask()方法中,控件已遍及每个部分,并且项目实例“ 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");
                }
            }
        }
    }