1

I'm building an accounting application and one of the method has been written to save an invoice into the database (MongoDB). Before saving an invoice I must create a number (alphanumeric characters) incrementing the last saved invoice number. Basically, I have to read the last created invoice to get the number and reuse that number + 1 to save the new invoice. To keep the invoice number consistent, I have written the following method:

public synchronized void saveInvoice(InvoiceObject object){
   //Get the last invoice and increment the number
   //Save the InvoiceObject with the incremented number
}

So far so good, but since this application is used by multiple clients, each client has its own invoice numbering sequence so, instead of blocking all clients (threads) while saving an invoice (because of the synchronized), I would like to allow multiple clients accessing the method "concurrently" and queuing the requests of a same client (to keep increasing properly its invoice sequence).

To summarize, here is a diagram of what I want to achieve: Diagram

How can I achieve this?

Thanks :-)

  • The database can do this for you automatically with AUTO_INCREMENT. Don't write code for this. – user207421 Dec 28 '19 at 02:32
  • I don’t think you understood the question. – Tomaz Fernandes Dec 28 '19 at 03:41
  • @TomazFernandes If that's addressed to me, I most certainly did. – user207421 Dec 28 '19 at 03:45
  • AUTO_INCREMENT won’t work here, as the OP clearly states that each client has it’s own invoice numbering – Tomaz Fernandes Dec 28 '19 at 03:51
  • @user207421, AUTO_INCREMENT cannot work here as the invoice numbering is per client, not system-wide. For example, client A can have numbering such as ABC001, ABC002, ABC003... while client B can have the numbering DEF001, DEF002, DEF003, ... Clients choose their numbering prefix and the last 3 (or more) digits auto-increment. Hope this is more clear :-) – gstievenard Dec 28 '19 at 14:01

2 Answers2

0

In general, you can prevent multiple threads from executing a critical section within a method by using a synchronized block with a lock that you specify.

class InvoiceRepository {

  private final Object lock = new Object();

  private int number;

  public void saveInvoice(InvoiceObject object) {
    int myNumber;
    synchronized(lock) {
      myNumber = ++number;
    }
    /* Save the invoice... */
  }

If you need it, instead of using intrinsic locking with a simple Object, you can use a Lock implementation to get more capabilities, like interruptibility or time-outs on lock acquisition.

But in this case, an AtomicInteger (or AtomicLong) looks like a good fit:

class InvoiceRepository {

  private final AtomicInteger number = new AtomicInteger();

  public void saveInvoice(InvoiceObject object) {
    int myNumber = number.incrementAndGet();
    /* Save the invoice. */
  }
erickson
  • 265,237
  • 58
  • 395
  • 493
-1

You can lock based on the Client's id.

Check this answer for details on how to implement it: Java synchronizing based on a parameter (named mutex/lock)

If you know all your client id's in advance Tudor's answer will be fine, if not check Timmo's answer which is dynamic and more complete, albait more complex.

Hope it helps!

Tomaz Fernandes
  • 2,429
  • 2
  • 14
  • 18