How to insert multiple rows with same id in java & mysql - java

public boolean saveScore1(Score obj) {
boolean returnValue = false;
String sql = "insert into score(e_id,u_id,u_score,y_id,b_id) values(?,?,?,?,?)";
try {
Connection connection = DBConnectionHandler.getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
ps.setInt(1, obj.getEId());
ps.setInt(2, obj.getUId());
ps.setString(3, obj.getUScore());
ps.setInt(4, obj.getYId());
ps.setInt(5, obj.getBId());
int i = ps.executeUpdate();
if (i > 0) {
returnValue = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return returnValue;
}
Here are the three table i'm using
Examtable: e_id integer(auto increment) pk,e_name varchar
UserTable: u_id integer(auto increment)pk,u_name varchar
ScoreTable: s_id integer(auto increment)pk ,u_id integer fk, e_id integer fk, u_score
I want to send multiple data to score table at a time with one sql query for same u_id but different e_id, beacuse e_id will contains different value like B.B.A,M.B.A, B.sc, M.sc etc. So one user can have different exam pass.
I'm using above java code to insert but i just take the last value from front-end jsf form.
How can i send multiple rows for same u_id with different e_id at a time.

First of all, you don't insert data with a SQL query. A query is a SELECT statement.
Using JDBC, you can batch multiple insert statements, such that number of round trips to the database are reduced (for performance). Functionally, it is the same as inserting one row at a time.
Since you are inserting multiple rows, you probably want all to succeed, or all to fail, so you need to do your own commit or rollback.
Of course, since to do want to insert multiple score rows, your method should take a List<Score>.
public boolean saveScores(List<Score> scores) {
String sql = "insert into score(e_id,u_id,u_score,y_id,b_id) values(?,?,?,?,?)";
try (Connection connection = DBConnectionHandler.getConnection()) {
connection.setAutoCommit(false);
try {
try (PreparedStatement ps = connection.prepareStatement(sql)) {
for (Score score : scores) {
ps.setInt (1, score.getEId());
ps.setInt (2, score.getUId());
ps.setString(3, score.getUScore());
ps.setInt (4, score.getYId());
ps.setInt (5, score.getBId());
ps.addBatch();
}
ps.executeBatch();
}
connection.commit();
} catch (Exception e) {
connection.rollback();
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}

Related

DELETE AND INSERT in same transaction throws Duplicate entry exception in JDBC

I have a table inbox_participants that has inbox_id as a foreign key. When the inbox is updated, participants may be added or deleted. I am trying to delete all the inbox participants for the given inbox_id and reinsert updated participants with the same participant_id. It runs normally on my local machine. But in the server, it gives a Duplicate Entry exception for inbox_participant_id that should have been deleted.
Update Inbox
logger.info("Update inbox. Inbox id : {}", id);
final String query = "UPDATE inbox SET subject=?, updated_at=?, type=? WHERE inbox_id=?";
Connection conn = null;
PreparedStatement pst = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false);
pst = dataSource.prepareStatement(query, conn);
logger.debug(debug, QUERY, query);
pst.setString(1, inbox.getSubject());
pst.setLong(2, TreeleafDate.timestamp());
pst.setInt(3, inbox.getTypeValue());
pst.setString(4, id);
if (pst.executeUpdate() != 1) {
rollback(conn);
return false;
}
if (!removeParticipants(conn, id, debug)) {
rollback(conn);
return false;
}
if (!updateParticipants(conn, id, accountIdParticipantMap, debug)) {
rollback(conn);
return false;
}
commit(conn);
return true;
} catch (SQLException | JDBCException e) {
rollback(conn);
logger.error(debug, "Error while updating inbox", e);
return false;
} finally {
close(pst);
close(conn);
}
Remove Participants
private boolean removeParticipants(final Connection conn,
final String id,
final TreeleafProto.Debug debug) {
logger.info(debug, "Deleting inbox participants. Inbox id : {}", id);
final String query = "DELETE FROM inbox_participant WHERE inbox_id=?";
try (PreparedStatement pst = dataSource.prepareStatement(query, conn)) {
logger.debug(debug, QUERY,
query);
pst.setString(1, id);
final var i = pst.executeUpdate();
logger.debug(debug, "Delete query rows updated : {}", i);
return i >= 0;
} catch (JDBCException | SQLException e) {
logger.error(debug, "Error while removing participants.", e);
return false;
}
}
Insert updated participants
private boolean updateParticipants(final Connection conn,
final String id,
final Map<String, InboxProto.InboxParticipant> participants,
final TreeleafProto.Debug debug) {
logger.info(debug, "Updating inbox participants");
final String query = "INSERT INTO inbox_participant (inbox_participant_id, inbox_id, account_id, `role`, created_at, updated_at, notification_type, `left`) VALUES(?, ?, ?, ?, ?, ?, ?, ?)";
try (PreparedStatement pst = dataSource.prepareStatement(query, conn)) {
logger.debug(debug, QUERY,
query);
for (Map.Entry<String, InboxProto.InboxParticipant> entry : participants.entrySet()) {
final var participant = entry.getValue();
pst.setString(1, getId(participant));
pst.setString(2, id);
pst.setString(3, entry.getKey());
pst.setInt(4, participant.getRoleValue());
pst.setLong(5, TreeleafDate.timestamp());
pst.setLong(6, TreeleafDate.timestamp());
pst.setInt(7, participant.getNotificationTypeValue());
pst.setInt(8, participant.getParticipantStatusValue());
pst.addBatch();
}
int[] ints = pst.executeBatch();
return ints.length == participants.size() &&
Arrays.stream(ints).allMatch(value -> value == 1);
} catch (JDBCException | SQLException e) {
logger.error(debug, "Error while updating participants.", e);
return false;
}
}
If I understand the general logic here, it looks like the code above is attempting to either add (INSERT) OR UPDATE by-way-of-first-deleting-and-then-inserting based on whether the participants are already there or not.
If this is the gist of what you're trying to do, you should look into using an UPSERT syntax. This is a way to push this type of "INSERT or UPDATE if-it-exists-already" logic into the DML which is generally going to be easier to write in code (less code) and easier to test in your SQL console outside of the code, too.
Here's an example reference guide that talks about Upserts.
https://blog.usejournal.com/update-insert-upsert-multiple-records-in-different-db-types-63aa44191884
So in your code, this strategy would allow you to remove "removeParticipants" as a method and then instead of INSERT_INBOX_PARTICIPANT being a straight INSERT, like INSERT INTO inbox_participant, you would have something like...
MERGE INTO INBOX_PARTICIPANT T USING
(VALUES
(?, ?, ?)
) S (INBOX_ID, PARTICIPANT_ID, SOME_DATA)
ON T.INBOX_ID = S.INBOX_ID and T.PARTICIPANT_ID= S.PARTICIPANT_ID
WHEN MATCHED THEN UPDATE SET SOME_DATA = S.SOME_DATA
WHEN NOT MATCHED THEN INSERT (INBOX_ID, PARTICIPANT_ID, SOME_DATA)
VALUES (S.INBOX_ID, S.PARTICIPANT_ID, S.SOME_DATA);
**NOTE: The exact syntax varies according to your underlying database! See page for details! **
This will likely solve your problem indirectly but also lead to easier to maintain code.
As to if you want to continue with your original problem, I would investigate whether your DELETE's are somehow getting rolled back inadvertently.
Or perhaps because you INSERT in batch mode but delete as a direct executeUpdate, there's a possibility that the "batch" mode INSERTs are getting a different transactional context than the DELETEs, since "batch mode" may be attempting to start a separate transaction to manage the batch. To test this theory, maybe try making it so the removes and adds run in the same batch context.
Also if removeParticipants has NO existing participants to delete, it looks like you call rollback because i==0. Is this what you wanted?

How to write a single query for multiple data manipulation in mysql?

I have to insert values from jsp form to database table and to the same table I need to insert values for two columns from 2 different tables.
Here is the code:
public class ForgotPassWordDAO {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
public void createSecretQnA(ForgotPassWord forgotPassWord) {
String sql = "INSERT INTO forgotpassword (PwdId,SecretQuestion1,SecretAnswer1,SecretQuestion2,SecretAnswer2)VALUES(?,?,?,?,?)"; // Here am inserting form values to database.
String sql1="INSERT INTO forgotpassword (CustId) SELECT CustId FROM signup";// Here am trying to get value from another table and insert
String sql2="INSERT INTO forgotpassword (LoginId) SELECT LoginId FROM login"; // Here am trying to get value from another table and insert
Connection conn = null;
try {
conn = dataSource.createConnection();
PreparedStatement ps = conn.prepareStatement(sql);
PreparedStatement ps1 = conn.prepareStatement(sql1);
PreparedStatement ps2 = conn.prepareStatement(sql2);
ps.setInt(1, forgotPassWord.getId());
ps.setString(2, forgotPassWord.getSq1());
ps.setString(3, forgotPassWord.getAnSq1());
ps.setString(4, forgotPassWord.getSq2());
ps.setString(5, forgotPassWord.getAnSq2());
ps.executeUpdate();
ps1.executeUpdate();
ps2.executeUpdate();
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
catch (NullPointerException e1){
}
finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
}
But on each executeUpdate() its incrementing and the values from the form are stored in one row and in the next row the values from the signup and login tables are getting stored. How to make all this get stored in a single row? Any help is appreciated.
You are doing 3 inserts, so at least 3 rows are created. Also, when you do SELECT CustId FROM signup, how can you ensure that only one and the right value of CustId is taken from signup table? With this query you are fetching all the CustId. Same goes for login table and query.
To merely resolve your problem you have to create a single query:
String sql = "INSERT INTO forgotpassword (PwdId,SecretQuestion1,SecretAnswer1,SecretQuestion2,SecretAnswer2,CustId,LoginId)VALUES(?,?,?,?,?,(SELECT CustId FROM signup),(SELECT LoginId FROM login))";
^ ^ ^ ^
but I don't think you have thought this enough.
There should be something like:
SELECT LoginId FROM login WHERE CustId=? //Here I'm guessing, I don't know your tables.
The point is to get the correct value both in login table and signup table that corresponds to the user who forgot his password. This can be easily done with a WHERE clause (supposing your foreign key are setted correctly).
EDIT
As per your comment I'm going to clarify the way you should add your new user.
First of all you need to create the new user, so as soon as the information needed is sent and checked you insert a new row in signup table. But wait to execute the query.
You need the CustId. Because is an auto-increment column, you don't know which value MySQL created. You must fetch it and you can do it directly when you create the new user adding a parameter to the prepared statement:
PreparedStatement pstmt = conn.prepareStatement(sqlForNewUser, Statement.RETURN_GENERATED_KEYS);
pstmt.executeUpdate();
ResultSet keys = pstmt.getGeneratedKeys();
keys.next();
custId = keys.getInt(1);
Now you have the new user Id and can use it to insert the other values:
String sql = "INSERT INTO forgotpassword (PwdId,SecretQuestion1,SecretAnswer1,SecretQuestion2,SecretAnswer2,CustId,LoginId)VALUES(?,?,?,?,?,(SELECT CustId FROM signup WHERE CustId = ?),(SELECT LoginId FROM login WHERE CustId = ?))";
//...
ps.setString(6, custId);
ps.setString(7, custId);

INSERT INTO ... VALUES ... SELECT. How to make nested statement with INSERT?

Please give me an idea how to execute statement to DB.
There are 2 tables(sorry for incorrect writing - it is just to give information about columns):
contractors(contractor_id, contractor_name, contract_num)
invoices(contractor_id, invoice_num, invoice_date, invoice_amount)
The 'contractor_id' in 'invoices' is a foreign key for 'contractor_id' in 'contractors'. How to insert in 'invoices'-table the following data: invoice_num, invoice_date, invoice_amount, if I have the 'contractor_name' from 'contractors'-table?
The solution which works is:
public void insertInvoiceDataByContractorName(String contractorsName, String invoiceNum, String date, float amount) {
String contrId = null;
try {
preparedStatement = connection.prepareStatement("SELECT contractor_id FROM contractors WHERE contractor_name=?");
preparedStatement.setString(1, contractorsName);
resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
contrId = resultSet.getString(1);
}
preparedStatement = connection.prepareStatement("INSERT INTO invoices VALUES(?, ?, ? ,?)");
preparedStatement.setString(1, contrId);
preparedStatement.setString(2, invoiceNum);
preparedStatement.setString(3, date);
preparedStatement.setFloat(4, amount);
preparedStatement.execute();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if (preparedStatement != null) {preparedStatement.close();}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
I don't know how to make it correct and more simpler by using just one statement. Thank you in advance for pieces of advice.
Use
INSERT INTO invoices SELECT contractor_id, ?, ?, ? FROM contractors WHERE contractor_name=?
this will insert 1 row assuming your contractor name is unique

Java insert into table with auto increment field

How can I insert into a table with primary key autoincrement?
I want to use prepared statements and I keep getting this error 0<1...
I tried with statement and it works :S
public void insertDobavitelj (String dobavitelj,String naslov, String telefon) {
String query = "INSERT INTO dobavitelj(ime,naslov,telefon) VALUES ('"+dobavitelj+"','"+naslov+"','"+telefon+"')";
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
stmt.executeUpdate(query);
/*stmt = conn.prepareStatement(query);
// stmt.setInt(1, 0);
stmt.setString(0, dobavitelj);
stmt.setString(1, naslov);
stmt.setString(2, telefon);
if (stmt.executeUpdate() == 1) {
JOptionPane.showMessageDialog(frame, "Uspesno ste dodali novega dobavitelja");
}
*/
}catch (ClassNotFoundException e) {
JOptionPane.showMessageDialog(frame,"Class not found - insert dobavitelj" );
}catch (SQLException exception) {
JOptionPane.showMessageDialog(frame, "SQL Exception - insert dobavitelj");
exception.printStackTrace();
}
I've tried with:
"INSERT INTO dobavitelj(ime,naslov,telefon) VALUES ('?'.'?','?')"
"INSERT INTO dobavitelj(idDobavitelja,ime,naslov,telefon) VALUES (?.'?'.'?','?')"
Thanx good people :)
You are using stmt.setString(0, dobavitelj); with a zero as index, the statement indexes start at 1.
Also change your query syntax to this: INSERT INTO dobavitelj(ime,naslov,telefon) VALUES ('?'.'?','?')
you can create a random number variable which you will insert in the auto increment column in mysql. multiply the random number by 1000 to get 999 values or 10000 to have 9999 values limit;
int randomnumber = (int) math.random() * 1000
statement.setInt(1, randomnumber)

Java Bulk Insertion Loops Take Time Code Attached?

hi i am new to java and i am inserting in in to database using loop from array it takes time how would i insert data in DB as bulk insertion my code here,
if(con != null)
{
rs = dboperation.DBselectstatement(con,"select host_object_id from nagios_hosts where address='"+ip+"'");
if (rs != null)
{
rs.next();
String id = rs.getString(1);
for(int i= 0;i<serviceArray.length;i++)
{
status.append(serviceArray[i]+"\n");
dboperation.DbupdateStatement(DbAcess.getNagios_connection(),"insert into nagios_servicelist(service_name,host_object_id) values('"+serviceArray[i]+"','"+id+"')");
}
}
}
do not go in detail about this code i tell you that i am getting id from the first query in "rs" resultset and "servicearray" have services that i want to insert in Db but it takes time in loop how will i do this array bulk insertion in Database?
hopes to listen from you soon
Thanks in Advance
You shuld use JDBC bulk insert for your purpose -
//Create a new statement
Statement st = con.createStatement();
//Add SQL statements to be executed
st.addBatch("insert into nagios_servicelist(service_name,host_object_id) values('"+serviceArray[0]+"','"+id+"')");
st.addBatch("insert into nagios_servicelist(service_name,host_object_id) values('"+serviceArray[1]+"','"+id+"')");
st.addBatch("insert into nagios_servicelist(service_name,host_object_id) values('"+serviceArray[2]+"','"+id+"')");
// Execute the statements in batch
st.executeBatch();
You can insert your own logic here. But this is the overview of how this is to be done.
The following code avoids out of memory error as well as SQL injection
String sql = "insert into employee (name, city, phone) values (?, ?, ?)";
Connection connection = new getConnection();
PreparedStatement ps = connection.prepareStatement(sql);
final int batchSize = 1000;
int count = 0;
for (Employee employee: employees) {
ps.setString(1, employee.getName());
ps.setString(2, employee.getCity());
ps.setString(3, employee.getPhone());
ps.addBatch();
if(++count % batchSize == 0) {
ps.executeBatch();
}
}
ps.executeBatch(); // insert remaining records
ps.close();
connection.close();

Categories

Resources