JdbcTemplate to batchUpdate to multiple tables at same time - spring-jdbc

JdbcTemplete.batchUpdate() can take a prepared statement and can fire off a number of inserts to the same table.
String sql = "INSERT INTO MYTABLE (COL1, COL2) VALUES (?, ?)"
List params = ...
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
public void setValues(PreparedStatement ps, int i) throws SQLException {
List<String> singleRowParams = params.get(i);
ps.setString(1, singleRowParams.get(0));
ps.setString(2, singleRowParams.get(1));
}
// This is the number of times to run the SQL statement.
public int getBatchSize() {
return params.size();
}
}
);
How do I insert into mutliple tables in the one batch update, is that even possible?
Thanks

No it's not possible. Think about if you were trying to run this SQL manually, how would you go about doing it? An alternative would be to iterate over your updates and amend the SQL each time for the relevant table(s).

Related

How to write transaction in Mariadb?

using query " BEGIN; INSERT INTO employee (id, name) VALUES (:id,:name); COMMIT ;" to commit the transaction through java code and additionally setting id and name parameters but getting below error.
"Caused by: java.sql.SQLSyntaxErrorException: (conn=812) You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'INSERT INTO employee (id, name) VALUES (150,'150_abc'); COMMIT' at line 1
have tried with belwo query:
start transaction; INSERT INTO employee (id, name) VALUES (:id,:name); COMMIT ;
using MariaDb version 10.7.3
you should try the following :
MOST IMPORTANT TO CONSIDER, IS TO SET THE AUTOCOMMIT TO FALSE, otherwise MariaDB will refuse not automatic transaction management.
import java.sql.*;
public class App {
public static void main(String[] argv) {
try (Connection conn = DriverManager.getConnection("jdbc:mariadb://192.0.2.1:3306?user=db_user&password=db_user_password")) {
conn.setAutoCommit(false);
try {
try (PreparedStatement prep = conn.prepareStatement("INSERT INTO test.accounts(first_name, last_name, email, amount) VALUES (?, ?, ?, ?)")) {
prep.setString(1, "John");
prep.setString(2, "Smith");
prep.setString(3, "john.smith#example.com");
prep.setDouble(4, 900.00);
prep.executeQuery();
}
try (PreparedStatement prep = conn.prepareStatement("UPDATE test.accounts SET amount = ? WHERE email = ?")) {
prep.setDouble(1, 1000.00);
prep.setString(2, "john.smith#example.com");
prep.executeQuery();
}
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
conn.rollback();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

retrieve a row of data from documentum via DQL

I have a list of users in my list view which is populated by retrieving data from documentum . If I click on any row of this least (each row represent one user) I should be able to see all of their information listed down .(This is my problem )
public void selectedItemFromListView(){
selected = lwAllUserGrp.getSelectionModel().getSelectedItem();
System.out.println(selected);
String query =" select * from dm_user where user_name = '#aclName'" ;
String test = query.replace("#aclname", selected);
GetDataWithDqlProfile(_session , query , "user_login_name" , "user_address" , "user_state" );
System.out.println(user.getAddress());
System.out.println(user.getState());
System.out.println(user.getUsername());
}
if I click on a row of list view I can successfully see who is selected and I need to retrieve all the other attributes of that username (same person) from documentum via DQL .
private void GetDataWithDqlProfile(IDfSession session, String Query, String username , String address , String state ) {
try {
IDfQuery UpdateQuery = new DfQuery();
UpdateQuery.setDQL(Query);
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
user.setAddress(col.getString(username));
user.setUsername(col.getString(address));
user.setState(col.getString(state));
col.close();
} catch (Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.showAndWait();
Logs.WriteLog(LoginController.Repository + ",User:" + LoginController.Username, "DQL Query", e.toString());
e.getStackTrace();
}
and my output is :
User's name
null
null
null
I've tried the DQL query in DQL tester and it works well
In order to fetch rows from IDfCollection you have to call next() on the collection object. This method both advances to the next row and returns a boolean if successful. Use a boolean test (e.g., while or if) to iterate, like this:
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
if (col.next()) {
user.setAddress(col.getString(username));
user.setUsername(col.getString(address));
user.setState(col.getString(state));
}
col.close();
The iteration is necessary even if the collection contains only one row. In other words, you need to manually advance to the first row.
1) As #eiviamu already mentioned, you have to call IDfCollection.next() to get the next row.
2) Your code, among other problems, has one documentum-related: closing of collection must happen always in finally block.
Otherwise you can get unclosed collection which might lead to memory leaks and weird application behavior (e.g. if I'm not mistaken there are 9 simultaneous open collections are allowed for one DCTM session by default, and if you exceed this limit an exception will be thrown)
For those of you referring to this question later here is how I solved the problem :
public ArrayList<User> GetDataWithDqlpro(IDfSession session, String Query, String username , String state , String address) {
try {
IDfQuery UpdateQuery = new DfQuery();
UpdateQuery.setDQL(Query);
IDfCollection col = UpdateQuery.execute(_session, IDfQuery.DF_QUERY);
while (col.next()) {
list.add( new User(col.getString(username),col.getString(address) , col.getString(state)));
}
col.close();
}catch (Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR, e.getMessage());
alert.showAndWait();
Logs.WriteLog(LoginController.Repository + ",User:" + LoginController.Username, "DQL Query", e.toString());
e.getStackTrace();
}
return (ArrayList<User>) list;
}
public void selectedItemFromListView(){
selected = lwAllUserGrp.getSelectionModel().getSelectedItem();
System.out.println(selected);
String Query = "select user_login_name , user_state , user_address from dm_user where user_login_name ='#aclname'";
Query = Query.replace("#aclname",selected );
ArrayList<User> allUserNames = GetDataWithDqlpro(_session, Query, "user_login_name","user_address","user_state");
for (int i = 0 ; i <= allUserNames.size()-1 ; i++ ){
if (selected.compareToIgnoreCase(allUserNames.get(i).getUsername() ) == 0){
System.out.println(allUserNames.get(i).getState() );
System.out.println(allUserNames.get(i).getAddress() );
System.out.println(allUserNames.get(i).getUsername() );
}
}
}
Worth mentioning that I have a class called User with constructor and get and set methods
I hope it will help some one :)

How to check table is empty with count(*)

I am trying to check if a table is empty. I code this method:
public boolean checkIfNULL()
throws SQLException, ClassNotFoundException {
boolean flag=false;
System.out.println("Checking if table is empty...");
String sq = "select count(*) from TABLE1";
try {
Class.forName(typeDB);
c = DriverManager.getConnection(path);
stm = c.prepareStatement(sq);
PreparedStatement stm = c.prepareStatement(sq);
int rowsAffected = stm.executeUpdate();
if(rowsAffected == 0)
flag=true;
} catch (SQLException e) {
System.out.println(e.getMessage());
} finally {
if (stm != null) {
stm.close();
}
if (c != null) {
c.close();
}
}
return flag;
}
but sth wrong is hapenning and I get an error message
Query returns results
Exceptionn: java.sql.SQLException: [SQLITE_ERROR] SQL error or missing database (Connection is closed)
How I check the returning value of check?
UPDATE 1:
Instead of the query above, I tried also SELECT EXISTS(SELECT 1 FROM TABLE1)
but the same is happening..
UPDATE 2:
I used this:
ResultSet rs = stm.executeQuery();
if(!rs.next())
flag=true;
else
System.err.println("ERROR - The table has records...");
and it prints the ERROR - "The table has records...". How is this possible? I see the table through SQLite manager and it is empty!
You are executing a SELECT, so you need to use executeQuery, not executeUpdate. executeUpdate is for statements like UPDATE, DELETE and INSERT, executeQuery is for executing statements that return a result set (like SELECT).
You need to execute a select statement, and do:
try (ResultSet rs = stm.executeQuery()) {
rs.next(); // You always have a row, with the count
int count = rs.getInt(1);
flag = count == 0;
}
The code in your update won't work, because if you do a SELECT count(*) FROM table, then you always have one row (with the count).

Dapper and Downward Integer Conversion

I am checking out v1.25 of Dapper with Sqlite via System.Data.Sqlite. If I run this query:
var rowCount = dbc.Query<int>("SELECT COUNT(*) AS RowCount FROM Data").Single();
I get the following error: System.InvalidCastException: Specified cast is not valid
This is because Sqlite returns the above value as an Int64, which I can verify with the following code. This will throw "Int64":
var row = dbc.Query("SELECT COUNT(*) AS RowCount FROM Data").Single();
Type t = row.RowCount.GetType();
throw new System.Exception(t.FullName);
Now, the following code will actually handle the downward conversion from Int64 to Int32:
public class QuerySummary
{
public int RecordCount { get; set; }
}
var qs = dbc.Query<QuerySummary>("SELECT COUNT(*) AS RecordCount FROM Data").Single();
rowCount = qs.RecordCount;
throw new System.Exception(rowCount.ToString());
When I throw this exception, it gives me the actual row count, indicating that Dapper handled the conversion for me.
My question is, why is it that dbc.Query<int> does not handle the downward conversion in a similar way to dbc.Query<QuerySummary>? Is this intended behavior?
No, that is not intentional. I've committed and pushed changes to github which make the following pass (it fails on 1.25); it should appear on NuGet at some point soon too:
// http://stackoverflow.com/q/23696254/23354
public void DownwardIntegerConversion()
{
const string sql = "select cast(42 as bigint) as Value";
int i = connection.Query<HasInt32>(sql).Single().Value;
Assert.IsEqualTo(42, i);
i = connection.Query<int>(sql).Single();
Assert.IsEqualTo(42, i);
}

"Cannot add an entity that already exists" while deleting and recreating record with LINQ

While trying to delete a record in a database and recreate it afterwards, using LINQ, I get the error: Cannot add an entity that already exists.
Although the record is deleted.
I am initialising my Sales_header object with data I get from a LINQ query in method
SelectOrdersByOrderID(OrderID).
If the OrderID of the Salesheader meets a certain condition, I want to delete the record in the database (Delete(Sales_header SalesHeader)), add additional values to the object and insert a new record in the database (Insert(Sales_header SalesHeader)).
I do not want to update the record, but delete it and recreate it.
Sales_header SalesHeader = new Sales_header();
SalesHeader = SalesHeaderClass.SelectOrdersByOrderID(OrderID) as Sales_header;
if (SalesHeader.OrderID == *certain value*)
{
SalesHeaderClass.Delete(SalesHeader);
SalesHeader.Orderdate = DateTime.Today;
SalesHeader.Ordertime = DateTime.Now;
SalesHeaderClass.Insert(SalesHeader);
}
...
Method in SalesHeaderClass to select the SalesHeader via LINQ
public static object SelectOrdersByOrderID(int OrderID)
{
var Query = (from p in dc.Sales_headers
where p.OrderID.Equals(OrderID)
select p).SingleOrDefault();
return Query;
Method in SalesHeaderClass to insert the SalesHeader via LINQ
public static void Insert(Sales_header SalesHeader)
{
dc.Sales_headers.InsertOnSubmit(SalesHeader);
dc.SubmitChanges();
}
Method in SalesHeaderClass to delete the SalesHeader via LINQ
public static void Delete(Sales_header SalesHeader)
{
var DelOrder = (from p in dc.Sales_headers
where p.OrderID == SalesHeader.OrderID
select p).Single();
dc.Sales_headers.DeleteOnSubmit(DelOrder);
dc.SubmitChanges();
}
What do I have to do to be able to insert the record?
Creating a new object with the same values does not help.
Aside from the question why an update is not suitable.
You need two contexts to first delete the record, and then insert the record. EF keeps all inserts/updates/deletes in memory until you do a SubmitChanges(), so you cannot have two entities with the same ID.
But to execute the whole things as a single transaction, you're going to need a TransactionScope.
using (var scope = new TransactionScope()) {
using (var salesHeader SalesHeader = new Sales_header()) {
// Delete record
...
salesHeader.SubmitChanges();
}
using (var salesHeader SalesHeader = new Sales_header()) {
// Insert record
...
salesHeader.SubmitChanges();
}
// Mark transaction complete
scope.Complete();
}
To fix this issue, use different datacontext for delete and insert operation.

Resources