I hope the title makes sense.
Let's say I have a stored procedure (in Microsoft SQL Server) which generates a select statement based on some parameters and then executes that select statement on a table. Let's say the table is Users and the select statement returns the first user in the table. The user is has an ID, a fname, and an lname.
How can I store the data that is generated by the select statement?
In eclipse, I want to use Spring and JdbcTemplate, and I'm thinking about using a callable statement. Any ideas?
From the Spring documentation:http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html
private class GetSysdateProcedure extends StoredProcedure {
private static final String SQL = "sysdate";
public GetSysdateProcedure(DataSource dataSource) {
setDataSource(dataSource);
setFunction(true);
setSql(SQL);
declareParameter(new SqlOutParameter("date", Types.DATE));
compile();
}
public Date execute() {
// the 'sysdate' sproc has no input parameters, so an empty Map is supplied...
Map<String, Object> results = execute(new HashMap<String, Object>());
Date sysdate = (Date) results.get("date");
return sysdate;
}
}
Related
I am making a discussion board with Spring.
I am using JdbcTemplate to populate the articles of the users from the database, but the JdbcTemplate's query method does not return the proper ResultSet. Interestingly, when I copy and paste the SQL query from the code to SQL Developer, it returns the proper results.
The photo that shows the SQL query works,
JdbcTemplate code
public class ForumDao {
private JdbcTemplate template;
public ForumDao(DataSource dataSource) {
template = new JdbcTemplate(dataSource);
}
public Collection<ForumArticle> getArticleList(){
Collection<ForumArticle> list = template.query("SELECT ARTICLE_ID, TITLE, NAME, VIEW_NUM, CREATED_DATE FROM MEMBER, FORUM WHERE MEMBER.ID = FORUM.MEMBER_ID",
new RowMapper<ForumArticle>() {
#Override
public ForumArticle mapRow(ResultSet rs, int rowNum) throws SQLException {
ForumArticle article = new ForumArticle();
System.out.println("completeeeee--------------------------------------------------------------------");
article.setArticleID(rs.getInt("ARTICLE_ID"));
article.setTitle(rs.getString("TITLE"));
article.setName(rs.getString("NAME"));
article.setViewNum(rs.getLong("VIEW_NAME"));
article.setCreatedDate(rs.getTimestamp("CREATED_DATE").toLocalDateTime());
return article;
}
});
System.out.println("-dddddddddddddddddddddddddddddddddddd " + list.size());
return list;
}
}
All the configuration set-up is done properly and I am using Oracle DB. I have another DAO class for user data and its JdbcTemplate works perfectly.
When I run my code, the list.size() returns 0 instead of 4. It does not throw any exception.
What can be the possible solution for this issue?
The following line looks wrong:
article.setViewNum(rs.getLong("VIEW_NAME"));
VIEW_NAME should be VIEW_NUM, no?
What's probably happening is that when the above line executes, the code throws a SQLException due to an unknown column in the result set, which terminates the processing and gives you an empty result.
In my Spring Batch Application, I am reading, processing and then trying to write with a ItemWriter to the database using stored procedure:
Below is what my CSV file looks like lets say which I want to read, process and write:
Cob Date;Customer Code;Identifer1;Identifier2;Price
20180123;ABC LTD;BFSTACK;1231.CZ;102.00
My ItemWriter:
#Slf4j
public class MyDBWriter implements ItemWriter<Entity> {
private final EntityDAO scpDao;
public MyWriter(EntityDAO scpDao) {
this.scpDao = scpDao;
}
#Override
public void write(List<? extends Entity> items) {
items.forEach(scpDao::insertData);
}
}
My DAO implementation:
#Repository
public class EntityDAOImpl implements EntityDAO {
#Autowired
private JdbcTemplate jdbcTemplate;
private SimpleJdbcCall simpleJdbcCall = null;
#PostConstruct
private void prepareStoredProcedure() {
simpleJdbcCall = new SimpleJdbcCall(jdbcTemplate).withProcedureName("loadPrice");
//declare params
}
#Override
public void insertData(Entity scp) {
Map<String, Object> inParams = new HashMap<>();
inParams.put("Identifier1", scp.getIdentifier1());
inParams.put("Identifier2", scp.getIdentifier1());
inParams.put("ClosingPrice", scp.getClosingPrice());
inParams.put("DownloadDate", scp.getDownloadDate());
simpleJdbcCall.execute(inParams);
}
}
My Stored procedure used to update is as follows:
ALTER PROCEDURE [dbo].[loadPrice]
#Identifier1 VARCHAR(50),
#Identifier1 VARCHAR(50),
#ClosingPrice decimal(28,4),
#DownloadDate datetime
AS
SET NOCOUNT ON;
UPDATE p
SET ClosingPrice = #ClosingPrice,
from Prices p
join Instrument s on s.SecurityID = p.SecurityID
WHERE convert(date, #DownloadDate) = convert(date, DownloadDate)
and s.Identifier1 = #Identifier1
if ##ROWCOUNT = 0
INSERT INTO dbo.Prices
(
sec.SecurityID
, ClosingPrice
, DownloadDate
)
select sec.SecurityID
, #ClosingPrice
, LEFT(CONVERT(VARCHAR, #DownloadDate, 112), 8)
from dbo.Instrument sec
WHERE sec.Identifier1 = #Identifier1
Give I have this setup, one of my requirement is that if I am unable to update/insert to the database using #Identifier1 i.e. there is no SecurityID which matched with Identifier1, I need to THEN update/insert
using the Identifier2. Second level match if you like.
How can I do this in my DAO insertData()? It is business logic and prefer in java code instead of stored proc but I am keen to look at your examples how this can be achieved.
How can I return a result of a row being updated/inserted and take decision as to whether or not to update/insert with second identifier?
For the update I would change the where clause to
WHERE convert(date, #DownloadDate) = convert(date, DownloadDate)
and (s.Identifier1 = #Identifier1 OR s.Identifier2 = #Identifier2)
and for the insert
WHERE sec.Identifier1 = #Identifier1 OR sec.Identifier2 = #Identifier2
That should work even if I haven't verified it myself. I am assuming that the given values for identifier1 and identifier2 can not match two different rows in the Instrument table.
I need Prepared Statement / instead of Query Builder using Cassandra Operations Interface and session
Any Example or recent docs. for Cassandra using java
For spring-data-cassandra v1.x, the getSession() method of org.springframework.cassandra.core.CqlOperations could let you access Session directly. However, similar APIs are deprecated since v2.0
Here is a example from https://github.com/opencredo/spring-data-cassandra-example/
#Autowired
private CqlOperations cqlTemplate;//or inherited interface, like CassandraOperations
private void insertEventUsingPreparedStatement() {
PreparedStatement preparedStatement = cqlTemplate.getSession().prepare("insert into event (id, type, bucket, tags) values (?, ?, ?, ?)");
Statement insertStatement = preparedStatement.bind(UUIDs.timeBased(), "type2", TIME_BUCKET, ImmutableSet.of("tag1", "tag2"));
cqlTemplate.execute(insertStatement);
}
See this to check how to use prepared statment while using java datastax driver.
However i would recommend to store all preparedstatments in a cache (for example a map) while application initializes and reuse the same whenever requreid by creating boundstatment out of it.
For example :
//Here Key is query string
private static final Map<String, PreparedStatement> psMap = new ConcurrentHashMap<String, PreparedStatement>();
//Will be invoked # initialization
public void init(Session session) {
this.session = session;
for (QuerySetEnum cql : QuerySetEnum.values()) {
psMap.put(cql.getStatement(), session.prepare(cql.getStatement()));
}
//In Dao Impl class
//Get bounded statment + execute by passing the value
#Override
public void decreaseStats(long size, long count, String mapname,
int bucketId) {
BoundStatement boundStatement = getBoundStatement(QuerySetEnum.DECREASE_STATS);
metaTemplate.execute(boundStatement.bind(size, count, mapname,
bucketId));
}
//Below is the implementation how to get BoundStatement out to prepared statment cache
private BoundStatement getBoundStatement(QuerySetEnum query) {
PreparedStatement preparedStatement = queryPool
.getPreparedStatement(query);
BoundStatement boundStatement = new BoundStatement(preparedStatement);
return boundStatement;
}
Use spring-data-cassandra and that will do all magic for you.
App sample https://github.com/valchkou-app/spring-boot-cassandra-simple
#Repository
interface ISensorMeasureRepository extends CassandraRepository<SensorMeasureEntity> {
#Query('select * from sensor_measures_simple where sensor_id=?0 and measure_time>=?1 and measure_time<=?2')
List<SensorMeasureEntity> getBySensorAndDateRange(int sensorId, Date start, Date end)
#Query('select * from sensor_measures_simple where sensor_id=?0 ALLOW FILTERING')
Stream<SensorMeasureEntity> getAllBySensor(int sensorId)
}
I use oracle stored procedures with spring-data-jpa. In the most cases it is pretty well, when it is a function or output parameter is first in the param list. But I have some stored procedures with ouput param is the last in the param list:
procedure get_data (some_val in varchar2 cur out sys_refcursor);
or returns more than one output refcursors like
procedure get_my_data (cur1 out sys_refcursor, cur2 out sys_refcursor, some_val in varchar2);
Is it possible with any way to use it with JpaRepository?
Finally, I've found answer by myself :)
My situation is a good point for using spring-data's Custom Implementation
You should:
Create Interface, named YourRepository*Custom* with your new
method (for example EmployeeRepositoryCustom)
Create an imiplementation for this interface with name
YourRepository*Impl* (for example EmployeeRepositoryImpl)
Inside method implementation you can use
SimpleJdbcCall for calling Oracle stored procedure, for example
...
PROFIT!!!
Note: naming rules are important if you want to use default configs
well,
if you want a localized call to a StoredProc from a service or utility class, then you can use Spring Jdbc for StoredProc. See below for implementation
public class StoredProcSampleTest extends StoredProcedure {
private static final String SPROC_NAME = "HH_EXTRACT.SAMPLE_TEST";
public StoredProcSampleTest(DataSource dataSource) {
super(dataSource, SPROC_NAME);
declareParameter(new SqlParameter("v_in_msg", Types.VARCHAR));
declareParameter(new SqlOutParameter("v_out_msg", Types.VARCHAR));
compile();
}
public String execute() {
HashMap<String, Object> hmap = new HashMap<String, Object>();
hmap.put("v_in_msg", "Suresh");
hmap.put("v_out_msg", "");
Map<String, Object> results = execute(hmap);
String outRes = (String) results.get("v_out_msg");
return outRes;
}
}
now in your utility class or Service class, do this
protected StoredProcSampleTest storedProcSampleTest;
#Autowired
public void setDataSource(final DataSource dataSource) {
this.storedProcSampleTest = new StoredProcSampleTest(dataSource);
}
:
public String callStoredProcSampleTest(){
return storedProcSampleTest.execute();
}
I am the getting
org.springframework.jdbc.BadSqlGrammarException:
PreparedStatementCallback; bad SQL grammar [select cid,
clinician-code, password, first-name, last-name from Clinician where
clinician-code= ?]; nested exception is
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown
column 'clinician' in 'field list'
error on the following code, You can also see the Table in the screen shot, except for cid all other attributes are VARCHAR(45)
Row mapper class
public class CClinicianRowMapper implements RowMapper {
#Override
public Object mapRow(ResultSet rs, int line) throws SQLException {
CClinicianResultSetExtractor extractor = new CClinicianResultSetExtractor();
return extractor.extractData(rs);
}
}
Result Extractor Class
public class CClinicianResultSetExtractor implements ResultSetExtractor {
#Override
public Object extractData(ResultSet rs) throws SQLException {
CClinician clinician = new CClinician();
clinician.setCid(rs.getLong("cid"));
clinician.setClinicianCode(rs.getString("clinician-code"));
clinician.setPassword(rs.getString("password"));
clinician.setFirstName(rs.getString("first-name"));
return clinician;
}
}
Class for selecting data from table
public List<CClinician> findClinician(CClinician _clinician) {
// TODO Auto-generated method stub
JdbcTemplate select = new JdbcTemplate(dataSource);
try
{
return select.query("select cid, clinician-code, password, first-name, last-name from Clinician where clinician-code= ?",
new Object[] {_clinician.getClinicianCode()}, new CClinicianRowMapper());
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
I know this is an old thread, but hopefully anyone stumbling across this question will find this answer useful.
I was getting the same exception in my spring app. Based on the output, I thought I had a syntax issue with my query. It turns out that I actually had a syntax error in my mapper method. I came across this issue because I originally created my Product class with different field names than the column names.
public class ProductMapper implements RowMapper<Product> {
public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
Product product = new Product();
product.setProduct_id(rs.getInt("product_id")); //was id. was causing BadSqlGrammarException
product.setProduct_name(rs.getString("product_name")); //was name. was causing BadSqlGrammarException
product.setPrice(rs.getDouble("price"));
product.setQuantity(rs.getInt("quantity"));
return product;
}
}
Once I made the above changes (my fields are named product_id and product_name), my app worked correctly. Just remember that any changes you make to column names or java fields should be made not only to your query statements, but also to your mapper method as well. I see that the OP did this correctly, but I thought it was worth reiterating. I hope someone finds this helpful.
In order to use a dash in the column names, you need to escape them with back ticks.
"SELECT cid, `clinician-code`, password, `first-name`, `last-name`
FROM Clinician
WHERE `clinician-code` = ?"
Check your query syntax properly for missing ; or extra comma (,) . 'Bad SQL Grammar Exception' is related only to syntactical mistake in Sql queries.
I was getting same error in following code while working on Spring JDBC:
String query= "update student set name=?, city=?, where id=?"; // due to extra comma after city=?,
Changed code to
String query= "update student set name=? city=?, where id=?";
Error resolved.