Java JDBC - Multiple prepared statement bulk insert - java

Using JDBC (Oracle) I need to insert about thousand rows into each of two tables. Something like this:
"INSERT INTO TABLE_A (A_ID, A_NAME, A_LAST_NAME) VALUES (MY_SEQUENCE.NEXTVAL, ?, ?)";
"INSERT INTO TABLE_B (B_ID, B_DESCRIPTION) VALUES (MY_SEQUENCE.CURRVAL, ?)";
The problem is that both tables are connected through common sequence, so that order of statements is important.
It would be quite easy if I had only one table. In that case I used code:
String insert = "Insert into TABLE_A(A_ID, A_NAME, A_LAST_NAME) values(MY_SEQUENCE.NEXTVAL, ?, ?)";
conn.setAutoCommit(false);
PreparedStatement ps = conn.prepareStatement(insert);
for(MyObject obj : myCollection) {
ps.setString(1, obj.getName());
ps.setString(2, obj.getLastName());
ps.addBatch();
}
ps.executeBatch();
conn.commit();
ps.close();
But this approach can work only with one prepared statment and thus with only one Insert. How can I provide a solution for this problem?

You can try
PreparedStatement ps = conn.prepareStatement(insert, Statement.RETURN_GENERATED_KEYS);
...
ps.executeBatch();
then
ResultSet rs = ps.getGeneratedKeys();
ps = conn.prepareStatement("INSERT INTO TABLE_B (B_ID, B_DESCRIPTION) VALUES (?, ?)");
for ( int counter =0;rs.next(); counter++ ) {
ps.setInt(1,rs.getInt(0));
ps.setString(2, myCollection.get(counter).getDescription());
ps.addBatch();
}
...

If I understand your problem correctly, you have a problem with NEXTVAL and CURRVAL since CURRVAL might change due to other DB use?
If so, you can change your code to this order:
currentNextVal = select NEXTVAL
INSERT into table_a with currentNextVal as the id
INSERT into table_b with the same currentNextVal
Did I understand your problem correctly?

Related

Insert database mysql get issue

i got issue when i go to Insert value to DB (do nothing).
before that i do select table to get last id, and it worked.
Here's my Code:
IDBManager dbManager = getParentExtension().getParentZone().getDBManager();
Connection connection = null;
int idRoom = params.getInt("idRoom");
String betsmall = params.getUtfString("betsmall");
int Uid = params.getInt("recid");
try{
connection = dbManager.getConnection();
PreparedStatement stmt = connection.prepareStatement("SELECT id_game from detail_game ORDER BY id_game DESC LIMIT 1");
ResultSet res = stmt.executeQuery();
if (!res.first())
{
trace("bla bla");
}
int id = res.getInt("id_game");
trace (id);
// **till here there is no problem, i can get id from select query
PreparedStatement stmts = connection.prepareStatement("INSERT INTO detil_bet (id_user, id_room, id_bet, bettype) VALUES (?, ?, ?, ? ");
stmts.setInt(1, Uid);
stmts.setInt(2, idRoom);
stmts.setInt(3, id);
stmts.setString(4, betsmall);
stmts.executeUpdate();
}
}
Here's the problem, insert do nothing.
PreparedStatement stmts = connection.prepareStatement("INSERT INTO detil_bet (id_user, id_room, id_bet, bettype) VALUES (?, ?, ?, ? ");
Looks like you need some end parentheses in "VALUES".
A catch block to print stack trace would have told you the issue here as well. I'm not the best SQL guy, I always use this to check my SQL syntax as well to double check if I've done everything right.
your connection seems not auto commit. Try to add
stmts.commit();
after "stmts.executeUpdate();".

is this actually a resource leak?

I have an "Invitation" object that is modeled in a MySQL database. This object has one list ("treatmentPlanIDsToCopyf") and is maintained in the database with a second table. The method I have written to insert into the main table and then loop through the list and insert records for each item in the list into the second table is below. At the line ps = cn.prepareStatement(sql);Eclipse is giving me a warning that says "Resource leak: 'ps' is not closed at this location". I am closing the prepared statement in the finally clause, so I wanted to know if there really is a resource leak I need to fix. This is my first time using batches with prepared statements, so I wasn't really sure. Thanks.
public void invitationCreate(Connection cn, Invitation invitation) throws SQLException{
PreparedStatement ps = null;
try {
//first insert primary invitation data into the invitation table
String sql = "INSERT INTO invitiation (invitation_code, recipient_email, sender_user_id_fk, date_intived, date_accepted, accepted, recipient_first_name, recipient_last_name) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
ps = cn.prepareStatement(sql);
ps.setString(1, invitation.getInvitationCode());
ps.setString(2, invitation.getRecipientEmail());
ps.setInt(3, invitation.getSenderUserID());
ps.setTimestamp(4, convertLocalTimeDateToTimstamp(invitation.getDateInvited()));
ps.setTimestamp(5, convertLocalTimeDateToTimstamp(invitation.getDateAccepted()));
ps.setBoolean(6, invitation.isAccepted());
ps.setString(7, invitation.getRecipientFirstName());
ps.setString(8, invitation.getRecipientLastName());
int success = ps.executeUpdate();
//now loop through all the treatmentPlanIDs in the invitation that are to be copied into the invitees account when the register
sql = "INSERT INTO invitation_treatment_plans (invitation_code_fk, invitation_treatment_plan_id_fk) VALUES (?, ?)";
ps = cn.prepareStatement(sql);//TODO confirm this if this is actually a resource leak
for(int treatmentPlanID : invitation.getTreatmentPlanIDsToCopy()){
ps.setString(1, invitation.getInvitationCode());
ps.setInt(2, treatmentPlanID);
ps.addBatch();
}
ps.executeBatch();
} finally {
DbUtils.closeQuietly(ps);
}
}
I believe the leak is in the first prepared statement.
After int success = ps.executeUpdate(); you need to close that prepared statement before you assign the variable to a new prepared statement.

SELECT after INSERT statement?

So my issue is after I insert a new record in the database, I want to do a SELECT query that should include that new record. However, the data being returned excludes the newly added record. It seems like whenever I first open the connection, whatever is already in the database is what my program goes off. I hope this makes sense. All input is appreciated.
Update:
So here is the INSERT snippet
String DML = "INSERT INTO MEMBERS (FIRST_NAME, LAST_NAME, BIRTHDATE, DEATH_DATE, MARITAL_STATUS,"
+ " WEDDING_DATE, SPOUSE_NAME, MILITARY_SERVICE, DATE_JOINED, DEPARTURE_DATE, ACCEPTANCE_MODE, DEPARTURE_MODE,"
+ " RELATED_TO, NOTES) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(DML);
pstmt.setString(1, jTextField2.getText());
pstmt.setString(2, jTextField1.getText());
pstmt.setString(3, jTextField6.getText());
pstmt.setString(4, jTextField11.getText());
pstmt.setString(5, jTextField3.getText());
pstmt.setString(6, jTextField5.getText());
pstmt.setString(7, jTextField4.getText());
pstmt.setString(8, jTextField8.getText());
pstmt.setString(9, jTextField7.getText());
pstmt.setString(10, jTextField10.getText());
pstmt.setString(11, jTextField9.getText());
pstmt.setString(12, jTextField13.getText());
pstmt.setString(13, jTextField14.getText());
pstmt.setString(14, jTextArea1.getText());
pstmt.executeUpdate();
if (conn.getAutoCommit() == false)
conn.commit();
Now this is the SELECT snippet which if fired after the INSERT
pstmt=conn.prepareStatement("SELECT CONCAT(LAST_NAME, ', ', FIRST_NAME) AS NAME FROM MEMBERS ORDER BY LAST_NAME, FIRST_NAME");
rs=pstmt.executeQuery();
It is very likely that you have autocommit mode disabled and/or you are running the 2 queries (INSERT then SELECT) as a transaction.
Try turning autocommit mode on and then running the 2 queries again (INSERT then SELECT), it should work.
If you mean this
stmt.executeUpdate("insert into t1 ...");
ResultSet rs = stmt.executeQuery("select ... from t1");
then data inserted in statement 1 is always visible in statement 2, both in autocommit on and off modes.
It is only possibly that select does not see inserted records if you insert in one transaction, do not commit, and read in another transaction
Something like this can be done:
You can use an autoincrement column say call it serialID.
Insert data normally. When retrieving use MAX(serialID)
SELECT CONCAT(LAST_NAME, ', ', FIRST_NAME) AS NAME FROM MEMBERS ORDER BY
LAST_NAME, FIRST_NAME where serialID = (select max(serialID) from MEMBERS);
You'll have to do this in one transaction.

How to get sequence.nextval from SQL in JDBC?

I have 5 tables where I use the same sequence's next value. The problem is, the subsequent tables gets a bigger value than the previous ones.
My code is like this:
String sql = "INSERT INTO table1(id, name) VALUES (id_seq.nextval, ?)";
ps.setString(1, "bar");
ps.executeUpdate();
sql = "INSERT INTO table2(id, name) VALUES (id_seq.nextval, ?)";
ps.setString(1, "tar");
ps.executeUpdate();
sql = "INSERT INTO table3(id, name) VALUES (id_seq.nextval, ?)";
ps.setString(1, "par");
ps.executeUpdate();
sql = "INSERT INTO table4(id, name) VALUES (id_seq.nextval, ?)";
ps.setString(1, "car");
ps.executeUpdate();
sql = "INSERT INTO table5(id, name) VALUES (id_seq.nextval, ?)";
ps.setString(1, "rar");
ps.executeUpdate();
My sequence is like this:
CREATE SEQUENCE "ID_SEQ" MINVALUE 1 MAXVALUE 9999999999 INCREMENT BY 1 START WITH 10 CACHE 20 NOORDER NOCYCLE ;
Now when I look at my tables, table1's ID is 10, but table2's ID is 11 and table3's ID is 12..... I want all the tables' IDs to be same. What should I do?
Thank you in advance.
edit: Had to include more tables than 2 to have more general question
Actually I found the answer online. I need to do this:
String sql = "select ID_SEQ.nextval from DUAL";
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
if(rs.next())
int nextID_from_seq = rs.getInt(1);
And when I insert this value to database, I type this:
String sql2 = "INSERT INTO table1(id, name) VALUES (?, ?)";
ps.setInt(1, nextID_from_seq);
ps.setString(2, "tar");
ps.executeUpdate();
sql2 = "INSERT INTO table2(id, name) VALUES (?, ?)";
ps.setInt(1, nextID_from_seq);
ps.setString(2, "par");
ps.executeUpdate();
...
...
The first string sql is "select ID_SEQ.nextval from DUAL." That "DUAL" in the end is not table name or anything. It's just one of the given or provided functionality by oracle. I can get any sequence's nextval by using it.
You can use id_seq.currval for the second table. It will reuse the same id.
sql = "INSERT INTO table2(id, name) VALUES (id_seq.currval, ?)";

Insert multiple rows into two tables in a single query using JDBC in JAVA

I have two tables student(id, name, city), teacher(id, name, salary).
And there are several rows which are needed to insert Mysql DB.
INSERT INTO student VALUES ('12', 'Tom', 'New York');
INSERT INTO student VALUES ('13', 'Jack', 'New York');
INSERT INTO teacher VALUES ('01', 'Joy', '42000');
INSERT INTO teacher VALUES ('02', 'Ryan', '39000');
The connector is JDBC in JAVA, could I write a single query to do it.
Use a PreparedStatement and batch insert:
List<Student> students = ...
Connection con = ...
String insertSql = "INSERT INTO student VALUES (?, ?, ?)";
PreparedStatement pstmt = con.prepareStatement(insertSql);
for (Student student : students) {
pstmt.setString(1, student.getId()); //not sure if String or int or long
pstmt.setString(2, student.getName());
pstmt.setString(3, student.getCity());
pstmt.addBatch();
}
pstmt.executeBatch();
//close resources...
Similar for your Teachers.
More info:
Using Prepared Statements
Difference between Statement and PreparedStatement
Reusing a PreparedStatement multiple times

Categories