just curious if anyone has any idea for making this program more simple. It reads records from a database into an ArrayList and allows the user to search for records by state. It processes a database of 1 million records in aprox 16000ms.
import java.sql.*;
import java.util.*;
public class ShowEmployeeDB
{
public static void main(String args[])
{
ArrayList <String> Recs = new ArrayList <String>();
String driverName = "sun.jdbc.odbc.JdbcOdbcDriver";
String connectionURL = "jdbc:odbc:CitizensDB";
Connection con = null;
Statement stmt = null;
String sqlStatement = "SELECT * FROM Citizens";
ResultSet rs = null;
int r = 0;
Scanner scan = new Scanner(System.in);
String search = null;
long starttime = System.currentTimeMillis();
try
{
Class.forName(driverName).newInstance();
con = DriverManager.getConnection(connectionURL);
stmt = con.createStatement();
rs = stmt.executeQuery(sqlStatement);
String ID = null;
String Age = null;
String State = null;
String Gender = null;
String Status = null;
String record = null;
while (rs.next())
{
for (int k = 1; k <= 1; ++k)
{
ID = rs.getString(k) + " ";
for (int j = 2; j <= 2; ++j)
Age = rs.getString(j) + " ";
for (int i = 3; i <= 3; ++i)
State = rs.getString(i).toUpperCase() + " ";
for (int h = 4; h <= 4; ++h)
Gender = rs.getString(h) + " ";
for (int g = 5; g <= 5; ++g)
Status = rs.getString(g) + " ";
}//for
record = ID + Age + State + Gender + Status;
Recs.add(record);
++r;
}//while
rs.close();
stmt.close();
con.close();
} catch (Exception ex) { ex.printStackTrace(); }
String endtime = System.currentTimeMillis() - starttime + "ms";
System.out.println(endtime);
System.out.print("Enter A Search State: ");
search = scan.nextLine().toUpperCase();
Iterator<String> iter = Recs.iterator();
while(iter.hasNext())
{
String s = iter.next();
if (s.contains(search))
{
System.out.println(s);
}
}//while
} // main
} // ShowEmployeeBD
Any advice would be greatly appreciated. Thank you in advance!
If search is not often, I would suggest to take the search string input before running the query, so that search results are directly from the DB. I this case you do not have to reiterate all 1 million records.
Perform searching directly on DB rather than fetching all the records and searching through java code.
Also if search is on multiple column, then prepare a meta data in DB at a single place on the basis of IDs, and the meta data can further be used for fetching the required results that match the query.
Separate your logic from the technical stuff. In such a convolut it is difficult to run unit tests or any optimizations.
Why do you need for loops, when only asking one value.
Use StringBuilder instead of String concatenation.
Use either try-with or put your close statements in a finally clause.
Don't initialize variables you don't need (r).
Use for each statements.
Query the database, not the result set.
Tune your database.
If you are only searching for a state, filter only those, so build an object and compare the state instead of a string contains.
Compare the state before storing strings in the list.
Tune your list because it constantly grows with 1Mio records.
Use a hashset instead of an arraylist.
Develop against interfaces.
A better program might look like following:
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class ShowEmployeeDB {
private static final String DRIVERNAME = "sun.jdbc.odbc.JdbcOdbcDriver";
private static final String CONNECTIONURL = "jdbc:odbc:CitizensDB";
private static final String SELECT_CITIZENS = "SELECT * FROM Citizens";
static {
try {
DriverManager.registerDriver((Driver) Class.forName(DRIVERNAME).newInstance());
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
public static void main(final String args[]) {
System.out.print("Enter A Search State: ");
searchRecords();
}
private static void searchRecords() {
try(Scanner scan = new Scanner(System.in);) {
final String state = scan.nextLine();
final long starttime = System.currentTimeMillis();
final Set<Record> records = searchRecordsByState(state);
System.out.println(System.currentTimeMillis() - starttime + "ms");
for(final Record r : records) {
System.out.println(r);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private static Set<Record> searchRecordsByState(final String stateToFilter) {
final Set<Record> records = new HashSet<>();
try(Connection con = DriverManager.getConnection(CONNECTIONURL);
PreparedStatement stmt = con.prepareStatement(SELECT_CITIZENS);
ResultSet rs = stmt.executeQuery(); ) {
while(rs.next()) {
final String state = rs.getString(3);
if(state.equalsIgnoreCase(stateToFilter)) {
final Record r = new Record(rs.getString(1), rs.getString(2), state, rs.getString(4), rs.getString(5));
records.add(r);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return records;
}
}
class Record {
String id, age, state, gender, status;
public Record(String id, String age, String state, String gender, String status) {
this.id = id;
this.age = age;
this.state = state;
this.gender = gender;
this.status = status;
}
public String getState() {
return state;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(id).append(' ')
.append(age).append(' ')
.append(state).append(' ')
.append(gender).append(' ')
.append(status);
return sb.toString();
}
}
This is untested, because I don't have a database with a million entries by hand.
But the best would be to query the database and catch only those entries you need. So use the WHERE-clause in your statement.
Related
I'm trying to read all records in a table from a database, and do some processing using those data. Following is the code that I use.
package differences;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
public class ConformancePercentageChecking {
private final String dbDriver = "com.mysql.jdbc.Driver";
private Connection connection = null;
private final String serverName = "localhost";
private final String mydatabase = "google";
private final String username = "root";//kh hoseinpur
private final String password = "123";
private final String extrainfo = "?useUnicode=true&characterEncoding=UTF-8";
int numberOfInsertedIDs = 0;
public void findConformances() {
try {
try {
Class.forName(dbDriver);//a call to forname("X") causes the class named X to be initialized
String url = "jdbc:mysql://" + serverName + "/" + mydatabase + extrainfo;
if (connection == null) {
connection = (Connection) DriverManager.getConnection(url, username, password);
}
} catch (ClassNotFoundException | SQLException e) {
JOptionPane.showMessageDialog(null, "database");
}
String query1, query2, query3, query4, query5, query6, testSuite, id;
PreparedStatement statement1, statement2, statement3, statement4, statement5, statement6;
query1 = "drop table PresConformance;";
query2 = "drop table PostConformance;";
statement1 = connection.prepareStatement(query1);
statement2 = connection.prepareStatement(query2);
statement1.executeUpdate();
statement2.executeUpdate();
query1 = "CREATE TABLE PresConformance(testSuite Text, conformance numeric(10), depthDifference numeric(10),pathLength numeric(10));";
query2 = "CREATE TABLE PostConformance(testSuite Text, conformance numeric(10), depthDifference numeric(10),pathLength numeric(10));";
query3 = "SELECT * FROM presDifference;";
query4 = "SELECT * FROM presdifference;";
query5 = "insert into PresConformance values(?,?,?,?);";
query6 = "insert into PostConformance values(?,?,?,?);";
statement1 = connection.prepareStatement(query1);
statement2 = connection.prepareStatement(query2);
statement3 = connection.prepareStatement(query3);
statement4 = connection.prepareStatement(query4);
statement5 = connection.prepareStatement(query5);
statement6 = connection.prepareStatement(query6);
Map<String, String> map = new HashMap<>();
statement1.executeUpdate();
statement2.executeUpdate();
ResultSet r1, r2, r3, r4;
r1 = statement3.executeQuery();
System.out.println("***1");
r2 = statement4.executeQuery();
System.out.println("***2");
int idCount = 0, depthDifference = 0, totalNumberOfExecutions = 0, testSuitesCounts = 0, difference = 0, pathLength = 0;
float conformancePercentage = 0, sumOfconformancePercentage = 0;
r3 = r1;
r4 = r2;
while (r1.next()) {
testSuitesCounts = 0;
sumOfconformancePercentage = 0;
testSuite = r1.getString("testSuite");
id = null;
id = map.get(testSuite);
if (id == null) {
idCount++;
map.put(Integer.toString(idCount), testSuite);
r3.absolute(r1.getRow());
r3.previous();
while (r3.next()) {
if (testSuite.equals(r3.getString("testSuite"))) {
System.out.println(testSuite + " equal");
totalNumberOfExecutions = r3.getInt("totalNumberOfExecutions");
difference = r3.getInt("difference");
conformancePercentage = (1 - ((float) difference / totalNumberOfExecutions)) * 100;
if (testSuitesCounts == 0) {
String[] testSuite1, testSuite2, testSuite3;
testSuite1 = testSuite.split("_");
testSuite2 = testSuite1[0].split("/");
testSuite3 = testSuite1[1].split("/");
depthDifference = Math.abs(testSuite2.length - 1) - testSuite3.length;
pathLength = (testSuite2.length - 1) + testSuite3.length;
}
testSuitesCounts++;
sumOfconformancePercentage += conformancePercentage;
}
}
statement5.setString(1, testSuite);
statement5.setFloat(2, (sumOfconformancePercentage / testSuitesCounts));
statement5.setInt(3, depthDifference);
statement5.setInt(4, pathLength);
statement5.executeUpdate();
}
System.out.println(r1.getRow());
}
System.out.println("Pres Finished*****************************************");
idCount = 0;
map = new HashMap<>();
while (r2.next()) {
testSuitesCounts = 0;
sumOfconformancePercentage = 0;
testSuite = r2.getString("testSuite");
id = null;
id = map.get(testSuite);
if (id == null) {
idCount++;
map.put(Integer.toString(idCount), testSuite);
r4.absolute(r2.getRow());
r4.previous();
while (r4.next()) {
if (testSuite.equals(r4.getString("testSuite"))) {
System.out.println(testSuite + " equal");
totalNumberOfExecutions = r4.getInt("totalNumberOfExecutions");
difference = r4.getInt("difference");
conformancePercentage = (1 - ((float) difference / totalNumberOfExecutions)) * 100;
if (testSuitesCounts == 0) {
String[] testSuite1, testSuite2, testSuite3;
testSuite1 = testSuite.split("_");
testSuite2 = testSuite1[0].split("/");
testSuite3 = testSuite1[1].split("/");
depthDifference = Math.abs(testSuite2.length - 1) - testSuite3.length;
pathLength = (testSuite2.length - 1) + testSuite3.length;
}
testSuitesCounts++;
sumOfconformancePercentage += conformancePercentage;
}
}
statement6.setString(1, testSuite);
statement6.setFloat(2, (sumOfconformancePercentage / testSuitesCounts));
statement6.setInt(3, depthDifference);
statement6.setInt(4, pathLength);
statement6.executeUpdate();
}
}
System.out.println("Post Finished*****************************************");
System.out.println("Finished Inserting to DB");
} catch (SQLException ex) {
Logger.getLogger(DifferencesPresPost.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
The problem, is that for both ResultSet objects r1 and r3, which contain tables' records, it just iterates once, and then reaches the end of the ResultSet objects.
I tried to count number of records in both ResultSet objects before each while loop, and it correctly prints the number of recoreds, but when it enters in these while loops, it works for only first row of each ResultSet objects.
Can any body help me to find out the result of this problem?
I believe by default your resultsets are TYPE_FORWARD_ONLY. You need to specify TYPE_SCROLL_INSENSITIVE when preparing your prepared statements. Hope this helps.
package Simple;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.text.*;
public class CurrentProg {
//connecting to the database
private static final String DB_DRIVER = "com.mysql.jdbc.Driver";
private static final String DB_CONNECTION ="jdbc:mysql://localhost:3306/db?autoReconnect=true";
private static final String DB_USER = "root";
private static final String DB_PASSWORD = "root";
static Connection dbConnection = null;
static Statement statement = null;
static int total=1;
//Searching between startdate and enddate
public static java.util.LinkedList searchBetweenDates(java.util.Date startDate, java.util.Date endDate) {
java.util.Date begin = new Date(startDate.getTime());
java.util.LinkedList list = new java.util.LinkedList();
list.add(new Date(begin.getTime()));
java.util.Date end = new Date(endDate.getTime());
endDate.setTime(endDate.getTime() + 24*3600*1000);
Calendar cal = Calendar.getInstance();
cal.setTime(begin);
dbConnection = getDBConnection();
while(begin.compareTo(endDate)<0){
begin = new Date(begin.getTime() + 86400000);
list.add(new Date(begin.getTime()));
Timestamp timestamp = new Timestamp(new Date().getTime());
//For a single day calculation: 24hours*60mins=1440 /2 (2 mins time difference as per the requirement) = 720
for (int j = 0; j < 720; j++) {
cal.add(Calendar.MINUTE, 2);
timestamp = new Timestamp(cal.getTime().getTime());
String S = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
String[] parts = S.split(" ");
String date=parts[0];
String time=parts[1];
cal.getTime().toString();
// To create data loop into a List
List<String> records = new ArrayList<String>();
StringBuffer record = new StringBuffer();
for (int i = 1; i <= total; i++) {
records = new ArrayList<String>(total);
int a2 = 220 + j % 31; // 230 - 244 by 1
String wString = Integer.toString(a2);
String a = String.valueOf(a2);
double b2 = 0.00 + j % 3.7 ; // 1.3 - 3.9 by 0.1
String aString = Double.toString(b2);
String b = String.valueOf(b2);
b = b.substring(0, Math.min(b.length(), 5));
record.delete(0, record.length());
record.append(a + "," + b + ",'"+ date + "', '"+ time + "'");
record.append("\t\t");
record.append("\n");
records.add(record.toString());
//Insert Query
String insertTableSQL = "INSERT INTO cmd1"
+ "(a, b, date, time) " + "VALUES"
+ "("+record.toString()+")";
System.out.println("insertTableSQL - " + insertTableSQL); // Statement.executeUpdate(insertTableSQL);
try {
statement = dbConnection.createStatement();
statement.executeUpdate(insertTableSQL);
System.out.println("Record is inserted into Db table!");
} catch (SQLException e) {
System.out.println(e.getMessage());
}
try {
// dbConnection = getDBConnection();
statement = dbConnection.createStatement();
statement.executeUpdate(insertTableSQL);
System.out.println("Record is inserted into Db table!");
} catch (SQLException e) {
System.out.println(e.getMessage());
}
finally {
// httpPost.releaseConnection()
try{
if(statement!=null)
statement.close();
}
finally{
}
try{
if(dbConnection!=null)
dbConnection.close();
}
finally{
}
}
}
}
}
return list;
}
#SuppressWarnings("unused")
public static void main(String[] args) throws Exception {
//To enter startDate and enddate
// EntityManagerFactory.getCache().evictAll;
SimpleDateFormat startDate=new java.text.SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat endDate=new java.text.SimpleDateFormat("yyyy-MM-dd");
java.util.LinkedList hitList = searchBetweenDates(
startDate.parse("2016-01-01"),
endDate.parse("2016-03-01"));
String[] combo = new String[hitList.size()];
for(int i=0; i<hitList.size(); i++)
combo[i] = new java.text.SimpleDateFormat("yyyy-MM-dd").format(((java.util.Date)hitList.get(i)));
}
private static void insertRecordIntodb() {
//
}
private static Connection getDBConnection() {
Connection dbConnection = null;
try {
Class.forName(DB_DRIVER);
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
try {
dbConnection = DriverManager.getConnection(DB_CONNECTION, DB_USER, DB_PASSWORD);
return dbConnection;
} catch (SQLException e) {
System.out.println(e.getMessage());
}
return dbConnection;
}
}
Server connection failure during transaction. Due to underlying exception: 'java.net.SocketException: java.net.SocketException: No buffer space available (maximum connections reached?): connect'.
** BEGIN NESTED EXCEPTION **
java.net.SocketException
MESSAGE: java.net.SocketException: No buffer space available (maximum connections reached?): connect
STACKTRACE:
java.net.SocketException: java.net.SocketException: No buffer space available (maximum connections reached?): connect
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:156)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:276)
at com.mysql.jdbc.Connection.createNewIO(Connection.java:2717)
at com.mysql.jdbc.Connection.<init>(Connection.java:1509)
at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:266)
at java.sql.DriverManager.getConnection(Unknown Source)
at java.sql.DriverManager.getConnection(Unknown Source)
at Simple.CurrentProg.getDBConnection(CurrentProg.java:186)
at Simple.CurrentProg.searchBetweenDates(CurrentProg.java:126)
at Simple.CurrentProg.main(CurrentProg.java:164)
** END NESTED EXCEPTION **
Attempted reconnect 3 times. Giving up.
Exception in thread "main" java.lang.NullPointerException
at Simple.CurrentProg.searchBetweenDates(CurrentProg.java:137)
at Simple.CurrentProg.main(CurrentProg.java:164)
Here I am trying to connect java program with database but when i am trying to insert large data say for 1 month so its only fetching 16000 records not more than that i want the data should be inserted as per the given date range what should i do to get that . In stacktrace its showing an exception as no buffer space available maximum connection reached. Thanks In advance
Here is the modified code. I removed a lot of code which is not necessary:
public static LinkedList<Date> searchBetweenDates(Date startDate, Date endDate) throws SQLException {
Date begin = new Date(startDate.getTime());
LinkedList<Date> list = new LinkedList<Date>();
list.add(new Date(begin.getTime()));
endDate.setTime(endDate.getTime() + 24 * 3600 * 1000);
Calendar cal = Calendar.getInstance();
cal.setTime(begin);
dbConnection = getDBConnection();
PreparedStatement ps = dbConnection.prepareStatement("INSERT INTO cmd1(aaaa, bbbb, datee, timee) VALUES(?, ?, ?, ?)");
while (begin.compareTo(endDate) < 0) {
begin = new Date(begin.getTime() + 86400000);
list.add(new Date(begin.getTime()));
Timestamp timestamp = new Timestamp(new Date().getTime());
// For a single day calculation: 24hours*60mins=1440 /2 (2 mins time
// difference as per the requirement) = 720
for (int j = 0; j < 720; j++) {
cal.add(Calendar.MINUTE, 2);
timestamp = new Timestamp(cal.getTime().getTime());
String S = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
String[] parts = S.split(" ");
String date = parts[0];
String time = parts[1];
cal.getTime().toString();
// To create data loop into a List
for (int i = 1; i <= total; i++) {
int a2 = 220 + j % 31; // 230 - 244 by 1
String a = String.valueOf(a2);
double b2 = 0.00 + j % 3.7; // 1.3 - 3.9 by 0.1
String b = String.valueOf(b2);
b = b.substring(0, Math.min(b.length(), 5));
ps.setString(1, a);
ps.setString(2, b);
ps.setString(3, date);
ps.setString(4, time);
ps.execute();
}
}
}
if (ps != null)
ps.close();
if (dbConnection != null)
dbConnection.close();
return list;
}
What I changed:
I removed your try/catch's because I wanted to make the code short so that I can edit it here easily. But you should handle exception correctly. And don't swallow exceptions ever. I mean the following is no go:
} catch (SQLException e) {
System.out.println(e.getMessage());
}
It is very bad Idea because you'll not see the real cause of the problem in this case; at least do e.printStackTrace() eventhough it is not recommended in a real project.
I exchanged the Statement object for PreparedStatement because it is much more efficient.
Removed package names and put import statements instead because it is not necessary to do so unless you have different classes from different packages with the same name.
I changed column names because my DB does not want to accept them. Column names like a are very bad. Choose instead descriptive names so that you might understand what it is for a couple of months later. Don't use column names like date because they are reserved words for some databases systems I know.
Don't create database resources like Connection in a loop unless it is absolutely needed! Otherwise, your program will go out of resources because these resources are very expensive! That is exactly what you are experiencing right now.
Hope it helps, otherwise, drop me a comment.
This is the code:
import java.util.*;
import java.io.*;
import java.net.*;
import java.sql.*;
import java.io.Console;
class SynchList {
ArrayList<PrintStream> it;
SynchList() {
it = new ArrayList<PrintStream>();
}
synchronized PrintStream get(int i) {
return it.get(i);
}
synchronized void add(PrintStream o) {
it.add(o);
}
synchronized int size() {
return it.size();
}
synchronized void remove(PrintStream o) {
it.remove(o);
}
}
class StringBroadcaster {
static SynchList Outputs = new SynchList();
static int i = 0;
public static void main(String[] args) throws Exception {
String message;
//Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
//Database password
Console cons;
char[] passwd;
String pass = "";
if ((cons = System.console()) != null &&
(passwd = cons.readPassword("%s", "Password:")) != null) {
for (int i = 0; i < passwd.length; i++) pass += passwd[i];
}
//Open a connection
Connection connect = DriverManager.getConnection("jdbc:mysql://igor.gold.ac.uk/ma203mk", "ma203mk", pass);
//Execute a query to create a statement with required arguments
Statement st = connect.createStatement();
int resultSet = st.executeUpdate(SQLquery);
//Execute a query
SQLquery = "INSERT INTO one (Port,Name,Message) VALUES('a','hello','hii')";
VALUES(1, 'hello', 'muhsina') ");
int port = Integer.parseInt(args[0]);
ServerSocket s = new ServerSocket(port);
Transaction k;
while (true) {
k = new Transaction(Outputs.size(), s.accept(), Outputs);
k.start();
System.out.println("Client Joined");
}//wait for client to connect
}
}//End of Main
class Transaction extends Thread {
SynchList outputs;
public int n;
Socket t;
InputStream b;
OutputStream p;
PrintStream pp;
public String name;
public Transaction(int i, Socket s, SynchList v) throws Exception {
outputs = v;
n = i;
t = s;
b = t.getInputStream();
p = t.getOutputStream();
pp = new PrintStream(p);
outputs.add(pp);
}
public void run() {
Scanner s = new Scanner(b);
name = s.next();
int c;
try {
while (s.hasNext()) {
String it = s.nextLine();
for (int j = 0; j < outputs.size(); j++) {
{
(outputs.get(j)).println(name + ": " + it);
(outputs.get(j)).flush();
}
}
System.out.println(name + ": " + it);
}
System.out.print("Client " + n + " " + name + " left the conversation");
outputs.remove(pp);
} catch (Exception e) {
outputs.remove(pp);
System.out.print(e);
}
}
}
I keep getting this error for the following code, can anyone help?
G:\StringBroadcaster.java:57: error: cannot find symbol
int resultSet = st.executeUpdate(SQLquery);
^
symbol: variable SQLquery
location: class StringBroadcaster
G:\StringBroadcaster.java:63: error: cannot find symbol
SQLquery = "INSERT INTO one (Port,Name,Message) VALUES('a','hello','muhsina')";
^
symbol: variable SQLquery
location: class StringBroadcaster
2 errors
Tool completed with exit code 1)
Thanks.
You have executed the line
int resultSet = st.executeUpdate(SQLquery);
before define the value of variable SQLquery.
You haven't declared a type for your SQLQuery variable (also variables conventionally start with a lowercase letter to distinguish them from class names). So the line below // Execute a query should read:
String SQLquery = "INSERT INTO one (Port,Name,Message) VALUES('a','hello','hii')";
Additionally:
You have a line after this, VALUES(1,'hello','muhsina')");, which is just completely illegal syntax. I'm guessing this was an accidental copy-paste error.
You're using the query variable before you declare it, as others have pointed out. You need to move the st.executeUpdate() call after the point where the query is declared.
I try to generate random code name as licenseKey and check whether it is exist in database or not. If not exist, then display in my jsp page, if exist, continue generating the random code. I got the error "java.lang.StackOverflowError". How to solve this? Below is my code :
package com.raydar.hospital;
import com.raydar.hospital.DB_Connection;
import java.sql.*;
public class RandomCodeGenerator {
String licenseKey = "";
int noOfCAPSAlpha = 4;
int noOfDigits = 4;
int minLen = 8;
int maxLen = 8;
char[] code = RandomCode.generateCode(minLen, maxLen, noOfCAPSAlpha, noOfDigits);
public RandomCodeGenerator(){
}
public String getOutputCode() throws Exception{
String result ="";
result = isLicenseKeyExist();
System.out.println("4 + " +result);
if (result=="false"){
System.out.println("1 + " +new String(code));
licenseKey = new String(code);
}
else if (result=="true"){
System.out.println("2 + " +new String(code));
licenseKey = new String(code);
isLicenseKeyExist ();
}
return licenseKey;
}
private String isLicenseKeyExist () throws Exception{
String code = "";
code = getOutputCode();
Connection connection = null;
Statement statement = null;
ResultSet rs = null;
String result="";
System.out.println("3 + " +code);
try{
DB_Connection connect = new DB_Connection();
connection = connect.getDBConnection();
statement = connection.createStatement();
rs = statement.executeQuery("SELECT licenseKey FROM hospital WHERE licenseKey = '" +code+ "'");
if (rs.next()){
result = "true";
}
else{
result = "false";
}
}catch (Exception e){
System.out.println("Error retrieving data! "+e);
}
return result;
}
}
You create a recursive loop where isLicenseKeyExist() calls getOutputCode(), but then getOutputCode() calls isLicenseKeyExist(). So eventually you run out of stack space, and get this exception.
Here,
public String getOutputCode() throws Exception{
String result ="";
result = isLicenseKeyExist();
...
}
private String isLicenseKeyExist () throws Exception{
String code = "";
code = getOutputCode();
...
}
I think you want something like this. Remove the field called code from your class, and its initialiser, and put the call to RandomCode.generateCode inside your getOutputCode method like this. The reason is that you'll have to call it repeatedly if your code is already in the database.
public String getOutputCode() throws SQLException {
String code;
do {
code = new String(RandomCode.generateCode(minLen, maxLen, noOfCAPSAlpha, noOfDigits));
}
while(licenceKeyExists(code));
return code;
}
private boolean licenceKeyExists(String code) throws SQLException {
try{
DB_Connection connect = new DB_Connection();
connection = connect.getDBConnection();
statement = connection.createStatement();
rs = statement.executeQuery("SELECT licenseKey FROM hospital WHERE licenseKey = '" +code+ "'");
return rs.next();
}
finally {
try {
connection.close();
} catch (SQLException ignored){}
}
}
#aween - #captureSteve has answered the first part of the question .
So, straight to "I wan't to call this function" comment. See, if I
understand your question correctly, you want to generate a key, and
check if it is available in the DB using isLicenseKeyExist() . In such
case, why don't you create the key first, then pass it to the
isLicenseKeyExist(). Then this function will return true/false based
on which you can decide what to do.
I'm attempting to fix a plugin I wrote a long time ago for Craftbukkit, but I'm stumped on one section. I've searched Google with little luck, and I've asked other Java developers only to hear that I shouldn't be using a for loop because it's rather basic, or that I'm using a boolean expression in the wrong place. Nobody will tell me how I can fix this, so I'll know for future references - Below is the class that throws the error:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.logging.Logger;
import org.bukkit.configuration.file.FileConfiguration;
public class Database
{
private static String host = null;
private static String port = null;
private static String database = null;
private static String table = null;
private static String username = null;
private static String password = null;
private static String colUsername = null;
private static Logger logger = null;
public static void init(FileConfiguration config, Logger log)
{
logger = log;
host = config.getString("DBHost");
port = config.getString("DBPort");
database = config.getString("DBName");
table = config.getString("DBTable");
username = config.getString("DBUser");
password = config.getString("DBPass");
colUsername = config.getString("ColUsername");
}
public static Hashtable<String, Object> getUserInfo(String user)
{
String url = "jdbc:mysql://" + host + ":" + port + "/" + database;
String query = "SELECT * FROM " + table + " WHERE " + colUsername + " = ?";
Connection connect = null;
PreparedStatement stmt = null;
ResultSet result = null;
Hashtable<String, Object> userInfo = new Hashtable<String, Object>();
try
{
Class.forName("com.mysql.jdbc.Driver");
connect = DriverManager.getConnection(url, username, password);
stmt = connect.prepareStatement(query);
stmt.setString(1, user);
result = stmt.executeQuery();
ResultSetMetaData rsmd;
int i;
for (; result.next(); i <= rsmd.getColumnCount())
{
rsmd = result.getMetaData();
i = 1; continue;
userInfo.put(rsmd.getColumnName(i), result.getObject(i));i++;
}
return userInfo;
}
catch (ClassNotFoundException e)
{
logger.warning("Unable to load driver. Using default behaviour.");
e.printStackTrace();
}
catch (SQLException e)
{
logger.warning("Database error. Using default behaviour.");
e.printStackTrace();
}
finally
{
if (result != null) {
try
{
result.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (stmt != null) {
try
{
stmt.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
if (connect != null) {
try
{
connect.close();
}
catch (SQLException e)
{
e.printStackTrace();
}
}
}
return null;
}
}
The error I encounter is in this part of the code:
for (; result.next(); i <= rsmd.getColumnCount())
{
rsmd = result.getMetaData();
i = 1; continue;
userInfo.put(rsmd.getColumnName(i), result.getObject(i));i++;
}
Where I get the error "Syntax error on token "<=", invalid AssignmentOperator"
How should I go about fixing this, and how can I improve it?
EDIT #1:
This is my updated code, according to Jon's answer:
try
{
Class.forName("com.mysql.jdbc.Driver");
connect = DriverManager.getConnection(url, username, password);
stmt = connect.prepareStatement(query);
stmt.setString(1, user);
result = stmt.executeQuery();
ResultSetMetaData rsmd = result.getMetaData();
while (result.next()) {
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
rsmd = result.getMetaData();
userInfo.put(rsmd.getColumnName(i), result.getObject(i));i++;
}
}
return userInfo;
}
Basically this is the wrong way round:
for (; result.next(); i <= rsmd.getColumnCount())
It should possibly be:
for (; i <= rsmd.getColumnCount(); result.next())
Although more likely, you actually want:
while (result.next()) {
// This outer loop is executed once per row
for (int i = 1; i <= rsmd.getColumnCount(); i++) {
// This inner loop is executed once per column (per row, as it's
// within the outer loop)
}
}
Having said that, you're not even initializing rsmd, which doesn't help. I suspect you may want to call ResultSet.getMetadata(), e.g.
rsmd = result.getMetadata();
For reference, the three parts of the for statement declaration are as follows:
The first part (empty in your case) is performed once, as initialization
The second part is a condition to check on each iteration; the loop ends when the condition evaluates to false
The third part is a statement is a step to take at the end of each iteration
See section 14.14.1 of the JLS or the for statement part of the Java tutorial for more details.
This won't work in the last part of a for loop:
i <= rsmd.getColumnCount()
Perhaps you meant this?
for (; i <= rsmd.getColumnCount(); result.next())
Basic syntax of a for-loop:
for (any; boolean; any)
your's is
for (any; any; boolean)
Just change the order.