Вопрос

I need to insert into database which has two columns-

ID Primary Key String
Data String

So that means ID should be unique every time , otherwise it will throw a duplicate row in unique index exception while inserting. And I need to choose ID in between this range 1-100000

So that means each thread should be using unique id always-

Below is the multithreaded program I wrote that will insert into database with different unique id's every time after getting from ArrayBlockingQueue.

So this program will be thread safe or not? Or is there any other better way to get the unique ID's every time for each thread? Or the below program can cause duplicate row in unique index ?

private static LinkedList<Integer> availableExistingIds = new LinkedList<Integer>();

public static void main(String[] args) {

        for (int i = 1; i <= 100000; i++) {
            availableExistingIds.add(i);
        }

        BlockingQueue<Integer> pool = new ArrayBlockingQueue<Integer>(200000, false, availableExistingIds);

        ExecutorService service = Executors.newFixedThreadPool(10);

            for (int i = 0; i < noOfTasks * noOfThreads; i++) {
                service.submit(new ThreadTask(pool));
            }
}   

class ThreadTask implements Runnable {

    private BlockingQueue<Integer> pool;
    private int id;

    public ThreadTask(BlockingQueue<Integer> pool) {
        this.pool = pool;
    }

    @Override
    public void run() {

         try {
            dbConnection = getDBConnection();
            preparedStatement = dbConnection.prepareStatement(INSERT_SQL);

            id = pool.take();

            preparedStatement.setString(1, String.valueOf(id));
            preparedStatement.setString(2, ACCOUNT);

            preparedStatement.executeUpdate();

       } finally {
         pool.offer(id);
        }

    }
}   
Это было полезно?

Решение

The pool.offer(id) means you put a used id back in the queue - so it can be reused later on by another thread. That is probably going to be an issue (since the queue is FIFO you will get a duplicate ID on the 100,001st insertion).

In any case, it seems very complicated when a static AtomicInteger would do the same thing without having to use a queue:

class ThreadTask implements Runnable {

    private final AtomicInteger id;

    ThreadTask(AtomicInteger id) {
        this.id = id; //in your main thread: id = new AtomicInteger(minId);
    }

    @Override
    public void run() {
        dbConnection = getDBConnection();
        preparedStatement = dbConnection.prepareStatement(INSERT_SQL);

        preparedStatement.setString(1, String.valueOf(id.getAndIncrement()));
        preparedStatement.setString(2, ACCOUNT);

        preparedStatement.executeUpdate();
    }
}

Note: as commented, your database can probably assign unique IDs for you.

Другие советы

An identity column is one to which the database assigns a new unique value on each insert. See here

I don't know this XpressMP database but you should search documentation for an identity or auto-increment type. You can also use a guid type at slightly more cost.

Remember that you will have to start after the last assigned ID when the program restarts. But you still don't need a queue, just a IdProvider class with a synchronized nextId method that increments and returns a private variable that has been initialized to the last assigned id.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top