I'am writing a method to retrieve an element of a DB giving a Long id parameter.
This id is unique, so the method should just return one element, and I want to create a class instance with this element retrived.
I've made the following method that works perfectly fine:
#Override
public ElementEntity getElement(final long id)
{
final MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("element_id", id);
final List<ElementEntity > listOfElements =
namedParameterJdbcOperations.query(SQL_RETURN_ELEMENT_BY_ID, paramSource, ROW_MAPPER_ELEMENT);
return !listOfElements .isEmpty() ? listOfElements.get(0) : null;
}
The ROW_MAPPER is implemented this way:
private static final RowMapper<ElementEntity > ROW_MAPPER_INSTALLER =
(rs, RowNum) ->
new ElementEntityBuilder().setElement(rs.getBytes("ELEMENT")).build();
The element is a byte array. I repeat, works perfectly. But I would like to avoid using a list and retrieving the first position and, instead, create directly the ElementEntity. So I tried the following approach:
#Override
public ElementEntity getElement(final long id)
{
final MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("element_id", id);
return namedParameterJdbcOperations.query(SQL_RETURN_ELEMENT_BY_ID, paramSource, (ResultSet rs) -> new DesktopAppInstallerEntity(rs.getBytes("ELEMENT")));
}
Althought I have't made any more changes, it gives me the following error:org.h2.jdbc.JdbcSQLNonTransientException: No data is available.
That's the full error (I changed some words to avoid showing the real SQL query):
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [SELECT SOMETHING FROM SOMEWHERE WHERE id = ?]; No data is available [2000-200]; nested exception is org.h2.jdbc.JdbcSQLNonTransientException: No data is available [2000-200]
I'm pretty new to all this JDBC, but it seems to me that the paramSource is not working properly when I apply this changes and I don't have the foggiest idea why is happening because I'm just changing the result extractor.
Well, I figured it out myself. I will share my answer to help the community. I used NamedParameterJdbcOperations.queryForObject instead of namedParameterJdbcOperations.query and used the same ROW_MAPPER:
#Override
public ElementEntity getElement(final long id)
{
final MapSqlParameterSource paramSource = new MapSqlParameterSource();
paramSource.addValue("id", id);
try
{
return namedParameterJdbcOperations.queryForObject(SQL_RETURN_ELEMENT, paramSource, ROW_MAPPER_ELEMENT);
}
catch (EmptyResultDataAccessException e)
{
return null;
}
}
In my particular case I'm interested to catch when the SQL Query attempt to find an Element that doesn't exist in the DB. For this purpose I catch and handle the EmptyResultDataAccessException thrown.
More info could be found here: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.html#queryForObject-java.lang.String-org.springframework.jdbc.core.namedparam.SqlParameterSource-org.springframework.jdbc.core.RowMapper-
Here I am getting Error at the List<Data> dataList = jdbcTemplate.query location.
Checkmarx says:
AppServices/src/main/java/com/mbusa/app/dao/impl/AppRequestDAOImpl.java
gets data from the database, for the query element. This element’s
value then flows through the code without being properly filtered or
encoded and is eventually displayed to the user in method
getRequestDetail at line 117 of
AppWeb/src/main/java/com/mbusa/app/controllers/AppRequestController.java.
This may enable a Stored Cross-Site-Scripting attack.
List<Data> dataList = jdbcTemplate.query(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
PreparedStatement pstmt = conn.prepareStatement(fSQL);
int index = 1;
for(Object param: effParams) {
pstmt.setString(index, (String) param);
index++;
}
return pstmt;
}
}, new RequestMapper());
public class RequestMapper implements RowMapper<Data> {
#Override
public Data mapRow(ResultSet rs, int rowNum) throws SQLException {
Data data = new Data();
data.setName(rs.getString("name"));
return data ;
}
}
I have added PreparedStatement here to resolve this issue and also tried adding HtmlUtil.htmlEscape upon output data, but still could not resolve this issue.
Can anyone help with this issue?
I have the following stored procedure which takes three parameters and returns three ref cursors.
variable id refcursor
variable item refcursor
variable amount refcursor
exec getdata(123,date1,date2, :id, :item, :amount) ;
print id;
print item;
print amount;
i have three resultsets for this stored procedure output. How can i call this in spring mvc and display these three resultsets. I was using the following code to fetch the data through sql query. But now i have developed a stored procedure. so how can i call this SP output insted of my query output.
public Optional<List<student>> getStudentDetails(String id) {
NamedParameterJdbcTemplate parameterJdbcTemplate = new
NamedParameterJdbcTemplate(dataSource);
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("Id", id);
List<student> studentList =
parameterJdbcTemplate.query(StudentQueryRepository.STUDENT_DETAIL_QUERY,
namedParameters, new studentDecodeRowMapper());
if (studentList.isEmpty()) {
return Optional.empty();
} else {
return Optional.of(studentList);
}
}
Try this:
List<CommunicationContact> campaigns = jdbcTemplate.execute(
new CallableStatementCreator() {
public CallableStatement createCallableStatement(Connection con) throws SQLException {
CallableStatement cs = con.prepareCall("{? = call MY_SERVICES.GET_CAMPAIGNS(?,?)}");
cs.registerOutParameter(1, OracleTypes.CURSOR);
cs.setString(2, customer);
cs.setString(3, channel);
return cs;
}
},
new CallableStatementCallback<List<CommunicationContact>>() {
#Override
public List<CommunicationContact> doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException {
cs.execute();
ResultSet rs = (ResultSet) cs.getObject(1);
List<CommunicationContact> communications = commContactRsExtractor.extractData(rs);
return communications;
}
}
);
And the I have a function on the database:
FUNCTION GET_CAMPAIGNS(p_cust IN VARCHAR2,
p_channel IN VARCHAR2)
RETURN SYS_REFCURSOR
IS
l_campaigns_cursor SYS_REFCURSOR;
BEGIN
BEGIN
OPEN l_campaigns_cursor FOR
SELECT...
EXCEPTION
WHEN OTHERS THEN
...
END;
RETURN l_campaigns_cursor;
END GET_CAMPAIGNS;
I believe that a stored procedure with out parameter will also work.
I am trying to execute this method using jdbc template:
public String getClientName(String uuid) {
System.out.println("UUID here in the dao layer is: " + uuid);
String sql = "Select email from client where uuid=?";
return jdbcTemplate.query(sql, new ResultSetExtractor<String>() {
#Override
public String extractData(ResultSet rs) throws SQLException, DataAccessException {
return rs.getString("email");
}
});
}
However I am getting this error:
SQLErrorCodes loaded: [DB2, Derby, H2, HSQL, Informix, MS-SQL, MySQL, Oracle, PostgreSQL, Sybase, Hana]
org.springframework.jdbc.BadSqlGrammarException: StatementCallback; bad SQL grammar [Select email from client where uuid=?]; nested exception is org.postgresql.util.PSQLException: ERROR: operator does not exist: character varying =?
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Where am I going wrong?
You are not passing the uuid which you got as a parameter to your method. You could do use the api like:
Object sqlParameters[] = {uuid};
return jdbcTemplate.query(sql, sqlParameters,
new ResultSetExtractor<List<String>>() {
#Override
public List<String> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<String> emailList=new ArrayList<String>();
while (rs.next()) {
emailList.add(rs.getString("email"));
}
return emailList;
}});
You're not using your uuid parameter anywhere... I suspect you actually want:
return jdbcTemplate.query(sql, new Object[] { uuid },
new ResultSetExtractor<String>() { ... });
That way uuid will be used as the value for the parameter in your SQL.
I am not able to retrieve column values from my database table with the following coding a message has been displayed in the console:
java.sql.SQLException: Invalid value for getInt() - 'Glomindz Support'
My code is:
package com.glomindz.mercuri.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import com.glomindz.mercuri.util.MySingleTon;
public class UserServicesDAO {
private Connection connection;
public UserServicesDAO() {
// connection = new MySingleTon().getConnection();
connection = MySingleTon.getInstance().getConnection();
}
public void get_all_data() {
}
public Map<Integer, String> get_all_data1() {
HashMap<Integer, String> result = new HashMap<Integer, String>();
String query = "SELECT * FROM spl_user_master";
try {
PreparedStatement stmt = connection.prepareStatement(query);
boolean execute = stmt.execute();
System.out.println(execute);
ResultSet resultSet = stmt.getResultSet();
System.out.println(resultSet.getMetaData());
while (resultSet.next()) {
result.put(resultSet.getInt(1), resultSet.getString("id"));
result.put(resultSet.getInt(2), resultSet.getString("name"));
result.put(resultSet.getInt(3), resultSet.getString("email"));
result.put(resultSet.getInt(4), resultSet.getString("mobile"));
result.put(resultSet.getInt(5), resultSet.getString("password"));
result.put(resultSet.getInt(6), resultSet.getString("role"));
result.put(resultSet.getInt(7), resultSet.getString("status"));
result.put(resultSet.getInt(8),
resultSet.getString("last_update"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
new UserServicesDAO().get_all_data1();
}
}
My db table schema is:
id name email mobile password role status last_update
1 Glomindz Support support#glomindz.com 9854087006 cbf91a71c11d5ec348b0c7e9b2f0055e admin 1 2013-05-02 22:05:14
2 Amarjyoti Das amarjyotidas#splcare.com 9864092598 88f2dccb02b2a20615211e5492f85204 admin 1 2013-04-26 05:44:41
You retrieve every column as an int for the key. I assume that some of these columns represent Strings or Dates.
while(resultSet.next()){
result.put(resultSet.getInt(1),resultSet.getString("id"));
result.put(resultSet.getInt(2),resultSet.getString("name")); //Most likely a String
result.put(resultSet.getInt(3),resultSet.getString("email"));
result.put(resultSet.getInt(4),resultSet.getString("mobile"));
result.put(resultSet.getInt(5),resultSet.getString("password"));
result.put(resultSet.getInt(6),resultSet.getString("role"));
result.put(resultSet.getInt(7),resultSet.getString("status"));
result.put(resultSet.getInt(8),resultSet.getString("last_update")); //Most likely a date
}
The inconsistencies between the data types and the object/value returned by the getInt() method causes the error. I would suggest building/modeling an object in your domain that stores rows from the table. Something like:
public class User{
private Integer id;
private String name;
private String email;
private String mobile;
private String password;
private String role;
private String status;
private Date lastUpdate;
/* Get and set methods for each field */
}
Then build a Map containing the object as the value and the id as the key:
//Use Map interface here, also notice generic arguments <Integer,User>
Map<Integer, User> result = new HashMap<Integer, User>();
try {
PreparedStatement stmt = connection.prepareStatement(query);
boolean execute = stmt.execute();
System.out.println(execute);
ResultSet resultSet = stmt.getResultSet();
System.out.println(resultSet.getMetaData());
while(resultSet.next()){
User user = new User();
user.setId(resultSet.getInt("id"));
user.setName(resultSet.getString("name");
user.setEmail(resultSet.getString("email");
//do this for each field, using appropriate method for type...
//then add to map
result.put(user.getId(), user);
}
I think you need all your data from the table as a Map. But you may have multiple rows in your DB, therefore you basically want a list of maps! Modify your method to something like this:-
public List<Map<Integer, String>> get_all_data1() {
List<Map<Integer, String>> allRows = new ArrayList<Map<Integer, String>>();
String query = "SELECT * FROM spl_user_master";
try {
PreparedStatement stmt = connection.prepareStatement(query);
boolean execute = stmt.execute();
System.out.println(execute);
ResultSet resultSet = stmt.getResultSet();
System.out.println(resultSet.getMetaData());
while (resultSet.next()) {
Map<Integer, String> result = new HashMap<Integer, String>();
result.put(1, resultSet.getString("id"));
result.put(2, resultSet.getString("name"));
result.put(3, resultSet.getString("email"));
result.put(4, resultSet.getString("mobile"));
result.put(5, resultSet.getString("password"));
result.put(6, resultSet.getString("role"));
result.put(7, resultSet.getString("status"));
result.put(8, resultSet.getString("last_update"));
allRows.add(result);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return allRows;
}
Here, for every fetched record from the DB, the columns are put into the Map, and each map, represents a row, which is added to a List!
If you are using JPA annotations to map entity fields with db table, you need to use #Enumerated(EnumType.STRING) annotation on ENUM type entity fields.
This error is due to, while creating the table you may mentioned name column as INTEGER. So while retrieving it will get that column using getInt() method. But actually the column is of type STRING.
U should change the datatype of name column to STRING and this issue will be fixed automatically.
According to documentation, getInt() or getString() requires columnIndex or columnLabel to get value for that column in particular entry. To find the column index you need to use findColumn(name) method to get its columnIndex. So your code should be as follows:
while (resultSet.next()) {
result.put(resultSet.findColumn("id"), resultSet.getInt("id"));
result.put(resultSet.findColumn("name"), resultSet.getString("name"));
result.put(resultSet.findColumn("email"), resultSet.getString("email"));
result.put(resultSet.findColumn("mobile"), resultSet.getInt("mobile"));
result.put(resultSet.findColumn("password"), resultSet.getString("password"));
result.put(resultSet.findColumn("role"), resultSet.getString("role"));
result.put(resultSet.findColumn("status"), resultSet.getInt("status"));
result.put(resultSet.findColumn("last_update"),
resultSet.getString("last_update"));
}
Basically you need to get your values according to the datatype with which it had been saved in DB. Check available methods to retrieve values by Ctrl+Click on ResultSet class
Please check the syntax error for a small mistake for comma(,) you are added before the select statement
Example:
select id, name, mobile, address from table_name;
but you are using like
select id, name, mobile, address, from table_name;
please check and correct it