Spring boot task to update foreign key in DB

Akki :

I am working on REST API using Spring boot which is going to manage the auction of items.

Users participating in auction will be in a separate Users table

Items to be Auctioned will be in Auction_items table, along with auction start and end time, winner null if auction is still in progress.

All the bids done by users for respective items are there in Bids table

I have already tried different ways(cron, fixedRate, fixedDelay) for scheduling the task, got a similar error for all of them, I am suspecting there might be a DB issue due to which it is happening.

Below are the tables and corresponding model class along with service and repository interface.

USERS TABLE:

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

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

Below are the model classes for above tables:

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
}

Below is the service class, where I am defining the scheduledTask() method to run and calculate the winner of Item auctioned once the end time of auction item is passed:

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

Below is the error which I get once, the time comes to update the data in table:

2019-04-22 12:55:30.123 INFO 9100 --- [ scheduling-1] >o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using >ASTQueryTranslatorFactory going to update DB 2019-04-22 12:55:30.464 ERROR 9100 --- [ scheduling-1] ?>o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in >scheduled task.

org.springframework.dao.InvalidDataAccessApiUsageException: >org.hibernate.QueryException: JPA-style positional param was not an integral >ordinal; nested exception is java.lang.IllegalArgumentException: >org.hibernate.QueryException: JPA-style positional param was not an integral >ordinal 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) ~ [spring-tx-5.1.6.RELEASE.jar:5.1.6.RELEASE] at >org.springframework.dao.support.DataAccessUtils.translateIfNecessary(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>or$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPos>tProcessor.java:138) ~[spring-data-jpa-2.1.6.RELEASE.jar:2.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.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.data.repository.core.support.SurroundingTransactionDetect>orMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.ja>va:61) ~[spring-data-commons-2.1.6.RELEASE.jar:2.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.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProx>y.java:212) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE] at com.sun.proxy.$Proxy91.findUser(Unknown Source) ~[na:na] at auction.demo.service.ItemService.scheduledTask(ItemService.java:55) >~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~ [na:1.8.0_121] at >sun.reflect.NativeMethodAccessorImpl.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] at >org.springframework.scheduling.concurrent.ReschedulingRunnable.run(Rescheduli>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] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_121] at >java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$2>01(ScheduledThreadPoolExecutor.java:180) [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_121] at >java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:61>7) [na:1.8.0_121] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]

Question: Create a scheduled task which runs when at the auction end time of an item and decides the winner of that item from Bids table and stores the Id of that user in Winner column of Auction_items table.

I think the reason behind above Error is, I have created a User member variable in model class, but in table side, it is expecting only the id of User not the complete User instance.

Even if this is the reason, I am not sure how to solve it, also if this is not the reason, will the application automatically store the proper user_id in winner column, if proper user instance is set using setUser().

Note that I have used @EnabledScheduling in the class, with main() method.

UPDATE: Pasted new ItemService.java, Item.java In Item.java I have used datatype User for the member variable since making it as Integer was not working

Akki :

Okay, so in the scheduledTask() method of ItemService.java, control was reaching every part and item instance 'i' was also getting updated, I guess I just needed to save that to DB using itemRepository.save(i) Below is the complete implementation of scheduledTask() method

@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");
                }
            }
        }
    }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=133465&siteId=1