Mysql and JDBC returned stale data - java

We are facing a strange issue with mysql data. We have a seqgenerator table which holds the current seq of the id. Every time an order is placed my application queries the seqgenerator table and updates one number and saves it back in the seqgenerator.
The query we are using to fetch is "select order_id from order_seq where appid = ? for update"
Query to update "update order_seq set order_id = ? where appid = ?"
This was working fine until last week, last week the select query returned id which was already used one day back and the id got reset and started incrementing from there due to which we have overridden 1 days orders.

Your design is just very bad.
First of all, Id should always be unique, this would have prevented your data from being overwritten.
Also SQL has an Auto-Increment field, so you don't have to update your ID by one each time
Auto-increment allows a unique number to be generated automatically
when a new record is inserted into a table.
Often this is the primary key field that we would like to be created
automatically every time a new record is inserted
Source:
https://www.w3schools.com/sql/sql_autoincrement.asp

Related

SQL Logic of Re-Inserting item from one table to another table? e.g Active records becoming Inactive records

I have a table named booking. The primary key is booking_id. The table has a column named booking_num. booking_num is used to identify the booking.
Another table is booking_hist. The purpose is to transfer completed records of booking from booking table into booking_hist table after a certain period, let's say 2 days. The column to identify it will be completed_dt.
For example, completed_dt is '08-SEP-19'.
What I'm trying to achieve is that after immediately 2 days after this date, it will be moved into booking_hist table.
Should there be any null<->non-null conversions of the column?
What is the logic I need to achieve this? How can i get the date to
count 2 days?
You can schedule a SQL Agent job runs daily and call a stored procedure to go through the active bookings and check the completed_dt like:
-- add your insert here, e.g. INSERT INTO bookings_hist (...)
SELECT *
FROM booking b
LEFT JOIN booking_hist h
ON b.booking_id=h.booking_id
WHERE h.booking_id IS NULL
AND completed_dt IS NOT NULL
AND completed_dt<DATEADD(DAY,-2,GETDATE());
This sounds like the kind of thing that should happen in a scheduled job.
I would add a ready_for_archive column to booking-just a boolean flag.
I would have a query that marked all bookings that happen before a specified date/time, and pass in the date of 2 days ago from java. Something like
UPDATE booking
SET ready_for_archive = 1
WHERE completed_dt <= :MY_START_DATE
Then I would add all of these records to the historical table
INSERT INTO booking_hist
SELECT * FROM booking
WHERE ready_for_archive = 1;
Then remove them from the booking table:
DELETE FROM booking
WHERE ready_for_archive = 1;
Marking the records to be archived before doing that process means there's no risk of accidentally deleting records that were one second too young to be copied.
Passing in the date after calculating it in Java makes the sql query more generic and reusable.
Create a stored procedure to move from one table to other
how to call the stored procedure in oracle with the daily scheduled jobs?
In where condition add ,
trunc(sysdate) - to_date('completed_dt', 'yyyy-mm-dd') >2
Please refer below link for other options:
How can I get the number of days between 2 dates in Oracle 11g?

How Can I get table's primary key via Oracle Database Change Notification

I could get notifications from an Oracle database thanks to this code and omitting this line:
prop.setProperty(OracleConnection.DCN_QUERY_CHANGE_NOTIFICATION,"true");
Also I could solve my ORA-29977 problem changing select * from act_code_metadata where product_id=1159 with select column_with_Number_type from act_code_metadata where product_id=1159
Everything works as expected :D
This is the code I use to print the row's information (Java 8):
DatabaseChangeRegistration dcp.addListener((DatabaseChangeEvent dce) ->
System.out.println(
"Changed row id : " +
dce.getTableChangeDescription()[0].getRowChangeDescription()[0].getRowid().stringValue()
+ " " + dce.getTableChangeDescription()[0].getRowChangeDescription()[0].getRowOperation().toString()));
But all the information I get is the row's physical address (rowid) and the operation involved (insert, delete or update).
I need to identify the row being modified/inserted/deleted to refresh my cached data in several Swing controls in my GUI.
I've read that, despite the rowid being imutable, the same rowid can be re-assigned if the row is deleted and a new one is inserted, and the rowid can change if the row is in a partitioned table. So the best that can be done is using the rowid and the row's primary key.
My table has a autoincrementable primary key (with a sequence and a trigger) created with this code.
I have no control on what happens on the database or if somebody inserts and deletes rows several times. So I can get the wrong row when selecting it using the rowid given by the notification.
Is there a way that I can get my row's primary key via Oracle Database Change Notification so I can identify the inserted/deleted/modified row correctly?
I'm working with Oracle Database XE 11.2 Express and Java 8. The user for database connection already has the change notification privilege.
It seems that you have a lot of overhead trying to basically maintain a fresh snapshot of the data in your GUI. It may be simpler to look at client result caching and just re-running your query every X seconds; and let Oracle do the magic of seeing if the data changed. You would be limited to a JDBC driver that supports OCI. See http://docs.oracle.com/cd/E11882_01/server.112/e41573/memory.htm#PFGRF985 for details. With client result caching, the first time the SQL is executed, it will take say 500 milliseconds. Next query using the same criteria it will take 2 or 3 milliseconds. Assuming the result set is small (less than 100 rows is quite small), you can get a lot better results without all that framework you are trying to build.

Locking Tables with postgres in JDBC

Just a quick question about locking tables in a postgres database using JDBC. I have a table for which I want to add a new record to, however, To do this for the primary key, I use an increasing integer value.
I want to be able to retrieve the max value of this column in Java and store it as a variable to be used as a new primary key when adding a new row.
This gives me a small problem, as this is going to be modelled as a multi-user system, what happens when 2 locations request the same max value? This will of course create a problem when trying to add the same primary key.
I realise that I should be using an EXCLUSIVE lock on the table to prevent reading or writing while getting the key and adding a new row. However, I can't seem to find any way to deal with table locking in JDBC, just standard transactions.
psuedo code as such:
primaryKey = "SELECT MAX(id) FROM table1;";
primary key++;
//id retrieved again from 2nd source
"INSERT INTO table1 (primaryKey, value 1, value 2);"
You're absolutely right, if two locations request at around the same time, you'll run into a race condition.
The way to handle this is to create a sequence in postgres and select the nextval as the primary key.
I don't know exactly what direction you're heading and how your handle your data, but you could also set the column as a serial and not even include the column in your insert query. The column will automatically auto increment.

Get a unique max id for each instance using mysql

I am using a field with a prefix + auto increment id. For each instance i am taking the max+1 of ID and adding that to prefix. Can anyone suggest me a way to get this as unique please?
You can try this:
Insert into table1 (id, user_id)
SELECT MAX(id)+1, CONCAT('a',CAST(MAX(id)+1 AS char))
FROM table1;
See this SQLFiddle
The problem with using max(id)+1 is that there may be multiple threads making the same call, and so the result would not be unique. There are several ways to solve this problem. The first is to use a sequence, where the database server will increment the number every time a new id is requested. You can use a table, with a number in it, but you have to lock the table when you update the number. Or you can allow the database to create the key for you when the table is inserted and retrieve the key after the insert. All are valid.
I prefer to use Hibernate and make it determine how to implement the ID for the database I am currently using.

Using Auto Increment with MySQL and need to retrieve that number

I have a database in which I need some IDs to be autoincremented, but I also need that ID that gets auto incremented to be the Foreign Key for another table. Is there a way to recover that number within the same transaction to insert values into the second table?
As in:
1) Create a user
2) Retrieve the ID number generated by the auto increment ( for example: AI:5 )
3) Insert values into a table called Doctor, that needs that number retrieved by that user, all within same transaction...
I know that JSP has some function to recover that ID generated but not sure about MySQL.
Another thing is, I can't just send a query to recover the last generated ID because for example if 10 accounts got created at the same time I might not get the supposed number.
For a pure MySQL solution:
SELECT LAST_INSERT_ID();
For a Java way:
ResultSet rs = stmt.getGeneratedKeys();

Categories