I try to read cassandra data by paging, but it doesn't work. My codes are as below. I got the same content for every page. Anything I missed ?
// Persist the entity objects
for (int i=0; i<1000; i++) {
// change person1's id
personObj1.setPersonId("haofan" + i);
dataServiceClient.persist(personObj1);
}
Query query;
List<Person> personList;
// Create and execute SELECT * query
for (int i =0; i<10; i++) {
String cqlString = "Select p from Person p";
// String cqlString = "Select p from Person p";
query = dataServiceClient.createQuery(cqlString).setMaxResults(100).setFirstResult(i*100);
personList = query.getResultList();
// Get the same personId for every page.
Assert.assertEquals(100, personList.size());
System.out.println("haofan for: " + personList.get(10).getPersonId());
}
You are looking for offset queries there is no support on Cassandra natively.
I try multi solution, finally it works for me as below solution. Refer: https://docs.datastax.com/en/developer/java-driver/3.6/manual/paging/
public String paging(Session session, String pageState) {
Statement statement = new SimpleStatement("SELECT * FROM testkeyspace.\"PERSON\"");
statement.setFetchSize(3);
if (pageState != null) {
statement.setPagingState( PagingState.fromString(pageState));
}
ResultSet rs = session.execute(statement);
int remaining = rs.getAvailableWithoutFetching();
System.out.println("remaining " + remaining);
for (Row row : rs) {
System.out.println("first" + row);
if (--remaining == 0) {
break;
}
}
return rs.getExecutionInfo().getPagingState().toString();
}
How to use this function:
#Test
#Category(DataServiceRequired.class)
public void pagingTest() throws Exception {
Cluster cluster = Cluster.builder().addContactPoint("localhost").withPort(9042).build();
Session session = cluster.connect();
String pageState = paging(session, null);
paging(session, pageState);
}
Related
I asked this question on Stackoverflow on calling a stored procedure with IN and OUT parameters using StoredProcedureItemReader, but unfortunately, the answer was that such support isn't available, and I have to implement my own ItemReader.
Calling stored procedure with an IN and OUT Parameter from Spring Batch
So, I went ahead and wrote this sample code. I am able to call my stored procedure, however, it's being called infinite times whenever the read() method is called in a Batch step.
#Component
public class MyStoredProcItemReader implements ItemReader<MyRow> {
#Autowired DataSource dataSource;
#Override
public MyRow read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
try (
Connection conn = dataSource.getConnection();
CallableStatement statement = conn.prepareCall("{call GetNameCountByFname(?, ?)}");
) {
statement.setString(1, "bob");
statement.registerOutParameter(2, Types.INTEGER);
boolean hadResults = statement.execute();
Integer totalBook = (Integer) statement.getObject(2, Integer.class);
System.out.println("Total: " + totalBook);
Map<String, Object> results = new HashMap<>();
// ResultSet resultSet = statement.getResultSet();
// ResultSetMetaData metaData = resultSet.getMetaData();
// int col = 1;
// while (resultSet.next())
// {
// String columnName = metaData.getColumnName(col);
// Object value = resultSet.getObject(col);
// results.put(columnName, value);
// ++col;
// }
//
// int columnCount = metaData.getColumnCount();
// for (int col = 1; col <= columnCount; col++) {
// String columnName = metaData.getColumnName(col);
// Object value = resultSet.getObject(col);
//
// results.put(columnName, value);
// }
while (hadResults) {
ResultSet resultSet = statement.getResultSet();
// process result set
while (resultSet.next()) {
String title = resultSet.getString("id");
String description = resultSet.getString("name");
int rating = resultSet.getInt("LastSynchronizationVersion");
System.out.println(
"| " + title + " | " + description + " | " + rating + " |");
}
hadResults = statement.getMoreResults();
}
statement.close();
MyRow row = new MyRow();
row.tableName = "tableName";
row.row = results;
return row;
} catch (SQLException ex) {
ex.printStackTrace();
}
return null;
}
}
What did I do wrong, and what's the right approach?
I am able to call my stored procedure, however, it's being called infinite times whenever the read() method is called in a Batch step.
An ItemReader is expected to return null at some point to signal the end of the data set. This is how the driving chunk-oriented step knows that there is no more data to read and gives the control to the enclosing job to move to the next step (if any).
So in your case, you need to make sure your item reader returns null at some point.
I use a jTable jquery for jsp page, it work very well. It can display the showing count records in bottom right of table well (e.g. Showing 1-10 of 22). When I insert the Filtering into the page, the showing count record is not correctly.
I follow this for Filtering: http://www.jtable.org/Demo/Filtering
How to customize the code for showing count record (I use java-jsp and sql server). Sorry for my English language :))
Here is the code I am using right now in controller.
if (action.equals("list")) {
try {
int startPageIndex = Integer.parseInt(request.getParameter("jtStartIndex"));
int numRecordsPerPage = Integer.parseInt(request.getParameter("jtPageSize"));
String jtSorting = null;
//Fetch Data from Rejected_Product Table
lstSite = dao.**getAllSite**(filter_site, startPageIndex, numRecordsPerPage, jtSorting);
//Get Total Record Count for Pagination
int siteCount = dao.**getSiteCount**();
//Convert Java Object to Json
Gson gson = new Gson();
JsonElement element = gson.toJsonTree(lstSite, new TypeToken<List<Site>>() {
}.getType());
JsonArray jsonArray = element.getAsJsonArray();
String listData = jsonArray.toString();
//Return Json in the format required by jTable plugin
listData = "{\"Result\":\"OK\",\"Records\":"+listData+",\"TotalRecordCount\":"+siteCount+"}";
response.getWriter().print(listData);
System.out.println(listData);
} catch (Exception ex) {
String error = "{\"Result\":\"ERROR\",\"Message\":" + ex.getStackTrace() + "}";
response.getWriter().print(error);
ex.printStackTrace();
}
}
and here method getAllSite:
public List<Site> getAllSite (FilterSite filter_site, int jtStartIndex, int jtPageSize, String jtSorting) {
List<Site> siteList = new ArrayList<Site>();
String query = "";
String siteQ = filter_site.getSite();
String clientQ = filter_site.getClient(); // wait
String locationQ = filter_site.getLocation();
if (locationQ.isEmpty()) {
locationQ = "";
} else {
locationQ = "and location like '%"+locationQ+"' ";
}
String site_idQ = filter_site.getSite_id();
if (site_idQ.isEmpty()) {
site_idQ = "";
} else {
site_idQ = "and site_id = '"+site_idQ+"' ";
}
String divisionQ = filter_site.getDivision();
if (divisionQ.isEmpty()) {
divisionQ = "";
} else {
divisionQ = "and division = '"+divisionQ+"' ";
}
int range = jtStartIndex+jtPageSize;
query = "SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY CODE) as row FROM [site]) a "
+ "WHERE (code like '%"+siteQ+"' "+locationQ+site_idQ+divisionQ+") "
+ "and row > "+jtStartIndex+" and row <= "+range;
try {
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(query);
System.out.println("query : "+query);
while (rs.next()) {
Site sitebean = new Site();
sitebean.setName(rs.getString("name"));
sitebean.setCode(rs.getString("code"));
.....
siteList.add(sitebean);
}
} catch (SQLException e) {
e.printStackTrace();
}
return siteList;
}
and here method getSiteCount :
public int getSiteCount () {
int count = 0;
String query = "SELECT COUNT(*) as count FROM [site] ";
try {
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery(query);
while (rs.next()) {
count = rs.getInt("count");
}
} catch (SQLException e) {
e.printStackTrace();
}
return count;
}
If you mean by "not correctly" that the row count is larger than expected, then the solution would be to include the where clause in the siteCount query.
WHERE (code like '%"+siteQ+"' "+locationQ+site_idQ+divisionQ+")
Hii i want to create a dynamic query for filtering products. I want filter product from PRODUCTS table
on the basis of certain parameters like
Brand
Flavour
Price
Size
Type
i am creating a function in which i am executing MySQL query i want to check which parameter user has used which parameter is used those value will not be null and rest of the not selected parameters will be null. so i am checking the function which is null which is not and passing them in query
I have tried the following code
but it shows null pointer execption with following message
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 '' at line 1
and u tried printing the query:
SELECT * FROM products WHERE 1=1 AND brand in (?,? AND Price < ? AND Size < ? AND Type = ?
Follwing is the code:
public List<Products> Filter_Itemsl(String[] Brand, String[] Flavour, float Price, float Size, String Type) {
List<Object> parameters = new ArrayList<Object>();
ResultSet rs;
List<Products> data = null;
PreparedStatement stmt;
try {
StringBuilder query = new StringBuilder("SELECT * FROM products WHERE 1=1");
if (Brand != null) {
query.append(" AND brand in (");
for (int i = 0; i < Brand.length; i++) {
query.append('?');
if (i < Brand.length - 1) {
query.append(',');
}
parameters.add(Brand[i]);
}
}
if (Flavour != null) {
query.append(" AND Flavour in (");
for (int i = 0; i < Brand.length; i++) {
query.append('?');
if (i < Flavour.length - 1) {
query.append(',');
}
parameters.add(Flavour[i]);
}
}
if (Price != 0) {
query.append(" AND Price < ?");
parameters.add(Price);
}
if (Size != 0) {
query.append(" AND Size < ?");
parameters.add(Size);
}
if (Type != null) {
query.append(" AND Type = ?");
parameters.add(Type);
}
String Query = query.toString();
System.out.println(Query);
stmt = DataBaseConnection.DBConn.getConnection().prepareStatement(Query);
int i = 1;
for (Object parameter : parameters) {
stmt.setObject(i++, parameter);
}
rs = stmt.executeQuery();
if (rs != null) {
data = new ArrayList<Products>();
while (rs.next()) {
Products p = new Products();
p.setTitle(rs.getString("Ttile"));
p.setCategory(rs.getString("Category"));
p.setSubCategory(rs.getString("SubCategory"));
p.setSubCategoryTwo(rs.getString("SubCategorytwo"));
p.setPrice(rs.getInt("Price"));
p.setFlavour(rs.getString("Flavour"));
p.setSize(rs.getFloat("Size"));
p.setImage(rs.getString("image"));
p.setBrand(rs.getString("Brand"));
p.setInstock(rs.getString("instock"));
p.setInstockQty(rs.getInt("instockqty"));
p.setType(rs.getString("Type"));
data.add(p);
}
}
} catch (Exception e) {
System.out.println(e.getStackTrace());
System.out.println("----------------------");
System.out.println(e.getMessage());
System.out.println("----------------------");
System.out.println(e.getSuppressed());
System.out.println("----------------------");
e.printStackTrace();
return null;
}
return data;
}
You are missing the closing ) for every IN sql statement.
You need to close the bracket after the for loop
if (Flavour != null) {
query.append(" AND Flavour in (");
for (int i = 0; i < Brand.length; i++) {
query.append('?');
if (i < Flavour.length - 1) {
query.append(',');
}
parameters.add(Flavour[i]);
}
query.append(")");
}
i am using below simple query to get the result for testing purpose.
qName = "select total_requests from (select 10000 as total_requests from dual)"; //this can be dynamic query
preStatement = connection.prepareStatement(qName);
ParameterMetaData pmd = preStatement.getParameterMetaData();
int stmtCount = pmd.getParameterCount();
int paramsCount = params == null ? 0 : params.length;
for (int i = 0; i < params.length; i++) {
if (params[i] != null) {
preStatement.setObject(i + 1, params[i]);
} else {
int sqlType = Types.VARCHAR;
if (!paramValid) {
try {
sqlType = pmd.getParameterType(i + 1);
} catch (SQLException e) {
paramValid = true;
}
}
preStatement.setNull(i + 1, sqlType);
}
}
ResultSet rs = preStatement.executeQuery();
once i am executing 3rd line, below error is thrown by application
Caused by: java.lang.AbstractMethodError: com.inet.pool.b.getParameterMetaData()Ljava/sql/ParameterMetaData;
at com.core.admin.util.AnalyzeHelper.fillQuery(AnalyzeHelper.java:61)
is this due to subQuery issue?
how to resolve this?
use this for executing query
preStatement.executeQuery();
you need to have a result set for viewing
ResultSet rs=preStatement.executeQuery();
while(rs.next())
{
rs.getString(1);// I assume that first column is a String.If it is an INT then use rs.getInt(1);
//similarly for other columns
}
It may helps you.
qName = "select total_requests from (select 10000 as total_requests from dual)";
preStatement = connection.prepareStatement(qName);
ResultSet rs= preStatement.executeQuery();
I used the following codes to update column Clob in oracle, it seems to be okay and work properly, after performance testing, it reported that need consumed more than 200ms while the length of string is more than 130000. Is it any good way to improve it?
private void updateClobDetailsField(Map<Integer, String> idToDetails){
long s1 = System.currentTimeMillis();
Connection conn = null;
PreparedStatement pStmt = null;
ResultSet rset = null;
Map<Integer, Clob> idToDetailsClob = new HashMap<Integer, Clob>();
int BATCH_SIZE = CMType.BATCH_UPDATE_MAXSIZE;
try
{
conn = getConnection();
ServerAdapter adapter = ServerAdapter.getServerAdapter();
List<Integer> IDList = new ArrayList<Integer>();
for(Integer id : idToDetails.keySet()){
IDList.add(id);
}
List<Integer> tempIDList = new ArrayList<Integer>(IDList);
while(!tempIDList.isEmpty()){
int size = tempIDList.size() < BATCH_SIZE ? tempIDList.size() : BATCH_SIZE;
List<Integer> currentBatch = tempIDList.subList(0, size);
String inClause = SQLHelper.prepareInClause("ID",currentBatch.size());
pStmt = conn.prepareStatement("SELECT ID, DETAILS FROM PROGRAM_HISTORY WHERE " + inClause);
for(int i = 0; i < currentBatch.size(); i++){
pStmt.setInt(i+1, (currentBatch.get(i)));
}
rset = pStmt.executeQuery();
while(rset.next()){
int id = rset.getInt(1);
Clob detailsClob = rset.getClob(2);
Writer writer = adapter.getCharacterOutputStream(detailsClob);
String details = idToDetails.get(id);
if (details != null) {
writer.write(details);
}
writer.flush();
writer.close();
idToDetailsClob.put(id, detailsClob);
}
currentBatch.clear();
BaseSQLHelper.close(pStmt, rset);
}
int counter = 0;
pStmt = conn.prepareStatement("UPDATE PROGRAM_HISTORY SET DETAILS = ? WHERE ID = ?");
for(int i=0; i<IDList.size(); i++){
int index = 1;
Clob detailsClob = (Clob) idToDetailsClob.get(IDList.get(i));
pStmt.setClob(index++, detailsClob);
pStmt.setInt(index++, IDList.get(i));
pStmt.addBatch();
counter++;
if(counter % BATCH_SIZE == 0) {
pStmt.executeBatch();
pStmt.clearBatch();
counter = 0;
}
}
if(IDList.size() % BATCH_SIZE > 0) {
pStmt.executeBatch();
}
}
catch (SQLException se)
{
se.printStackTrace();
}
catch (IOException se)
{
se.printStackTrace();
}
finally
{
cleanup(conn, pStmt, null);
}
System.out.println(System.currentTimeMillis()-s1);
}
If I understand your code correctly, you are appending text to your details clob column.
Doing it in PL/SQL would be faster since you wouldn't have to fetch the clob across the network. For example you could prepare this statement:
DECLARE
l_details CLOB;
BEGIN
SELECT details INTO l_details FROM program_history WHERE ID = ?;
dbms_lob.append(l_details, ?);
END;
and bind currentBatch.get(i) and idToDetails.get(id).
Notice that you don't need an additional update with PL/SQL.
Execute your query with an updatable ResultSet so that you can update the data as you scroll through without separate update statements being executed.
You need to create your prepared statement with the resultSetConcurrency set to ResultSet.CONCUR_UPDATABLE. Check out the oracle documentation on dealing with streams for the various ways you can handle the clob data.