The transaction-free approach still has potential issues though. Consider:
select isbn, copies_in_stock
from books
where isbn = "12345678"
and copies_in_stock >= 1;
isbn: 12345678
copies_in_stock: 1
update books
set copies_in_stock = copies_in_stock - 1
where isbn = "12345678"
If you have two of the above requests happen at the same time such that the execution order is SELECT SELECT UPDATE UPDATE, you'll end up with -1 copies_in_stock. You can try adding an "and copies_in_stock >= 1" to the UPDATE and then look at the number of affected rows, and perform recovery logic if the number of affected rows is 0, but at that point you've basically implemented a transaction, probably badly if it isn't what you set out to do.