Can't retrieve ID from an insert in JDBC with PreparedStatement - java

I'm trying to get the ID of an insert row which is auto_increment in MySQL. I'm using the parameter Statement.RETURN_GENERATED_KEYS in the prepareStatement method and trying to obtain it via the getGeneratedKeys method. Somehow, it is not retrieving the ID.
It should be noted that the insertion is done, but since the ID is not obtained, I cannot perform the other inserts and that is why it gives me the error "MySQL ERROR 1452", because an insert is being made later with the ID 0 that does not exist.
public int insertar(Compra objC, ArrayList<DetalleCompra> listaDetalle) {
try {
conexion = MySQLConexion.conexion();
conexion.setAutoCommit(false);
procedimientoAlmacenado = conexion.prepareStatement("{call insertar_compra (?, ?)}", Statement.RETURN_GENERATED_KEYS);
fecha = FORMATO_FECHA.parse(objC.getFecha());
fechaSQL = new java.sql.Date(fecha.getTime());
procedimientoAlmacenado.setDate(1, fechaSQL);
procedimientoAlmacenado.setInt(2, objC.getIdCliente());
resultado = procedimientoAlmacenado.executeUpdate();
int idCompra = 0;
ResultSet idGenerada = procedimientoAlmacenado.getGeneratedKeys();
if (idGenerada.next()) {
idCompra = idGenerada.getInt(1);
}
if (resultado != 0) {
for (DetalleCompra x : listaDetalle) {
procedimientoAlmacenado = conexion.prepareCall("{call insertar_detalle_compra (?, ?, ?)}");
procedimientoAlmacenado.setInt(1, idCompra);
procedimientoAlmacenado.setInt(2, x.getIdProducto());
procedimientoAlmacenado.setInt(3, x.getCantidad());
resultado = procedimientoAlmacenado.executeUpdate();
procedimientoAlmacenado = conexion.prepareCall("{disminuir_stock (?, ?)}");
procedimientoAlmacenado.setInt(1, x.getIdProducto());
procedimientoAlmacenado.setInt(2, x.getCantidad());
resultado = procedimientoAlmacenado.executeUpdate();
}
}
conexion.commit();
} catch (Exception e) {
System.out.println(e.getMessage());
try {
conexion.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
if (procedimientoAlmacenado != null)
procedimientoAlmacenado.close();
if (conexion != null)
conexion.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
return resultado;
}
I also tried to create a variable:
String[] generatedId = { "ID" };
and place it in the method prepareStatement:
procedimientoAlmacenado = conexion.prepareStatement("{call insertar_compra (?, ?)}", generatedId);
However, it doesn't work either. I'm suspecting that it has to do with the fact that I'm doing the statement inside a stored procedure, or with setAutoCommit(false), but I can't think of anything else.

Ok so what I did was make the stored procedure return me the last inserted ID:
delimiter $$
create procedure insertar_compra (in fec datetime, in client_id int, out id int)
begin
insert into compra values (null, fec, client_id, 'P');
set id = LAST_INSERT_ID();
end; $$
delimiter ;
And then I got it with the registerOutParameter() method:
public int insertar(Compra objC, ArrayList<DetalleCompra> listaDetalle) {
try {
conexion = MySQLConexion.conexion();
conexion.setAutoCommit(false);
procedimientoAlmacenado = conexion.prepareCall("{call insertar_compra (?, ?, ?)}");
fecha = FORMATO_FECHA.parse(objC.getFecha());
fechaSQL = new Timestamp(fecha.getTime());
procedimientoAlmacenado.setTimestamp(1, fechaSQL);
procedimientoAlmacenado.setInt(2, objC.getIdCliente());
procedimientoAlmacenado.registerOutParameter(3, Types.INTEGER);
resultado = procedimientoAlmacenado.executeUpdate();
int idCompra = 0;
idCompra = procedimientoAlmacenado.getInt(3);
if (resultado != 0) {
for (DetalleCompra x : listaDetalle) {
procedimientoAlmacenado = conexion.prepareCall("{call insertar_detalle_compra (?, ?, ?)}");
procedimientoAlmacenado.setInt(1, idCompra);
procedimientoAlmacenado.setInt(2, x.getIdProducto());
procedimientoAlmacenado.setInt(3, x.getCantidad());
resultado = procedimientoAlmacenado.executeUpdate();
procedimientoAlmacenado = conexion.prepareCall("{call disminuir_stock (?, ?)}");
procedimientoAlmacenado.setInt(1, x.getIdProducto());
procedimientoAlmacenado.setInt(2, x.getCantidad());
resultado = procedimientoAlmacenado.executeUpdate();
}
}
conexion.commit();
} catch (Exception e) {
System.out.println(e.getMessage());
try {
conexion.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
if (procedimientoAlmacenado != null)
procedimientoAlmacenado.close();
if (conexion != null)
conexion.close();
} catch (SQLException e) {
System.out.println(e.getMessage());
}
}
return resultado;
}
Thanks to Mark Rotteveel for the suggestion!

Related

java calling procedure of package no response

I have created an API module of spring boot application to call stored procedure. When it comes to the implementation, stmt.execute cannot be called with no response. Would you please tell me which module or wayout to modify under my java environment is 1.8?
int retVal = -1;
int errCode = -1;
String errText = null;
int outPos;
int pos = 0;
System.out.println("call 2");
String SQL_SELECT = "{call database_sid.test_pkg.get_pc_lue(?,?,?,?,?,?)}";
try (Connection conn = DriverManager.getConnection(DBC_URL, USERNAME, PASSWORD);
CallableStatement preparedStatement = conn.prepareCall(SQL_SELECT);
) {
System.out.println("call db");
preparedStatement.setString(++pos, "OFFER_TYPE");
preparedStatement.setString(++pos, null); // acct srv limit
preparedStatement.registerOutParameter(outPos = ++pos, Types.REF_CURSOR);
preparedStatement.registerOutParameter(++pos, Types.INTEGER);
preparedStatement.registerOutParameter(++pos, Types.INTEGER);
preparedStatement.registerOutParameter(++pos, Types.VARCHAR);
System.out.println("call 10");
ResultSet resultSet = preparedStatement.executeQuery();
System.out.println("call 11");
while (resultSet.next()) {
String value = resultSet.getString("LOOKUP_VALUE");
String type = resultSet.getString("LOOKUP_TYPE");
PcTblBPcLookUp obj = new PcTblBPcLookUp();
obj.setLookUpValue(value);
obj.setLookUpType(type);
result.add(obj);
System.out.println("call 1obecj1");
}
result.forEach(x -> System.out.println(x));
System.out.println("call finish ");
} catch (SQLException e) {
System.err.format("SQL State: %s\n%s", e.getSQLState(), e.getMessage());
} catch (Exception e) {
e.printStackTrace();
System.out.println("call error : " + e.getMessage());
}
You need to execute your stored procedure using execute and then you need to fetch your resultset from opsition registered for out parameter
preparedStatement.execute();
ResultSet rs = (ResultSet) preparedStatement.getObject(outPos);

Looping try/catch statement

I'm trying to take two random rowid from my database. Everything works but I have a scenario when there is only one rowid. I want to make a loop on my try/catch until there is second number in my database.
What I'm doing wrong? Thank you
public void Kaslaimejo() {
String sql = "SELECT rowid FROM Zaidejai WHERE Pirmas < 4 ORDER BY random() LIMIT 2";
Integer value1 = null, value2 = null;
Integer judesiukas1 = null, judesiukas2 = null;
int a = 0;
int k = 15; // kiek kartu? Reikia infinity padaryti
for (a = 0; a < 3; a++) {
try {
Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if (rs.next()) {
value1 = rs.getInt("rowid");
if (rs.next()) {
value2 = rs.getInt("rowid");
PreparedStatement buvo = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo.setInt(1, i);
buvo.setInt(2, value1);
int buvolala = buvo.executeUpdate ();
PreparedStatement buvo2 = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo2.setInt(1, i);
buvo2.setInt(2, value2);
int buvolala2 = buvo2.executeUpdate ();//
i++;
}
System.out.println("Pirmas zaidejas" + value1); // atspausdina 1 random zaideja is duomenu bazes
System.out.println("Antras zaidejas" + value2); // atspausdina 2 random zaideja is duomenu bazes
}
} catch (SQLException e) {
a--;
//System.out.println(e.getMessage());
}
}
}
Right now my program loops two times and then gives me SQLException. How I can loop my program until there is no SQLException?
OK, I've tried to write what I think you're trying to do.
You wait for ever until someone puts at least two entries in the database.
You extract two values, process them, then wait some more.
Some points to watch out:
1. Object comparisons need to be made with .equals() not with ==
2. You might want to provide some way to break out of the infinite loop I've written (while(true)).
3. Careful with null values. They might produce NullPointerException.
4. Try to break up your code into methods. Each large block of code could go into each own method.
public void Kaslaimejo(){
String sql = "SELECT rowid FROM Zaidejai WHERE Pirmas < 4 ORDER BY random() LIMIT 2";
Integer judesiukas1 = null, judesiukas2 = null;
while(true) {
List<Integer> values = new ArrayList<>();
while (values.size() < 2) {
try (Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
if( rs.next() ){
Integer value = rs.getInt("rowid");
values.add(value);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
try( Connection conn = Serveris.connect()) {
PreparedStatement buvo = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo.setInt(1, i);
buvo.setInt(2, values.get(0));
int buvolala = buvo.executeUpdate ();
PreparedStatement buvo2 = conn.prepareStatement("UPDATE Zaidejai SET Numeriukas = ? WHERE rowid = ?");
buvo2.setInt(1, i);
buvo2.setInt(2, values.get(1));
int buvolala2 = buvo2.executeUpdate ();//
i++;
}catch (SQLException e) {
e.printStackTrace();
}
Connection conn = Serveris.connect();
try {
PreparedStatement pstmt = conn.prepareStatement("SELECT Pirmas FROM Zaidejai WHERE rowid = ?");
PreparedStatement pstmt2 = conn.prepareStatement("SELECT Pirmas FROM Zaidejai WHERE rowid = ?");
pstmt.setInt(1, values.get(0));
pstmt2.setInt(1, values.get(1));
ResultSet myrsv = pstmt.executeQuery();
ResultSet myrsv2 = pstmt2.executeQuery();
{
if (myrsv.next()) {
judesiukas1 = myrsv.getInt("Pirmas");
if (myrsv2.next()) {
judesiukas2 = myrsv2.getInt("Pirmas");
}
}
//System.out.println("Pirmo zaidejo veiksmas" + myrsv.getInt("Pirmas"));
//System.out.println("Antro zaidejo veiksmas" + myrsv2.getInt("Pirmas"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (judesiukas1.equals(judesiukas2)) // careful here. NullPointerException may happen.
{
try {
PreparedStatement laim = conn.prepareStatement("UPDATE Zaidejai SET Rezultatas = ? WHERE rowid = ?"); // ble ble update reikia naudoti , o ne insert into. Insert kai sukuriame nauja kazka tik
PreparedStatement laim2 = conn.prepareStatement("UPDATE Zaidejai SET Rezultatas = ? WHERE rowid = ?");
laim.setString(1, "Lygiosios");
laim.setInt(2, values.get(0));
laim2.setString(1, "Lygiosios");
laim2.setInt(2, values.get(1));
int irasyk = laim.executeUpdate (); // kodel executeupdate, o ne executequery????
int irasyk2 = laim2.executeUpdate (); // kodel executeupdate, o ne executequery????
{
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.print("Lygiosios");
} else {
// (1) - Rock
// (2) Scissors
// (3) - Paper
switch (values.get(0)){
case 1:
if (judesiukas2 == 2)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
case 2:
if (judesiukas2 == 3)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
case 3:
if (judesiukas2 == 1)
System.out.print("Zaidejas 1 wins!");
else
System.out.print("Zaidejas 2 wins!");
break;
}
}
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The logic becomes easier if you add the values to a list
var values = new ArrayList<Integer>();
while (values.Count < 2) {
try (Connection conn = Serveris.connect();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql))
{
while (values.Count < 2 && rs.next()) {
Integer v = rs.getInt("rowid");
values.Add(v);
}
} catch (SQLException e) {
}
}
//TODO: process the values here
The advantage is, that you can retrieve one value at the first database query and the second at a later one or both in the same round and you don't have to keep track of which one of two variables to use.
(Bear with me with the syntax details, I'm not a Java programmer.)
How i can loop my program until there is no SQLException?
Change this (because, it will only allow to loop two times)
for (a = 0; a < 2; a++) {
to
while(true)
Put everything inside while(true), if exception occurred, then it will come out from the while loop. Something similar :
try
{
while(true)
{
...
...
}
...
}
catch(SQLException e)
{
// do somthing
}

Java Heap space with jpa native Query

I am having an OOME problem when trying to run a native SQL query through the jpa / hibernate EM.
The treatment serves to make millions of insertion per pack of 50.
Here is code of my algorithm:
private void createNewJetonsForIndividus(boolean isGlobal, List<String> entreprises, List<String> services,
String user, Timestamp dateDB) {
LocalDateTime timer = LocalDateTime.now();
List<Object[]> MinMaxId = getMinMaxIdDroitsIndividusActifsForCreation(
isGlobal, entreprises, services);
if (null != MinMaxId.get(0)[0]) {
int idStart = ((BigInteger) MinMaxId.get(0)[0]).intValue();
int idEnd = idStart + PAS;
int idMax = ((BigInteger) MinMaxId.get(0)[1]).intValue();
int nbRowsTotal = 0;
Logger.debug("Droits Individus : ID Min {} - ID Max {}", idStart, idMax);
do {
int finalIdStart = idStart;
int finalIdEnd = idEnd;
callTransaction(() -> create(false, true,isGlobal, entreprises, services, finalIdStart,
finalIdEnd, user, dateDB));
idStart = idEnd + 1;
idEnd = idEnd + PAS;
}
while (idMax > idEnd);
}
}
the method is used to calculate the id min and max of the records that interest my treatment. Subsequently, I use the create method whose code is below :
int nbRowsFind;
List<Object[]> listeDroitsIndividusActifsForCreation = getDroitsIndividusActifsForCreation(
isGlobal, entreprises, services, idStart, idEnd);
if (ValidationUtils.isNotEmpty(listeDroitsIndividusActifsForCreation)) {
nbRowsFind = listeDroitsIndividusActifsForCreation.size();
StringBuilder sbJeton = new StringBuilder();
sbJeton.append("INSERT INTO sigs_nv_jeton VALUES ");
StringBuilder sbDroitHasJeton = new StringBuilder();
if (isCreateForIndiv) {
sbDroitHasJeton.append("INSERT INTO sigs_droits_individu_has_nv_jeton VALUES ");
}
listeDroitsIndividusActifsForCreation.stream().forEach(object -> {
sbJeton.append("(");
sbDroitHasJeton.append("(");
BigInteger idDroit = (BigInteger) object[0];
String jetonGenerated = IdJetonGenerator.codeGenerator(idDroit.toString(), DateUtils.now());
sbJeton.append("'").append(jetonGenerated).append("', ");
appendDate(sbJeton, object[1]);
appendDate(sbJeton, object[2]);
sbJeton.append(0).append(", ");
sbJeton.append(0).append(", ");
sbJeton.append("'").append(dateDB).append("', ");
sbJeton.append("'").append(user).append("'");
sbDroitHasJeton.append(idDroit).append(",'").append(jetonGenerated).append("'");
sbJeton.append("),");
sbDroitHasJeton.append("),");
});
String requestJeton = sbJeton.toString();
sbJeton.delete(33, sbJeton.length());
requestJeton = requestJeton.substring(0, requestJeton.length() - 1);
jpaApi.em().createNativeQuery(requestJeton).executeUpdate();
String requestDroitHasJeton = sbDroitHasJeton.toString();
sbDroitHasJeton.delete(54, sbDroitHasJeton.length());
requestDroitHasJeton = requestDroitHasJeton.substring(0, requestDroitHasJeton.length() - 1);
**jpaApi.em().createNativeQuery(requestDroitHasJeton).executeUpdate();**
**jpaApi.em().flush();
jpaApi.em().clear();**
}
When I analyze the Heap Dump, I notice that despite the flush and clear, queries are still referenced in the SessionFactory, is this normal?
enter image description here
flush is executing changes made in the unit of work and clear removes entities from the persistence context.
Both have nothing to do with native SQL queries. I assume that the native queries are cached anywhere else (Hibernate, JDBC...)
I would suggest that you use a prepared statement instead of your dynamic insert statement.
This is my new implementation :
Statement statement = null;
ResultSet resultSet = null;
int nbRows = 0;
try {
statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
try {
resultSet = statement.executeQuery(queryGetDroitsEntreprisesActifsForCreation(isGlobal, entreprises, services));
resultSet.beforeFirst();
while (resultSet.next()) {
nbRows += 1;
queryInsertJetonsAndLinkDroitsJeton(isCreateForEntreprise, isCreateForIndiv, connection, resultSet,
user, dateDB);
}
System.out.println(nbRows);
} finally {
if (resultSet != null) {
resultSet.close();
}
}
} finally {
if (statement != null) {
statement.close();
}
}
The method "queryGetDroitsEntreprisesActifsForCreation" returns a SQL query in String.
The method "queryInsertJetonsAndLinkDroitsJeton" use the famous PreparedStatement :
PreparedStatement psJeton = null;
PreparedStatement psDroitJeton = null;
try {
String sbJeton = "INSERT INTO TABLE1 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ";
psJeton = connection.prepareStatement(sbJeton);
String jetonGenerated;
if (isCreateForEntreprise) {
jetonGenerated = IdJetonGenerator.codeGenerator(String.valueOf(resultSet.getInt("id_e")), DateUtils.now());
} else {
jetonGenerated = IdJetonGenerator.codeGenerator(String.valueOf(resultSet.getInt("id_i")), DateUtils.now());
}
psJeton.setString(1, jetonGenerated);
psJeton.setString(2, ContextType.GD.name());
psJeton.setString(3, JetonType.ANONYME.name());
psJeton.setInt(4, 1);
psJeton.setTimestamp(5, resultSet.getTimestamp("dt_debut"));
psJeton.setTimestamp(6, resultSet.getTimestamp("dt_fin"));
psJeton.setInt(7, 0);
psJeton.setInt(8, 0);
psJeton.setInt(9, 0);
psJeton.setInt(10, 0);
psJeton.setTimestamp(11, dateDB);
psJeton.setString(12, user);
psJeton.setTimestamp(13, dateDB);
psJeton.setString(14, user);
psJeton.executeUpdate();
String sbDroitHasJeton = null;
if (isCreateForEntreprise) {
sbDroitHasJeton = "INSERT INTO sigs_dej VALUES (?, ?)";
}
if (isCreateForIndiv) {
sbDroitHasJeton = "INSERT INTO sigs_dij VALUES (?, ?)";
}
psDroitJeton = connection.prepareStatement(sbDroitHasJeton);
if(isCreateForEntreprise) {
psDroitJeton.setInt(1, resultSet.getInt("id_e"));
} else {
psDroitJeton.setInt(1, resultSet.getInt("id_i"));
}
psDroitJeton.setString(2, jetonGenerated);
psDroitJeton.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (psJeton != null) {
psJeton.close();
}
if (psDroitJeton != null) {
psDroitJeton.close();
}
}
I hope this is the best implementation of PreparedStatement & Scrollable ResultSet

SQL executeBatch slow processing

Basically i have to read a csv file and perform some validation.
If duplicate record is found i've to delete the previous record and insert the latest 1.
The file contains about 100k records. I'm not sure what I'm doing wrongly but it's taking way too long to load the data.
public static ArrayList<BootstrapMessage> loadLocation(File file) {
ArrayList<BootstrapMessage> errors = new ArrayList<BootstrapMessage>();
CSVReader reader = null;
Connection conn = null;
Connection conn2 = null;
PreparedStatement pstmt = null;
PreparedStatement ps = null;
try {
conn = ConnectionManager.getConnection();
conn2 = ConnectionManager.getConnection();
conn.setAutoCommit(false);
pstmt = conn.prepareStatement(INSERT_LOCATION);
ps = conn2.prepareStatement("delete from location where `timestamp` = ? AND mac_address = ?");
reader = new CSVReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
reader.readNext();//header
String[] record = reader.readNext();
int counter = 2;//starting from line 2. Line 1 is header
int validRecords = 0;
while (record != null) {
ArrayList<String> message = null;
//try {
message = ValidatorUtil.validateLocation(record, file.getName(), counter);
if (message != null) {//contains error
errors.add(new BootstrapMessage(file.getName(), counter, message));
} else {//valid record
String key = record[0] + record[1];
if (locations.containsKey(key)) {//duplicate found.
pstmt.executeBatch();
message = new ArrayList<String>();
message.add("duplicate row");
errors.add(new BootstrapMessage(file.getName(), locations.get(key), message));
//delete record from database
ps.setTimestamp(1, Timestamp.valueOf(record[0]));
ps.setString(2, record[1]);
ps.executeUpdate();
//inserting the latest record
pstmt.setTimestamp(1, Timestamp.valueOf(record[0]));
pstmt.setString(2, record[1]);
pstmt.setInt(3, Integer.parseInt(record[2]));
pstmt.addBatch();
if (validRecords % 2000 == 0) {
pstmt.executeBatch();
}
} else {
pstmt.setTimestamp(1, Timestamp.valueOf(record[0]));
pstmt.setString(2, record[1]);
pstmt.setInt(3, Integer.parseInt(record[2]));
pstmt.addBatch();
validRecords++;
if (validRecords % 2000 == 0) {
pstmt.executeBatch();
}
}
}
if (validRecords > 0) {
pstmt.executeBatch();
conn.commit();
}
record = reader.readNext();
counter++;
}
System.out.println("valid location records = " + validRecords);
//numOfValidRecords.put(fileName, validRecords);
if (!errors.isEmpty()) {
return errors;
}
} catch (FileNotFoundException ex) {
Logger.getLogger(LocationDAO.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(LocationDAO.class.getName()).log(Level.SEVERE, null, ex);
} catch (SQLException ex) {
Logger.getLogger(LocationDAO.class.getName()).log(Level.SEVERE, null, ex);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
Logger.getLogger(LocationDAO.class.getName()).log(Level.SEVERE, null, ex);
}
}
ConnectionManager.close(conn2, ps);
ConnectionManager.close(conn, pstmt);
}
return null;
}
Why don't you use native database loaders to do the job?
Or I would first insert all the records into staging and then do the duplicate removals by using the database tools, either SQL or some database procedure. This way it has to be faster.

Multiple stored procedures with input and output parameters called from java

I want to add a new row in a table - NewOrder which has the columns ID, OrderDate, OrderValue using the following stored procedure.
create proc [dbo].[insert_new_order]( #newID int OUTPUT,
#oValue float)
as
begin
insert into NewOrder values (GETDATE(),#oValue)
set #newID = ##IDENTITY
end
The #newID represents one of the input parameters for the following stored procedure which inserts a new row in the table OrderedProduct which has the columns ProductID, OrderID, Price, Quantity
create proc [dbo].[insert_updates_in_ordered_product] ( #newID int,
#productID int,
#price float,
#qty int)
as
begin
insert into OrderedProduct values(#productID,#newID,#qty,#price)
end
I am calling these 2 stored procedures like this:
public static void addNewOrderToDB(ArrayList<Product> list){
Connection connection = null;
CallableStatement statement1 = null;
String q1 = "{? = CALL insert_new_order(?)}";
String q2 = "{CALL insert_updates_in_ordered_product(?,?,?,?)}";
float orderValue = 0;
//calculate orderValue
for(Product p : list){
orderValue = orderValue + (p.getPrice() * p.getQty());
}
System.out.println(orderValue);
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
connection = DriverManager.getConnection(url);
statement1 = connection.prepareCall(q1);
statement1.registerOutParameter(1, Types.INTEGER);
statement1.setFloat(2, orderValue);
ResultSet rs = statement1.executeQuery();
int uniqueID = rs.getInt(1);
System.out.println(uniqueID);
statement1 = connection.prepareCall(q2);
for(Product p : list){
statement1.setInt(1, p.getProductId());
statement1.setInt(2,uniqueID);
statement1.setInt(3, p.getQty());
statement1.setFloat(4, p.getPrice());
}
statement1.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally{
if(statement1 != null){
try {
statement1.close();
} catch (SQLException e) {
System.err.println("SQLException: " + e.getMessage());
}
}
if(connection != null){
try {
connection.close();
} catch (SQLException e) {
System.err.println("SQLException: " + e.getMessage());
}
}
}
}
But i get this error:
com.microsoft.sqlserver.jdbc.SQLServerException: Procedure or function 'insert_new_order' expects parameter '#oValue', which was not supplied.
How can i fix this?
Does it work if you change like this?
String q1 = "{CALL insert_new_order(?, ?)}";
That matches your create proc better.

Categories