Spring Jdbc Template + MySQL = TransientDataAccessResourceException : Invalid Argument Value : Java.io.notSerializationException - java

I was using spring jdbc template to insert some data into the database and I was getting this error.
Here is my code :
JdbcTemplate insert = new JdbcTemplate(dataSource);
for(ResultType result : response.getResultSet().getResult())
{
Object[] args = new Object[] {result.getAddress(), result.getCity(), result.getState(), result.getPhone(), result.getLatitude(), result.getLongitude(),result.getRating().getAverageRating(), result.getRating().getAverageRating(), result.getRating().getTotalRatings(), result.getRating().getTotalReviews(), result.getRating().getLastReviewDate(), result.getRating().getLastReviewIntro(), result.getDistance(), result.getUrl(), result.getClickUrl(), result.getBusinessUrl(), result.getBusinessClickUrl()};
insert.update("INSERT INTO data.carwashes ( address, city, state, phone, lat, lng, rating, average_rating, total_ratings, total reviews, last_review_date, last_review_intro, distance, url, click_url, business_url, business_click_url, category_id, zipcode_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,96925724,78701)", args);
}
Quite lengthy code.. but, basically it gets the value from a object and sticks it to a array and passed that array to insert method of jdbc template.
Any help will be appreciated.

My guess is that one of the items in your arg array is of a type not recognised by JdbcTemplate, (i.e. it's not a String, a Date, and so on), and so it's calling setObject() on the statement. The driver will then try to serialize the argument into a binary, discovers it's not serializable, and throws the exception.
Make sure the arguments in the array are all what you think they should be, e.g. they shouldn't be instances of your own classes, but should be standard Java types.

Related

Java SQL - Insert into table only new entries

I am trying to insert new entries into my database, but only the new entries. If a class with the crn that I am adding already exists in the database then I would like to skip it to not have duplicates.
Below is the code I have right now. I have tried a few different methods but I keep getting exception:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'EXCEPT crn' at line 1
The database entry works fine without the "EXCEPT crn", but again it adds duplicates.
try {
String query = null;
try {
query = "INSERT INTO Classes (crn, subject, creditHours, title, capacity, instructor, schedule) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?) EXCEPT crn";
} catch(Exception e) {
conn.close();
}
PreparedStatement preparedStmt = conn.prepareStatement(query);
preparedStmt.setInt(1, crn);
preparedStmt.setString(2, subject);
preparedStmt.setInt(3, creditHours);
preparedStmt.setString(4, title);
preparedStmt.setString(5, capacity);
preparedStmt.setString(6, instructor);
preparedStmt.setString(7, schedule);
preparedStmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
If a class with the crn that I am adding already exists in the database then I would like to skip it to not have duplicates.
In MySQL, I would recommend the insert ... on duplicate key syntax:
INSERT INTO Classes (crn, subject, creditHours, title, capacity, instructor, schedule)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE crn = VALUES(crn);
For this to work, you need a unique constraint (or the like) on column crn:
ALTER TABLE Classes ADD CONSTRAINT cs_classes_uniq_crn UNIQUE(crn);
Then, when an INSERT occurs that would generate a duplicate crn, the query goes to the UPDATE clause, that actually performs a no-op.
Can you alter the row or rows you want? You could just put a unique constraint on them so they can't accept columns that have the same value.
ALTER TABLE table_name
ADD UNIQUE (column_name);
If you need multiple columns you can add the constraint to the table like this:
ALTER TABLE table_name
ADD CONSTRAINT constraint_name UNIQUE (column1, column2, etc);
The SQL statement that you try to execute is invalid because MySql does not support EXCEPT.
Since you want to skip the insertion of rows that already exist you can use INSERT IGNORE:
query = "INSERT IGNORE INTO Classes (crn, subject, creditHours, title, capacity, instructor, schedule) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?)";
but for this to work there should be a unique constraint for the column crn.It seems like it is the PRIMARY KEY of the table so it is already unique.
If there isn't a unique constraint for the column crn you can use NOT EXISTS like this:
query = "INSERT INTO Classes (crn, subject, creditHours, title, capacity, instructor, schedule) "
+ "SELECT ?, ?, ?, ?, ?, ?, ? "
+ "WHERE NOT EXISTS (SELECT 1 FROM Classes WHERE crn = ?)";
so you will have to pass as the 8th parameter of the Prepared Statement crn again:
preparedStmt.setInt(8, crn);

Java validating column length before inserting into the database

Sorry it's maybe an easy question but I can't find anything on Google. I'm parsing csvData with e.g. more than 100000 rows / objects. I want to check that ALL values for the attributes are valid before they get written into the database. Annotations like #Size or #Length do not help...
To give you an example:
Entity:
#Entity
#Data
public class Transaction {
#Size(max = 30)
private String timestamp;
}
The csv is parsed and the objects are written down in a List.
List<Transaction> transaction = new ArrayList<>();
// list will be filled
try {
databaseConnector.saveAllTransactions(transaction, transactionRepository);
} catch (ConstraintViolationException exc) {
System.out.println(exc.getMessage());
}
The error that appears after the 5th object.
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into transaction (amount, customer_customer_id, discount, receipt_no, receipt_pos_no, timestamp, unit_price) values (?, ?, ?, ?, ?, ?, ?)
Validation failed for classes [com.stuff.project.entity.Transaction] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='muss zwischen 0 und 30 liegen', propertyPath=timestamp, rootBeanClass=class com.stuff.project.entity.Transaction, messageTemplate='{javax.validation.constraints.Size.message}'}
]
Only that you know how the method looks like.
public boolean saveAllTransactions(List<Transaction> transactions, TransactionRepository transactionRepository) {
transactionRepository.saveAll(transactions);
return true;
}
The only thing I could imagine is to go through the whole list of objects and check for each object the attributes for it's length like:
transactions.forEach(e -> e.getTimestamp().length != 30); ....
That does not seem to be very performance friendly...
First of all: performance shouldn't be your primary concern. You have a list with N entries, and when you want to check the string length for each of the N entries, hey: you have to iterate the N entries, and look at each one. Of course, you could theoretically do that in parallel, which, given "enough" data to work with, makes things quicker, at the cost of more CPU power being used.
The real problem: you start to implement "extra validation", instead of relying on your annotations. In other words: you are working "around" your framework. That is rarely a good idea.
Assuming we are talking generic Java (bean) annotations, the canonical answer would be to do two things:
to create a class that represents a list of your Transaction objects
to provide a custom validator that works on that list (and that knows to iterate all entries, and check that string length)

java.sql.sqlexpcetion:ORA-00917:missing comma

I am sorry that i ask a very stupid question but i cant find the place where i miss the comma in the code..
sqlStr.append("INSERT INTO DS_GOAL ");
sqlStr.append("(DS_SITE_CODE, DS_FINANCIAL_YEAR, DS_DEPARTMENT_CODE, DS_PLAN_ID, DS_GOAL_ID, ");
sqlStr.append("DS_DESC, TO_CHAR(DS_PLAN_END_DATE, \"dd/MM/YY\"),");
sqlStr.append("DS_CORP_OBJECTIVE, DS_CORP_OBJECTIVE_OTHER, DS_FOCUS, DS_FOCUS_OTHER, ");
sqlStr.append("DS_TOTAL, DS_EQUIPMENT, DS_RECRUIT, DS_FTE, ");
sqlStr.append("DS_CREATED_USER, DS_MODIFIED_USER, DS_GOAL_ORDER ) ");
sqlStr.append("VALUES ");
sqlStr.append("(?, ?, ?, ?, ?,");
sqlStr.append("?, ?,");
sqlStr.append("?, ?, ?, ?,");
sqlStr.append("?, ?, ?, ?,");
sqlStr.append("?, ?, ?)");
sqlStr_insertGoal = sqlStr.toString();
After the
sqlStr.toString()
the console shows
INSERT INTO DS_GOAL (DS_SITE_CODE, DS_FINANCIAL_YEAR, DS_DEPARTMENT_CODE, DS_PLAN_ID,
DS_GOAL_ID,
DS_DESC, TO_CHAR(DS_PLAN_END_DATE, 'dd/MM/YYYY'),
DS_CORP_OBJECTIVE, DS_CORP_OBJECTIVE_OTHER, DS_FOCUS, DS_FOCUS_OTHER,
DS_TOTAL, DS_EQUIPMENT, DS_RECRUIT,
DS_FTE, DS_CREATED_USER, DS_MODIFIED_USER, DS_GOAL_ORDER)
VALUES (?, ?, ?, ?, ?,?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?)
After Edited the code
the console shows
INSERT INTO DS_GOAL (DS_SITE_CODE, DS_FINANCIAL_YEAR, DS_DEPARTMENT_CODE, DS_PLAN_ID,
DS_GOAL_ID,
DS_DESC, DS_PLAN_END_DATE,
DS_CORP_OBJECTIVE, DS_CORP_OBJECTIVE_OTHER, DS_FOCUS, DS_FOCUS_OTHER,
DS_TOTAL, DS_EQUIPMENT, DS_RECRUIT,
DS_FTE, DS_CREATED_USER, DS_MODIFIED_USER, DS_GOAL_ORDER)
VALUES (?, ?, ?, ?, ?,?, TO_CHAR(DS_PLAN_END_DATE, 'dd/MM/YYYY'),?, ?, ?, ?,?, ?, ?,
?,?, ?, ?)
But the consoles shows invalid column index error
Thanks for help
I suspect your problem isn't actually a case of a missing comma (in my experience ORA errors are notorious for telling you the wrong thing). My suspicion is that your real issue is the use of " around the format string in your TO_CHAR call. To demonstrate, try this:
SELECT TO_CHAR(SYSDATE, "dd/MM/YY")
FROM DUAL;
If I run the above I get an ORA-00904: "dd/MM/YY": invalid identifier error. If I change the quotes to apostrophes instead:
SELECT TO_CHAR(SYSDATE, 'dd/MM/YY')
FROM DUAL;
I get 16/04/14. Double quotes are for identifiers, not strings:
SELECT TO_CHAR(SYSDATE, 'dd/MM/YY') AS "The Date"
FROM DUAL; // ^ This is an identifier
prints:
The Date
--------
16/04/14
EDIT:
Sorry, I should have spotted this one sooner! You're using TO_CHAR in your columns list, which you can't do. The below example nicely produces an ORA-00917: missing comma error:
CREATE TABLE JON_TEST (COL1 VARCHAR2(20));
COMMIT;
INSERT INTO JON_TEST (TO_CHAR(COL1, 'DD/MM/YYYY'))
VALUES (SYSDATE);
Whereas this works:
INSERT INTO JON_TEST (COL1)
VALUES (TO_CHAR(SYSDATE, 'dd/MM/YYYY'));
So you need to correct three things:
You need to change TO_CHAR to TO_DATE, and
You need to move the call to TO_DATE to your VALUES clause, and
You need to ensure that you use ' instead of " with the format string.
This is how Oracle define the syntax for INSERT statements:
Notice that in the middle section that it only says column_name and not sql_expression.
Try changing your query to the following:
sqlStr.append("INSERT INTO DS_GOAL ")
.append("(DS_SITE_CODE, DS_FINANCIAL_YEAR, DS_DEPARTMENT_CODE, DS_PLAN_ID, DS_GOAL_ID, ")
.append("DS_DESC, DS_PLAN_END_DATE, ")
.append("DS_CORP_OBJECTIVE, DS_CORP_OBJECTIVE_OTHER, DS_FOCUS, DS_FOCUS_OTHER, ")
.append("DS_TOTAL, DS_EQUIPMENT, DS_RECRUIT, DS_FTE, ")
.append("DS_CREATED_USER, DS_MODIFIED_USER, DS_GOAL_ORDER ) ")
.append("VALUES ")
.append("(?, ?, ?, ?, ?,")
.append("?, TO_DATE(?, 'dd/MM/YY'),")
.append("?, ?, ?, ?,")
.append("?, ?, ?, ?,")
.append("?, ?, ?)");
sqlStr_insertGoal = sqlStr.toString();

DB2 unique index and autonumbering

Having gotten an answer to a Java problem I had last week (thanks!), I'm now on to a new problem with DB2... The Java app I'm working on takes data from a web form and puts in in a DB2 file (database). The SQL string that is passed to the Java PreparedStatement object is:
insert into EVCRPTFL (
AUID, URLEX, URNEX, URNAME, URRCPT, URRUN, URRECT, URRECS, URRDYS, URRWKS, URRMHS, URRMTH, URRDAY, URRTHE, URRWHT, URRWDY, UREXPT, UROCRM, UROCRN, UREXPR, URSTTS, URACTV, URRPT, URD1YR, URD1YN, URD1MR, URD1MN, URD1DR, URD1DN, URD2YR, URD2YN, URD2MR, URD2MN, URD2DR, URD2DN, URRPAR, URLANG, URCTRY
)
values (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
Here's the table creation script:
CREATE TABLE EVCRPTFL (
URID int NOT NULL,
AUID decimal(11,0) NOT NULL,
URLEX timestamp,
URNEX timestamp,
URNAME varchar(40) NOT NULL,
URRCPT varchar(500) NOT NULL,
URRUN timestamp,
URRECT char(1) NOT NULL,
URRECS int NOT NULL,
URRDYS int NOT NULL,
URRWKS int NOT NULL,
URRMHS int NOT NULL,
URRMTH int NOT NULL,
URRDAY int NOT NULL,
URRTHE int NOT NULL,
URRWHT int NOT NULL,
URRWDY int NOT NULL,
UREXPT int NOT NULL,
UROCRM int NOT NULL,
UROCRN int NOT NULL,
UREXPR timestamp,
URSTTS char(1) NOT NULL,
URACTV timestamp,
URRPT int NOT NULL,
URD1YR int,
URD1YN int,
URD1MR int,
URD1MN int,
URD1DR int,
URD1DN int,
URD2YR int,
URD2YN int,
URD2MR int,
URD2MN int,
URD2DR int,
URD2DN int,
URRPAR varchar(1000),
URLANG char(2),
URCTRY char(2)
);
CREATE UNIQUE INDEX EVCRPTFL ON EVCRPTFL(URID);
As you can see, it's passing in all the values in the SQL string except the first one, URID. After a record is inserted, I can see it in the database with an ID number, which implies to me that the database is adding the URID automatically (that is, the ID is not being generated in the Java code and then passed to the database). In my previous experience with Oracle and PHP, I used Oracle Sequences to make autonumbered fields, and I'm aware that there are broadly similar features in MySQL, Postgres, and probably other database systems, but I haven't been able to find how autonumbering works in DB2.
My coworker who is more familiar with DB2 is also puzzled; he says there are no Triggers set up on the table according to what he looked at, and that generally in the RPG code here it sounds like ID numbers are generated in the code and then passed to the database, rather than being generated by the database itself.
So my question is: Does the Unique Index on URID also autogenerate ID numbers, or is there something else I need to be looking for either in the database or in the Java code?
And my followup question is: I will eventually need to be using the URID number for insertion into another table storing related data. In Oracle, this was done with "insert into returning into " and then getting the data back out of the parametrized id_variable in the code. Is there a similar feature in DB2? I found documentation on an IDENTITY_VAL_LOCAL function, but it doesn't look like I can always guarantee that it will return the correct ID, for instance if another insert happens from the web form between the first insert and the invokation of IDENTITY_VAL_LOCAL...
I can provide code samples or other database info if needed. Thanks!
The unique index on URID does not autogenerate ID numbers.
The DB2 way to do this is to add a GENERATED BY DEFAULT or GENERATED ALWAYS to your URID column definition:
URID int NOT NULL
GENERATED BY DEFAULT AS IDENTITY( START WITH 1, INCREMENT BY 1 )
UNIQUE
GENERATED BY DEFAULT will let you specify a custom value if you need it.
I recommend looking over the documentation for the CREATE TABLE statement.

Getting error while executing dao

Hello friends i am running code given below which contains the setLogTimeEntery function and when this function is executed i am getting
"Error : java.sql.SQLException: ORA-00917: missing comma"
error and my database is oracle plese any one tell me wht is the problem.
public int setLogTimeEntery(Connection con, LogTimeBean ltb) {
int ans = 0;
try{
psmt=con.prepareStatement("Insert into TR_LogTime values((Select count(*) from Tr_LogTime) + 1 ,(select sysdate from dual) , Prj_Id=?,Area_Id=?,Actvity_Id=?,ID_No=?,Work_Date=(select to_date(?,'dd/mm/yyyy')from dual) ,Work_Hours=?,Division=?,Description=?,Remarks=?,Work_Week=?)");
psmt.clearParameters();
psmt.setString(1,ltb.getLt_Prj_Id());
psmt.setInt(2,ltb.getLt_Area_Id());
psmt.setInt(3,ltb.getLt_Actvity_Id());
psmt.setInt(4, ltb.getLt_ID_No());
psmt.setString(5, ltb.getLt_Work_Date());
psmt.setFloat(6,ltb.getLt_Work_Hours());
psmt.setInt(7,ltb.getLt_Division());
psmt.setString(8, ltb.getLt_Description());
psmt.setString(9, ltb.getLt_Remarks());
psmt.setInt(10, ltb.getLt_Work_Week());
ans=psmt.executeUpdate();
psmt.close();
}catch(Exception e){
System.err.println("Error : "+e);
}
return ans;
}
I don't think your Oracle SQL statement (as defined in the prepared statement) is valid. When using the insert into [table] values(...) syntax, you don't use column=value expressions.
If you're specifying all of the column values in the correct order, then use this:
psmt=con.prepareStatement("Insert into TR_LogTime values((Select count(*) from Tr_LogTime) + 1 ,(select sysdate from dual), ?, ?, ?, ?,(select to_date(?,'dd/mm/yyyy')from dual) ,?,?,?,?,?)");
Otherwise, if you're only specifying a subset of the columns, use the syntax of
insert into TR_LogTime (col1, col2, col3, ...) values (?, ?, ?, ...)
(I didn't specify the exact column names in your example since I don't know all of them)
More on this syntax.
try this:
Insert into TR_LogTime (XXX, YYY, Prj_Id, Area_id, Activity_Id, ID_No, Work_Date, Work_Hours, Division, Description, Remarks, Work_Week) values (
(Select count(*) from Tr_LogTime) + 1 , (select sysdate from dual) , ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
You'll need to replace XXX and YYY with the appropriate column names

Categories