I use StatementResult = session.run(Cypher_query) to run cypher query with java. The program in concern is used to import nodes from csv files with LOAD CSV
This error is thrown:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.logging.SimpleFormatter.format(Unknown Source)
at java.util.logging.StreamHandler.publish(Unknown Source)
at java.util.logging.ConsoleHandler.publish(Unknown Source)
at java.util.logging.Logger.log(Unknown Source)
at java.util.logging.Logger.doLog(Unknown Source)
at java.util.logging.Logger.log(Unknown Source)
at org.neo4j.driver.internal.logging.JULogger.warn(JULogger.java:54)
at org.neo4j.driver.internal.security.TLSSocketChannel.close(TLSSocketChannel.java:477)
at org.neo4j.driver.internal.net.SocketClient.stop(SocketClient.java:192)
at org.neo4j.driver.internal.net.SocketConnection.close(SocketConnection.java:260)
at org.neo4j.driver.internal.net.ConcurrencyGuardingConnection.close(ConcurrencyGuardingConnection.java:178)
at org.neo4j.driver.internal.net.pooling.PooledSocketConnection.dispose(PooledSocketConnection.java:251)
at org.neo4j.driver.internal.net.pooling.PooledConnectionReleaseConsumer.accept(PooledConnectionReleaseConsumer.java:50)
at org.neo4j.driver.internal.net.pooling.PooledConnectionReleaseConsumer.accept(PooledConnectionReleaseConsumer.java:29)
at org.neo4j.driver.internal.net.pooling.PooledSocketConnection.close(PooledSocketConnection.java:200)
at org.neo4j.driver.internal.NetworkSession.closeCurrentConnection(NetworkSession.java:385)
at org.neo4j.driver.internal.NetworkSession.syncAndCloseCurrentConnection(NetworkSession.java:359)
at org.neo4j.driver.internal.NetworkSession.run(NetworkSession.java:102)
at org.neo4j.driver.internal.NetworkSession.run(NetworkSession.java:93)
at org.neo4j.driver.internal.NetworkSession.run(NetworkSession.java:73)
Is there any way to go around that error? Or is there no way except for importing less nodes?
The whole java code:
import java.io.File;
import java.io.FileNotFoundException;
import org.neo4j.driver.v1.AuthTokens;
import org.neo4j.driver.v1.Driver;
import org.neo4j.driver.v1.GraphDatabase;
import org.neo4j.driver.v1.Record;
import org.neo4j.driver.v1.Session;
import org.neo4j.driver.v1.StatementResult;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Logger;
public class ImporterImprovedVersion {
private static String path = "file:///C:/csvsToImport/csvs";
private int num;
private boolean headerPresent(String filePath) throws FileNotFoundException{
Scanner scanner = new Scanner(new File(filePath));
if(scanner.hasNext()){
String firstLine = scanner.nextLine();
scanner.close();
if(filePath.contains("address")){
System.out.println("address! " + this.num + " " + firstLine.contains("addr_tag_links"));
return firstLine.contains("addr_tag_links");
}else if (filePath.contains("transaction")){
System.out.println("transaction! " + this.num + " " + firstLine.contains("value_bitcoin"));
return firstLine.contains("value_bitcoin");
}else{
System.out.println("wallet! " + this.num + " " + firstLine.contains("primAddress,firstSeenTime"));
return firstLine.contains("primAddress,firstSeenTime");
}
}
scanner.close();
return false;
}
public ImporterImprovedVersion(int num, boolean withOutputIndex, Session session, String mainDir) throws FileNotFoundException{
this.num = num;
//import csvs and create corresponding nodes
String folderPath = ImporterImprovedVersion.path + num + "/";
System.out.println(folderPath);
String queryAddr = null;
if(this.headerPresent(mainDir + num + "\\addresses.csv")){
queryAddr = "LOAD CSV From '" + folderPath + "addresses.csv' AS line"
+ " WITH line"
+ " SKIP 1";
}else{
queryAddr = "LOAD CSV From '" + folderPath + "addresses.csv' AS line";
}
String queryWallet = null;
if(this.headerPresent(mainDir + num + "\\wallet.csv")){
queryWallet = "LOAD CSV From '" + folderPath + "wallet.csv' AS line"
+ " WITH line"
+ " SKIP 1";
}else{
queryWallet = "LOAD CSV From '" + folderPath + "wallet.csv' AS line";
}
File tranFile = new File(mainDir + num + "\\transactionRelation.csv");
String queryTran = null;
System.out.println(tranFile);
System.out.println(tranFile.exists());
if(tranFile.exists()){
if(this.headerPresent(mainDir + num + "\\transactionRelation.csv")){
queryTran = "LOAD CSV From '" + folderPath + "transactionRelation.csv' AS line"
+ " WITH line"
+ " SKIP 1";
}else{
queryTran = "LOAD CSV From '" + folderPath + "transactionRelation.csv' AS line";
}
}else{
if(this.headerPresent(mainDir + num + "\\transactionRelation1.csv")){
queryTran = "LOAD CSV From '" + folderPath + "transactionRelation1.csv' AS line"
+ " WITH line"
+ " SKIP 1";
}else{
queryTran = "LOAD CSV From '" + folderPath + "transactionRelation1.csv' AS line";
}
}
StatementResult sR = session.run(queryWallet
+ " MERGE (w:Wallet { primWallAddr:line[0]})"
+ " ON CREATE SET w.first_seen = line[1], w.last_seen=line[2]");
System.out.println("Wallet nodes created");
sR = session.run(queryAddr + " MERGE (a:Address {AddId:(line[0])})"
+ " SET a.addr_tag_link= CASE WHEN a.addr_tag_link = 'null' or a.addr_tag_link IS NULL THEN line[1] ELSE a.addr_tag_link END,"
+ " a.addr_tag= CASE WHEN a.addr_tag = 'null' or a.addr_tag IS NULL THEN line[2] ELSE a.addr_tag END,"
+ " a.first_seen=line[3], a.last_seen=line[4], a.multiExist= a.multiExist OR apoc.convert.toBoolean(line[6])"
+ " WITH a, line[5] as li5"
+ " MATCH (a), (wa:Wallet) WHERE li5=wa.primWallAddr"
+ " MERGE (a)-[r:BelongTo{uniqueReferenceBelongTo:(a.AddId + wa.primWallAddr)}]->(wa)"
+ " ON CREATE SET r.primWallAddr = wa.primWallAddr,"
+ " wa.first_seen = CASE WHEN apoc.date.parse(wa.first_seen, 's',\"yyyy-MM-dd'T'HH:mm:ss\") < apoc.date.parse(a.first_seen, 's',\"yyyy-MM-dd'T'HH:mm:ss\") THEN wa.first_seen ELSE a.first_seen END,"
+ " wa.last_seen = CASE WHEN apoc.date.parse(wa.last_seen, 's',\"yyyy-MM-dd'T'HH:mm:ss\") > apoc.date.parse(a.last_seen, 's',\"yyyy-MM-dd'T'HH:mm:ss\") THEN wa.last_seen ELSE a.last_seen END");
System.out.println("Address nodes created");
System.out.println("BelongTo rel created");
if(withOutputIndex){
sR = session.run(queryTran
+ " MATCH (senderAddress:Address {AddId:line[0]}), (senderAddress)-[:BelongTo]->(sender:Wallet),"
+ " (receiverAddress:Address {AddId:line[1]}), (receiverAddress)-[:BelongTo]->(receiver:Wallet)"
+ " MERGE (sender)-[r:SendTo{uniqueReferenceTran:(line[2] + line[8])}]->(receiver)"
+ " ON CREATE SET r.tranHashString=line[2],r.time=line[3],r.value_bitcoin=line[4],"
+ "r.value_dollar=line[5],r.type=line[6],r.estChanAddr=line[7],r.outputIndex=line[8]");
}else{
System.out.println("withoutOutputIndex");
sR = session.run(queryTran
+ " MATCH (senderAddress:Address {AddId:line[0]}), (senderAddress)-[:BelongTo]->(sender:Wallet),"
+ " (receiverAddress:Address {AddId:line[1]}), (receiverAddress)-[:BelongTo]->(receiver:Wallet)"
+ " MERGE (sender)-[r:SendTo{uniqueReferenceTran:(line[2] + 'default')}]->(receiver)"
+ " ON CREATE SET r.tranHashString=line[2],r.time=line[3],r.value_bitcoin=line[4],"
+ " r.value_dollar=line[5],r.type=line[6],r.estChanAddr=line[7],r.outputIndex='default'");
}
sR.list();
System.out.println("Tran rel created");
String queryAddrDiffWallet = "MATCH (a:Address)-[:BelongTo]->(w1:Wallet), (a)-[r0:BelongTo]->(w2:Wallet)"
+ " WHERE w1 <> w2"
+ " RETURN count(a)";
sR = session.run(queryAddrDiffWallet);
List<Record> records = sR.list();
System.out.println(records.get(0).get("count(a)").asInt());
System.out.println(records.get(0).get("count(a)").asInt() == 0);
if(records.get(0).get("count(a)").asInt() != 0){
sR = session.run("MATCH (a:Address)-[:BelongTo]->(w1:Wallet), (a)-[r0:BelongTo]->(w2:Wallet)"
+ " WHERE w1 <> w2"
+ " RETURN a");
}
String queryMergeWallet = "MATCH (a:Address)-[:BelongTo]->(w1:Wallet)"
+ " WITH DISTINCT a, min(ID(w1)) as minId"
+ " MATCH (minW:Wallet)"
+ " WHERE ID(minW) = minId"
+ " SET a.primWallAddr = minW.primWallAddr"
+ " WITH DISTINCT minW, a"
+ " MATCH (a)-[r0:BelongTo]->(w2:Wallet)"
+ " WHERE minW <> w2"
+ " WITH DISTINCT minW, w2, r0"
+ " SET minW.first_seen = CASE WHEN apoc.date.parse(minW.first_seen, 's',\"yyyy-MM-dd'T'HH:mm:ss\") < apoc.date.parse(w2.first_seen, 's',\"yyyy-MM-dd'T'HH:mm:ss\") THEN minW.first_seen ELSE w2.first_seen END,"
+ " minW.last_seen = CASE WHEN apoc.date.parse(minW.last_seen, 's',\"yyyy-MM-dd'T'HH:mm:ss\") > apoc.date.parse(w2.last_seen, 's',\"yyyy-MM-dd'T'HH:mm:ss\") THEN minW.last_seen ELSE w2.last_seen END"
+ " WITH DISTINCT minW, w2, r0"
+ " DELETE r0"
+ " WITH DISTINCT minW, w2"
+ " MATCH (b:Address)-[r:BelongTo]->(w2)"
+ " WITH DISTINCT r, minW, w2, b"
+ " DELETE r"
+ " WITH DISTINCT b, minW, w2"
+ " MERGE (b)-[be:BelongTo{uniqueReferenceBelongTo:(b.AddId + minW.primWallAddr)}]->(minW)"
+ " ON CREATE SET be.primWallAddr = minW.primWallAddr"
+ " WITH DISTINCT w2, minW"
+ " MATCH (w3:Wallet)-[r2:SendTo]->(w2)"
+ " MERGE (w3)-[rN:SendTo{uniqueReferenceTran:r2.uniqueReferenceTran}]->(minW)"
+ " ON CREATE SET rN.tranHashString=r2.tranHashString,rN.time=r2.time,"
+ "rN.value_bitcoin=r2.value_bitcoin,rN.value_dollar=r2.value_dollar,"
+ "rN.type=r2.type,rN.estChanAddr=r2.estChanAddr,rN.outputIndex=r2.outputIndex"
+ " WITH DISTINCT w2, minW, r2"
+ " DELETE r2"
+ " WITH DISTINCT w2, minW"
+ " MATCH (w2)-[r1:SendTo]->(w4:Wallet)"
+ " MERGE (minW)-[rN2:SendTo{uniqueReferenceTran:r1.uniqueReferenceTran}]->(w4)"
+ " ON CREATE SET rN2.tranHashString=r1.tranHashString,rN2.time=r1.time,"
+ "rN2.value_bitcoin=r1.value_bitcoin,rN2.value_dollar=r1.value_dollar,"
+ "rN2.type=r1.type,rN2.estChanAddr=r1.estChanAddr,rN2.outputIndex=r1.outputIndex"
+ " WITH DISTINCT r1"
+ " DELETE r1"
;
if(records.get(0).get("count(a)").asInt() != 0){
//merge any wallet containing same addresses and adjust the transaction as well (w2 merge to w1)
try{
sR = session.run(queryMergeWallet);
}catch(Exception e){
e.printStackTrace();
try {
Thread.sleep(20000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
sR = session.run(queryMergeWallet);
}
}
System.out.println("same wallet merged");
System.out.println("----------abc----------------------" + num);
//delete all wallets with no addresses
sR = session.run(
" MATCH (n:Wallet)"
+ " WHERE NOT ()-[:BelongTo]->(n)"
+ " DETACH DELETE n"
);
System.out.println("Wall with no addr deleted");
}
public static void main(String[] args) throws FileNotFoundException{
Driver driver = GraphDatabase.driver( "bolt://localhost:7687", AuthTokens.basic( "neo4j", "neo7474" ) );
try(Session session = driver.session()){
String mainDir = "C:\\Program Files\\neo4j-enterprise-3.1.1\\import\\csvsToImport\\csvs";
// create index
session.run( "CREATE CONSTRAINT ON (addr:Address) ASSERT addr.AddId IS UNIQUE");
session.run( "CREATE CONSTRAINT ON (wa:Wallet) ASSERT wa.primWallAddr IS UNIQUE");
System.out.println("aaa");
int counter = 537;
while(counter < 660){
File dir = new File(mainDir + counter);
if(dir.exists()){
System.out.println("aaa");
ImporterImprovedVersion a = new ImporterImprovedVersion(counter, counter > 260, session, mainDir);
}
counter ++;
}
}
}
}
I imported many rows for nodes and relationships. By the time the exception is thrown, the graph has 184448 relationships, 82179 of them have 8 properties; and 117314 nodes, 69714 of them have 6 properties. I will update my question with this information. (Could the number of nodes and relationships along with their properties be the reason?)
Did you try to increase the heap size in the JVM (-Xmx option)? The CSVs you are trying to import may be too big.
LOAD CSV has built in batching possibilities. So whenever you are running out of memory using LOAD CSV use PERIODIC COMMIT. Read more in documentation.
Example:
USING PERIODIC COMMIT 10000
LOAD CSV WITH HEADERS FROM "file:///customers.csv" AS row
CREATE (:Customer {companyName: row.CompanyName})
Related
One web project I'm involved in requires generating a CSV to the user.
One field is notes and there can be multiple notes in the field, separated by a return (alt-enter in Excel), appearing as
A USER entered on 02/17/2023: Test note
A USER entered on 02/17/2023: This is another note
Is it possible to insert control codes into a Java string that Excel will pick up and format the cell properly?
For what it's worth, this was my attempt:
}else if (formType.equalsIgnoreCase("downloadCSV")) {
Date d = new Date();
String filename = "C:/temp/rtTmp" + d.getTime() + ".csv";
File f = new File(filename);
List<Contact> contactList = RetentionTrackDatabaseUtil.getContacts();
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
bw.write("name,"
+ "gender,"
+ "age,"
+ "DOB,"
+ "DOH,"
+ "DOR,"
+ "DOS,"
+ "dateContact,"
+ "reason,"
+ "status,"
+ "empNum,"
+ "shift,"
+ "phone,note(s)\n");
for (Contact c : contactList) {
System.out.println(c.getAge());
bw.append("\"" + c.getName() + "\"" + ","
+ c.getGender() + ","
+ Integer.toString(c.getAge()) + ","
+ (c.getDOB()!=null?RetentionTrackUtil.sdf.format(c.getDOB()):"") + ","
+ (c.getDOH()!=null?RetentionTrackUtil.sdf.format(c.getDOH()):"") + ","
+ (c.getDOR()!=null?RetentionTrackUtil.sdf.format(c.getDOR()):"") + ","
+ (c.getDOS()!=null?RetentionTrackUtil.sdf.format(c.getDOS()):"") + ","
+ (c.getDateContact()!=null?RetentionTrackUtil.sdf.format(c.getDateContact()):"") + ","
+ c.getReason() + ","
+ c.getStatus() + ","
+ c.getEmpNum() + ","
+ c.getShift() + ","
+ c.getPhone() + ",");
for(Note n: c.getNoteList()){
bw.append("(" + n.getEnteredBy() + " on " + RetentionTrackUtil.sdf.format(n.getNoteDate()) + ")" + n.getNote() + "\\n");
}
bw.append("\n");
}
bw.close();
sendFile(response, filename);
}
I wrote a piece of JDBC template code, which inserts the record in the table, but the problem is my execution is stuck on this particular snippet, it seems some kind of hang up. I didn't figure out the cause as query properly running in sqldeveloper
List<SalaryDetailReport> reports = salaryDetailReportDAO.findAll(tableSuffix, regionId, circleId);
// the above line find the required data, if data is found then it proceeds
if (reports != null && reports.size() > 0) {
for (SalaryDetailReport salaryDetail : reports) {
try {
SalaryDetail sd = new SalaryDetail();
sd.setDetailReport(salaryDetail);
salaryDetailDAO.save(sd, tableSuffix);
} catch (Exception e) {
log.error("Error occured", e);
e.printStackTrace();
throw new MyExceptionHandler(" Error :" + e.getMessage());
}
}
System.out.println("data found");
} else {
log.error("Salary Record Not Found.");
throw new MyExceptionHandler("No record Found.");
}
You people saw try-catch , my execution stuck inside try and catch and here is the insertion code in my implementation class. when i commented the above code then my application works fine, but why my application stuck here, I am not able to figure it out, kindly help me
#Override
public void save(SalaryDetail details, String tableSuffix) {
String tabName = "SALARY_DETAIL_" + tableSuffix;
// String q = "INSERT INTO " + tabName + "(ID "
String q = "INSERT INTO SALARY_DETAIL_TBL "
+ " (ID "
+ " ,EMP_NAME "
+ " ,EMP_CODE "
+ " ,NET_SALARY "
+ " ,YYYYMM "
+ " ,PAY_CODE "
+ " ,EMP_ID "
+ " ,PAY_CODE_DESC "
+ " ,REMARK "
+ " ,PAY_MODE ) "
+ " (SELECT (sd.SALARY_REPORT_ID) ID "
+ " ,(sd.emp_name) emp_name "
+ " ,(sd.EMP_CODE) EMP_CODE "
+ " ,(sd.amount) NET_SALARY "
+ " ,(sd.YYYYMM) YYYYMM "
+ " ,(sd.pay_code) pay_code "
+ " ,(sd.emp_id) emp_id "
+ " ,(sd.PAY_CODE_DESC) PAY_CODE_DESC "
+ " ,(sd.REMARK) REMARK "
+ " ,(sd.PAY_MODE)PAY_MODE "
// + " FROM SALARY_DETAIL_REPORT_" + tableSuffix + " sd "
+ " FROM SALARY_DETAIL_REPORT_TBL sd "
+ " WHERE sd.PAY_CODE = 999 "
+ " AND sd.EMP_ID IS NOT NULL "
// + " AND sd.EMP_ID NOT IN (SELECT EMP_ID FROM SALARY_DETAIL_" + tableSuffix + ") "
+ " AND sd.EMP_ID NOT IN (SELECT EMP_ID FROM SALARY_DETAIL_TBL) "
+ " ) ";
MapSqlParameterSource param = new MapSqlParameterSource();
param.addValue("id", details.getId());
param.addValue("EMP_NAME", details.getEmpName());
param.addValue("EMP_CODE", details.getEmpCode());
param.addValue("NET_SALARY", details.getNetSalary());
param.addValue("GROSS_EARNING", details.getGrossEarning());
param.addValue("GROSS_DEDUCTION", details.getGrossDeduction());
param.addValue("YYYYMM", details.getYyyymm());
param.addValue("EMP_ID", details.getEmployee() != null ? details.getEmployee().getEmpId() : null);
KeyHolder keyHolder = new GeneratedKeyHolder();
getNamedParameterJdbcTemplate().update(q, param);
// details.setId(((BigDecimal) keyHolder.getKeys().get("ID")).longValue());
}
The main problem is in your query is Not In condition. It will degrade your performance. Try to fetch the "SELECT EMP_ID FROM SALARY_DETAIL_TB" in a separate query and pass in the Not in block in the main query. This will increase the performance of your query. Every time a save is performed this will fire the select query every time.
You have to decide whether you will insert records from SELECT or from the application.
If you don't need to manipulate with data after their select then you can simply call one INSERT INTO SELECT statement without any for cycle. It will be fast because of the only one INSERT statement call.
So you will implement method like copyAllInSalaryDetail(tableSuffix, regionId, circleId) in your SalaryDetailReportDAO and that method will execute INSERT INTO salary_detail_tbl... (...) (SELECT ... WHERE ...) using the same WHERE condition as you have in findAll() method. All inserts will be done only on the Database layer.
If you want to manipulate with data before their insert you can continue with your approach using SalaryDetail bean and for cycle, but you should remove the SELECT part from the INSERT statement and use values from the provided bean. Then the save() method can look like:
#Override
public void save(SalaryDetail details, String tableSuffix) {
// use tableSuffix if it is really needed
String q = "INSERT INTO SALARY_DETAIL_TBL "
+ " (ID "
+ " ,EMP_NAME "
+ " ,EMP_CODE "
+ " ,NET_SALARY "
+ " ,YYYYMM "
+ " ,PAY_CODE "
+ " ,EMP_ID "
+ " ,PAY_CODE_DESC "
+ " ,REMARK "
+ " ,PAY_MODE ) "
+ " VALUES (:id "
+ " ,:emp_name "
+ " ,:emp_code "
+ " ,:net_salary "
+ " ,:yyyymm "
+ " ,:pay_code "
+ " ,:emp_id "
+ " ,:pay_code_desc "
+ " ,:remark "
+ " ,:pay_mode)";
MapSqlParameterSource param = new MapSqlParameterSource();
// KeyHolder keyHolder = new GeneratedKeyHolder();
// details.setId(((BigDecimal) keyHolder.getKeys().get("ID")).longValue());
param.addValue("id", details.getId());
param.addValue("emp_name", details.getEmpName());
param.addValue("emp_code", details.getEmpCode());
param.addValue("net_salary", details.getNetSalary());
param.addValue("pay_code", details.getPayCode());
param.addValue("pay_code_desc", details.getPayCodeDesc());
param.addValue("pay_mode", details.getPayMode());
param.addValue("remark", details.getPayRemark());
param.addValue("yyyymm", details.getYyyymm());
param.addValue("emp_id", details.getEmployee() != null ? details.getEmployee().getEmpId() : null);
getNamedParameterJdbcTemplate().update(q, param);
}
I am trying to output arrays on a new line through a basic client, server application. However, to accomplish this I have had to use substring to find the # after each word to signal the end of the line. However I want to remove this function and have each section on a new line.
public ClientHandler(Socket socket,Users newUser, int newClientUser)
throws IOException
{
client = socket;
input = new Scanner(client.getInputStream());
output = new PrintWriter(
client.getOutputStream(),true);
user = newUser;
clientUser = newClientUser;
String[] itemName = {user.getItemName(1), user.getItemName(2)};
String[] description = {user.getItemDescription(1), user.getItemDescription(2)};
String[] itemtime = {user.getItemTime(1), user.getItemTime(2)};
output.println(itemName[0] + "#" + itemName[1]
+ "#" + "Welcome To The Auction User:" + clientUser
+ itemName[0] +": "+ description[0] +
"#"+ itemName[1] +": "+description[1]+
"#"+ "Deadline For " + itemName[0] + ": "
+ itemtime[0] + "#" +"Deadline For " +
itemName[1] + ": " + itemtime[1]+"#");
}
private synchronized void getMessage(String response)
{
String message="";
for(int i= count; !response.substring(i, i+1).equals("#"); i++)
{
count = i;
}
}
output.println(itemName[0] + "\n" + itemName[1]
+ "\n" + "Welcome To The Auction User:" + clientUser
+ itemName[0] +": "+ description[0] +
"\n"+ itemName[1] +": "+description[1]+
"\n"+ "Deadline For " + itemName[0] + ": "
+ itemtime[0] + "\n" +"Deadline For " +
itemName[1] + ": " + itemtime[1]+"\n");
Instead of having a "#" signify a new line, you can use "\n". Java will read that from your string as a new line.
I need the currentStockLevel for another void Method in java, is there any possibility to get it?
I think no, because of void right?
public void receive (int currentStock)
{
String outLine;
if (currentStockLevel > 0)
outLine = productCode;
{
outLine = ". Current Stock: " + currentStockLevel;
outLine += " Current Stock changed from " + currentStockLevel;
currentStockLevel += currentStock;
outLine += " to " + currentStockLevel;
int storeCost = wholeSalePrice * currentStockLevel;
System.out.println (productCode + ":" + " Received " + currentStockLevel + "." + " Store Cost " + "$" + storeCost + "." + " New stock level: " + currentStockLevel);
}
I was wondering if someone here could help me, I can't find a solution for my problem and I have tried everything.
What I am trying to do is read and parse lines in a csv file into java objects and I have succeeded in doing that but after it reads all the lines it should insert the lines into the database but it only inserts the 1st line the entire time and I don't no why. When I do a print it shows that it is reading all the lines and placing them in the objects but as soon as I do the insert it wants to insert only the 1st line.
Please see my code below:
public boolean lineReader(File file){
BufferedReader br = null;
String line= "";
String splitBy = ",";
storeList = new ArrayList<StoreFile>();
try {
br = new BufferedReader(new FileReader(file));
while((line = br.readLine())!=null){
line = line.replace('|', ',');
//split on pipe ( | )
String[] array = line.split(splitBy, 14);
//Add values from csv to store object
//Add values from csv to storeF objects
StoreFile StoreF = new StoreFile();
if (array[0].equals("H") || array[0].equals("T")) {
return false;
} else {
StoreF.setRetailID(array[1].replaceAll("/", ""));
StoreF.setChain(array[2].replaceAll("/",""));
StoreF.setStoreID(array[3].replaceAll("/", ""));
StoreF.setStoreName(array[4].replaceAll("/", ""));
StoreF.setAddress1(array[5].replaceAll("/", ""));
StoreF.setAddress2(array[6].replaceAll("/", ""));
StoreF.setAddress3(array[7].replaceAll("/", ""));
StoreF.setProvince(array[8].replaceAll("/", ""));
StoreF.setAddress4(array[9].replaceAll("/", ""));
StoreF.setCountry(array[10].replaceAll("/", ""));
StoreF.setCurrency(array[11].replaceAll("/", ""));
StoreF.setAddress5(array[12].replaceAll("/", ""));
StoreF.setTelNo(array[13].replaceAll("/", ""));
//Add stores to list
storeList.add(StoreF);
}
} //print list stores in file
printStoreList(storeList);
executeStoredPro(storeList);
} catch (Exception ex) {
nmtbatchservice.NMTBatchService2.LOG.error("An exception accoured: " + ex.getMessage(), ex);
//copy to error folder
//email
}
return false;
}
public void printStoreList(List<StoreFile> storeListToPrint) {
for(int i = 0; i <storeListToPrint.size();i++){
System.out.println( storeListToPrint.get(i).getRetailID()
+ storeListToPrint.get(i).getChain()
+ storeListToPrint.get(i).getStoreID()
+ storeListToPrint.get(i).getStoreName()
+ storeListToPrint.get(i).getAddress1()
+ storeListToPrint.get(i).getAddress2()
+ storeListToPrint.get(i).getAddress3()
+ storeListToPrint.get(i).getProvince()
+ storeListToPrint.get(i).getAddress4()
+ storeListToPrint.get(i).getCountry()
+ storeListToPrint.get(i).getCurrency()
+ storeListToPrint.get(i).getAddress5()
+ storeListToPrint.get(i).getTelNo());
}
}
public void unzip(String source, String destination) {
try {
ZipFile zipFile = new ZipFile(source);
zipFile.extractAll(destination);
deleteStoreFile(source);
} catch (ZipException ex) {
nmtbatchservice.NMTBatchService2.LOG.error("Error unzipping file : " + ex.getMessage(), ex);
}
}
public void deleteStoreFile(String directory) {
try {
File file = new File(directory);
file.delete();
} catch (Exception ex) {
nmtbatchservice.NMTBatchService2.LOG.error("An exception accoured when trying to delete file " + directory + " : " + ex.getMessage(), ex);
}
}
public void executeStoredPro(List<StoreFile> storeListToInsert) {
Connection con = null;
CallableStatement st = null;
try {
String connectionURL = MSSQLConnectionURL;
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver").newInstance();
con = DriverManager.getConnection(connectionURL, MSSQLUsername, MSSQLPassword);
for(int i = 0; i <storeListToInsert.size();i++){
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores WHERE StoreID = " + storeListToInsert.get(i).getStoreID() + " AND RetailID = "+ storeListToInsert.get(i).getRetailID() + ")"
+ " UPDATE tblPay#RetailStores "
+ " SET RetailID = '" + storeListToInsert.get(i).getRetailID() + "',"
+ " StoreID = '" + storeListToInsert.get(i).getStoreID() + "',"
+ " StoreName = '" + storeListToInsert.get(i).getStoreName() + "',"
+ " TestStore = 0,"
+ " Address1 = '" + storeListToInsert.get(i).getAddress1() + "',"
+ " Address2 = '" + storeListToInsert.get(i).getAddress2() + "',"
+ " Address3 = '" + storeListToInsert.get(i).getAddress3() + "',"
+ " Address4 = '" + storeListToInsert.get(i).getAddress4() + "',"
+ " Address5 = '" + storeListToInsert.get(i).getAddress5() + "',"
+ " Province = '" + storeListToInsert.get(i).getProvince() + "',"
+ " TelNo = '" + storeListToInsert.get(i).getTelNo() + "',"
+ " Enabled = 1"
+ " ELSE "
+ " INSERT INTO tblPay#RetailStores ( [RetailID], [StoreID], [StoreName], [TestStore], [Address1], [Address2], [Address3], [Address4], [Address5], [Province], [TelNo] , [Enabled] ) "
+ " VALUES "
+ "('" + storeListToInsert.get(i).getRetailID() + "',"
+ "'" + storeListToInsert.get(i).getStoreID() + "',"
+ "'" + storeListToInsert.get(i).getStoreName() + "',"
+ "0,"
+ "'" + storeListToInsert.get(i).getAddress1() + "',"
+ "'" + storeListToInsert.get(i).getAddress2() + "',"
+ "'" + storeListToInsert.get(i).getAddress3() + "',"
+ "'" + storeListToInsert.get(i).getAddress4() + "',"
+ "'" + storeListToInsert.get(i).getAddress5() + "',"
+ "'" + storeListToInsert.get(i).getProvince() + "',"
+ "'" + storeListToInsert.get(i).getTelNo() + "',"
+ "1)");
st.executeUpdate();
}
con.close();
} catch (Exception ex) {
nmtbatchservice.NMTBatchService2.LOG.error("Error executing Stored proc with error : " + ex.getMessage(), ex);
nmtbatchservice.NMTBatchService2.mailingQueue.addToQueue(new Mail("support#nmt-it.co.za", "Service Email Error", "An error occurred during Store Import failed with error : " + ex.getMessage()));
}
}
Any advise would be appreciated.
Thanks
Formatting aside, your code is wrong (I truncated the part of the query):
for(int i = 0; i <storeListToInsert.size();i++){
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores ...
+ "'" + storeListToInsert.get(i).getTelNo() + "',"
+ "1)");
st.executeUpdate();
}
Don't do a classical for loop while foreach exists and can be better to use, and even if you do a classical for loop, use local variables, eg:
for(int i = 0; i <storeListToInsert.size();i++){
StoreFile item = storeListToInsert.get(i);
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores ...
+ "'" + item.getTelNo() + "',"
+ "1)");
st.executeUpdate();
}
Which could translate as:
for (StoreFile item : storeListToInsert) {
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores ...
+ "'" + item.getTelNo() + "',"
+ "1)");
st.executeUpdate();
}
Now, the second problem is your PreparedStatement. A PreparedStatement allow reusing, which means you don't need to create PreparedStatement per item which is what you are doing.
Also, you need to close the statement otherwise, you will exhaust resources..
You must not create it in the for loop, but before, like this:
PreparedStatement st = null;
try {
st = con.prepareCall( "IF EXISTS (SELECT * FROM tblPay#RetailStores ...
+ "SET RetailID = :RetailID ,"
+ "1)");
for (StoreFile item : storeListToInsert) {
st.setString(":RetailID", item.getRetailID());
st.executeUpdate();
}
} finally {
if (null != st) {st.close();}
}
In brief:
You need to close the PreparedStatement after usage, because it is a memory leak otherwise.
You need to rewrite your query using either named parameters, either positional parameter (like: ? or ?1 for first parameter, and so on). I favor named parameters, but they are not always available. The example I linked all use positional parameters.
You need to set the value for each parameters in the for loop, and care about the type. I expected here that getRetailID() is a String, but it might be a Long in that case that would be st.setLong.
Your query is reusable, avoiding the need to reparse it/resend it to the SQL Server. You just send the parameter's values. Beside, you can also batch update.
A PreparedStatement for a statement that you generate (like you are doing) is overkill, and beside, it is missing SQL escapement to protect the String you inject to your query to avoid it being badly interpreted (aka SQL errors) or worst, to do what it was not intended for (like, even if it is far fetched, dropping the whole database, etc).
The executeUpdate() return the number of updated rows. You can check it to see if there was updates.
You can also use Batch statement, which can help performances.
And finally, you can use opencsv to parse common CSV files.