• If the Insert statement you are running comes from a single sql statement, then you wouldn't need to manually lock any records?

    eg:

    BEGIN TRANSACTION [Tran1]
    BEGIN TRY
    Insert into invoice_table(id,invoice_company,col2,col3,....)
    select (select max(id)+1 from invoice_table) as id
            ,'Company XYZ' as invoice_company
            ,col2 
     
    COMMIT TRANSACTION [Tran1]
    END TRY
    BEGIN CATCH
    ROLLBACK TRANSACTION [Tran1]
     PRINT 'Some error'
     THROW
    END CATCH

    However the requirement for gap free monotonically increasing numbers would mean you are limiting the scalability of the transaction, since, max+1 logic in a multi user scenario would mean that users would have to wait until the previous transaction is complete to get their inserts to work. This kind of problem can be overcome using sequences, if the requirement for gap free is not such a big deal. As it is by using a database if your actions are coded to be atomic(either the invoice module would cause an insert to the table or never gets into the database and throws an exception), the you can be sure that you wont have any missing invoices from your application when the application calls the "add_invoice" stored procedure..