I have a class that contains methods that connect to a database, run a query, and assigns data from the database into variables.
The purpose of this Java program is to scan a database that houses information on security threats for client's servers. When the query is run it should return selected data fields from 2 tables (target_stats and attack_stats) upon reading that the number of attacks (target_stats.num_attacks) is above 0.
I can successfully retrieve data from the target table but I get null values from the attacker table and I know that the field is not null in the database.
My question: can anyone detect an error, most likely a logical one, in my query that is causing the unfavorable results? I am a beginner programmer and fairly new to SQL.
Also, I am in the process of learning setters and getters in this program, all of the retrieved data is to be used in another class but I am testing and learning with just the target field for now. Perhaps that is causing an issue?
UPDATE I rant he query in MySQL query browser and get the same unfavorable result, so the problem is just in my query logic. I have done some research in queries and joins but must still be lacking suitable knowledge.
My code (hopefully I post it correctly in format):
public class Database {
String details = null;
int threat_level = 0;
ResultSet rslt = null;
private String target2;
Connection con;
public void createConnection() {
//Establish a connection
try {
con = DriverManager.getConnection("sensitiveInformation");
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("Database connected");
}
public ResultSet getData() {
String query = "SELECT target_stats.server_id, target_stats.target, target_stats.threat_level, target_stats.client_id, attack_stats.attacker, attack_stats.num_this_attack " +
" FROM target_stats " +
" LEFT OUTER JOIN attack_stats " +
" ON target_stats.target = attack_stats.target " +
" WHERE target_stats.num_attacks > '0' " +
" AND target_stats.interval_id>'2'";
Statement stmt = null;
try {
stmt = con.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
try {
rslt = stmt.executeQuery(query);
} catch (SQLException e) {
e.printStackTrace();
}
return rslt;
}
public void process() {
try {
String server_id = rslt.getString("server_id");
target2 = rslt.getString("target");
threat_level = rslt.getInt("threat_level");
int client_id = rslt.getInt("client_id");
String attacker = rslt.getString("attacker");
String num_this_attack = rslt.getString("num_this_attack");
details = "Target IP: " + target2 + " Server ID: " + server_id + " Client ID: " + client_id + " Threat Level: " + threat_level + " Attacker IP: " + attacker + " Number of attacks: " + num_this_attack;
System.out.println(details);
} catch (SQLException e) {
e.printStackTrace();
}
}
public String getTraget2() {
return target2;
}
}
Update: I should mention that I have a while loop in another class that properly reads through each record.
Update 2: Here is the main class, I am not concerned with the GUI elements right now:
public class MainDisplay extends JFrame {
static Toolkit tk = Toolkit.getDefaultToolkit();
static int Width = (int)tk.getScreenSize().getWidth();
static int Height = (int)tk.getScreenSize().getHeight();
public static JFrame frame = new JFrame();
public static JLayeredPane lpane = new JLayeredPane();
public static String target;
public static void main (String[] args) {
new MainDisplay();
}
public MainDisplay() {
frame.setPreferredSize(new Dimension(Width, Height));
frame.setLocation(0,0);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
//NoRisk Run = new NoRisk();
//Run.NoThreat();
ThreatPanel Run = new ThreatPanel();
Database Data = new Database();
//Create Connection to Database and run query
Data.createConnection();
Data.getData();
try {
while(Data.rslt.next()){
Data.process();
Run.TargetServer = Data.getTraget2();
System.out.print(Data.getTraget2()); //for testing purposes
Run.ShowThreats();
try {
Thread.sleep(1000*10); // sleeps for ten seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
//Run.ShowThreats();
frame.setLayout(new BorderLayout());
frame.add(lpane, BorderLayout.CENTER);
lpane.setBounds(0,0, Width, Height);
frame.pack();
frame.setVisible(true);
}
}
Did you try to execute the same query in database? You mentioned it should return some results but did you try it in database before putting in the codes? If the database is not returning the desirable result, we will look into the query statement, for example instead of left outer join you might have to use inner join.
The field in attacker table may be not null, but when you have LEFT OUTER JOIN - you will have null values in a query when there is no corresponding data in attack_stats table - please check that.
The query looks ok - try with LEFT INNER JOIN - then you will have no rows visible where there are no corresponding data in attack_stats table.
Pat, Can you post your main method, from where you are calling this code. Also you should iterate over resultset to move the cursors.
while(rslt.next())
{
String server_id = rslt.getString("server_id");
target2 = rslt.getString("target");
threat_level = rslt.getInt("threat_level");
int client_id = rslt.getInt("client_id");
String attacker = rslt.getString("attacker");
String num_this_attack = rslt.getString("num_this_attack");
details = "Target IP: " + target2 + " Server ID: " + server_id + " Client ID: " + client_id + " Threat Level: " + threat_level + " Attacker IP: " + attacker + " Number of attacks: " + num_this_attack;
System.out.println(details);
}
Related
I have a problem with a really slow connection between my Java code and a MySQL remote Database when i use multiple query.
This is my code
ArrayList<Server_Log> ar =Server_Log_Utilities.getBy2Dates(cmb_date.getSelectedItem() + "", cmb_date2.getSelectedItem() + "");
for (int c = 0; c < ar.size(); c++) {
Server_Log sl = ar.get(c);
String username = User_Utilities.getUserName(sl.getUser() + "");
String row[] = {sl.getDate(), sl.getTime(), username, sl.getReff(), sl.getDescription()};
}
but I user this code data will load fast
ArrayList<Server_Log> ar =Server_Log_Utilities.getBy2Dates(cmb_date.getSelectedItem() + "", cmb_date2.getSelectedItem() + "");
for (int c = 0; c < ar.size(); c++) {
Server_Log sl = ar.get(c);
String row[] = {sl.getDate(), sl.getTime(), sl.getReff(), sl.getDescription()};
}
this is User_Utilities.getUserName(sl.getUser() + ""); Method
public static String getUserName(String id) {
String UserName="";
try {
Connection con = new DBCon().getConnection();
ResultSet rst = DBHandle.getData(con, "SELECT username FROM user WHERE id='" + id + "'");
while (rst.next()) {
UserName =rst.getString(1);
}
con.close();
} catch (Exception ex) {
Logger.getLogger(User_Utilities.class.getName()).log(Level.SEVERE, null, ex);
}
return UserName;
}
Server_Log_Utilities.getBy2Dates(cmb_date.getSelectedItem() + "",
cmb_date2.getSelectedItem() + ""); Method
public static ArrayList getBy2Dates(String date1, String date2) {
try {
ar = new ArrayList<>();
Connection con = new DBCon().getConnection();
ResultSet rst = DBHandle.getData(con, "SELECT * FROM server_log WHERE date BETWEEN '" + date1 + "' AND '" + date2 + "' ORDER BY `date`");
while (rst.next()) {
Server_Log ci = new Server_Log();
ci.setId(rst.getInt(1));
ci.setDate(rst.getString(2));
ci.setTime(rst.getString(3));
ci.setReff(rst.getString(4));
ci.setDescription(rst.getString(5));
ci.setUser(rst.getInt(6));
ar.add(ci);
}
con.close();
} catch (Exception ex) {
Logger.getLogger(Student_Utilities.class.getName()).log(Level.SEVERE, null, ex);
}
return ar;
}
When accessing a remote database, especially over a slow link, the number of SQL statements executed is very important.
This is why the JDBC API support concepts like statement batching.
In your case, you're calling getUserName for every record in ar. Consider ways to reduce the number of calls.
Example 1: If user is usually the same, or only a few users are generating log entries, caching the user names would eliminate redundant lookup.
Example 2: Rather than looking up the user in the client, modify the Server_Log_Utilities.getBy2Dates to add a JOIN to the User table. This way, no extra turn-arounds to database will be needed.
Example 3: Instead of calling getUserName individually in a loop, collect the user ids, and lookup the names in a batch. Use either a JDBC batch of multiple SELECT statements, or use a single statement with UserId IN (?,?,?,?,...).
hi I am getting this error in my Java program. Here is my query. It is working good in SQL server. but getting
Error: Incorrect syntax near 'WebApp'.
private static final String SERVICES =
"SELECT s.Service_ID "
+ ",s.[Location_ID] "
+ ",COALESCE(st.[Service_Type_Name],s.[Service_Name]) AS Service_name "
+ ",st.Service_Type_Name "
+ " FROM [WebApp].[dbo].[Services] s join [WebApp].[dbo].[ServiceTypes] st on s.Service_Type=st.Service_Type_ID "
+ " join WebApp.dbo.Locations l on s.Location_ID=l.Location_ID "
+ " where s.Deleted=0 "
+ " ORDER BY Location_ID ";
and here is my method it is working fine on ms sql server 2008
public List<MAServiceVO> getAddServices() throws CoopCRSAPIException {
ArrayList<MAServiceVO> results = new ArrayList<MAServiceVO>();
MAServiceVO maServiceVO = null;
log.debug("==========IN VendorDAOimpl.java (service)===========");
//int serviceID = 0;
//int prevServiceID = 0;
try {
conn = MSSQLDAOFactory.createConnection();
stmt = conn.prepareStatement(SERVICES);
// stmt.setTimestamp(1, startDate);
// stmt.setTimestamp(2, endDate);
stmt.execute();
rs = stmt.getResultSet();
while (rs.next()) {
// create new service
maServiceVO = new MAServiceVO();
// set service fields
maServiceVO.setServiceID(rs.getInt("Service_ID"));
maServiceVO.setLocationID(rs.getInt("Location_ID"));
maServiceVO.setServiceName(rs.getString("Service_Name"));
maServiceVO.setServiceType(rs.getString("Service_Type_Name"));
log.debug("==========done with VendorDAOimpl.java (service)===========");
}
} catch (SQLException e) {
log.debug(e.getMessage());
throw new CoopCRSAPIException(e.getMessage(), " VendorDAOimpl", "getAddServices", 500);
} finally {
closeConnections("getAddServices");
}
log.debug("&&&&&&&&&&&&&&&&&&&&&");
log.debug("==========finsh===========");
return results;
}
I don't see anything out of whack there. If there a reason you don't have this in a stored procedure instead of pass through sql? I did notice you didn't put square brackets around your final join but that shouldn't make any difference.
Here is your query after stripping off all the extra string parts for java.
SELECT s.Service_ID
, s.[Location_ID]
, COALESCE(st.[Service_Type_Name], s.[Service_Name]) AS Service_name
, st.Service_Type_Name
FROM [WebApp].[dbo].[Services] s
join [WebApp].[dbo].[ServiceTypes] st on s.Service_Type = st.Service_Type_ID
join [WebApp].[dbo].[Locations] l on s.Location_ID = l.Location_ID
where s.Deleted = 0
ORDER BY Location_ID;
I'm doing an app for school project and I came across this error I've tried to figure it out but I can't seem to fix it.
Let me explain the problem first, basically I'm trying to update previously created user. Initially the profile has only username and a password. I want the user to be able to add whatever details he wishes to later on once he has created his own profile.
I have one class which has the database connectivity and update Profile method. The other class is a jFrame where user can input some data into textfields and the intention is that it will be inserted into fields for existing profile within the database (Initially those fields are declared as null).
Below you can see my DBConnect class which contain the Login method and UpdateProfile method. In the login method I'm creating a profile object which holds all the variables and methods such as getUsername, getPassword etc.
public class DBConnect {
private Connection dbConnection;
public Profile profile;
public DBConnect() {
try {
dbConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/prototype?user=root");
} catch (Exception ex) {
System.out.println("Connection failed :" + ex);
}
}
public void Login() {
profile = new Profile(LoginWindow.usernameField.getText(), LoginWindow.passwordField.getText());
Statement userQuery = null;
try {
//Look for the user with valid username and password
userQuery = dbConnection.createStatement();
ResultSet rs = userQuery.executeQuery("Select * FROM Profile WHERE pName = \"" + profile.getUsername() + "\" and password = \"" + profile.getPassword() + "\"");
if (rs.next()) {
profile.isLoggedin(true);
} else {
profile.isLoggedin(false);
}
} catch (SQLException ex) {
profile.isLoggedin(false);
System.out.println(ex);
} finally {
try {
if (userQuery != null) {
userQuery.close();
}
} catch (SQLException ex) {
System.out.println("Failed to close login query");
}
}
}
public void updateProfile(String _height, String _weight, String _goalWeight, String _age) {
Statement updateQuery = null;
try {
updateQuery = dbConnection.createStatement();
updateQuery.executeUpdate("UPDATE Profile SET height='" + _height + "',weight='" + _weight + "',goalWeight='" + _goalWeight + "',age='" + _age + "' WHERE pName =" + profile.getUsername());
} catch (SQLException ex) {
System.out.println(ex);
} finally {
try {
if (updateQuery != null) {
updateQuery.close();
}
} catch (SQLException ex) {
System.out.println("Failed to close updateCustomer query");
}
}
}
}
I'm trying to update some of the fields that were empty with the Update Profile method and to get the profile that I want to update I wrote "WHERE pName =" + profile.getUsername());" in order to retrieve the record of the user.
Finally in the EditProfile jFrame I wrote this method to pass on the parameters for the updateProfile methods.
private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {
LoginWindow.dbc.updateProfile(heightTextField.getText(), weightTextField.getText(), goalWeightTextField.getText(), ageTextField.getText());
}
Everything compiles but I'm having mySQLSyntaxError which is:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Admin' in 'where clause'
The database is not updated and I don't know how to fix it.
My assumptions is that there is a problem with "WHERE pName =" + profile.getUsername());" in updateProfile declaration. The "Admin" is the result of profile.getUsername(); and its the actual username of currently logged in user.
Please help.
You have a little syntax error: Your line
updateQuery.executeUpdate("UPDATE Profile SET height='" + _height + "',weight='" + _weight + "',goalWeight='" + _goalWeight + "',age='" + _age + "' WHERE pName =" + profile.getUsername());
should read
updateQuery.executeUpdate("UPDATE Profile SET height='" + _height + "',weight='" + _weight + "',goalWeight='" + _goalWeight + "',age='" + _age + "' WHERE pName ='" + profile.getUsername()) + "'";
(You need to enclose the pName parameter with single quotes.)
...and you really need to start using PreparedStatement as others also suggested.
that exactly the problem. try that:
ResultSet rs = userQuery.executeQuery("Select * FROM Profile WHERE pName = '" + profile.getUsername() + "' and password = '" + profile.getPassword() + "' ");
I have a SQL query, consisting of different statements (this is a simplified version, which also triggers the error) :
private static String getActiveKeyEventsSql =
"SET #report_model_id = 2; " +
"SELECT MAX(report_ts) AS report_ts " +
"FROM `pulse_data`.`key_event_reports` " +
"WHERE report_model_id = #report_model_id ";
I am trying to call that statement from inside my Java Application:
public static void main(String[] args) throws Exception {
MySQLLayer _db = new MySQLLayer();
Connection _conn = null;
try {
_conn = _db.getConnection();
PreparedStatement getActiveKeyEventsStmt = _conn.prepareStatement(getActiveKeyEventsSql);
ResultSet rs = getActiveKeyEventsStmt.executeQuery();
while (rs.next()) {
LOG.info(rs.getLong("report_ts"));
}
} catch (SQLException e) {
LOG.error("COULD NOT GET MAX REPORT.", e);
} finally {
try {
if (_conn != null && !_conn.isClosed()) {
_conn.close();
}
} catch (SQLException e) {
LOG.info("COULD NOT CLOSE CONNECTION.", e);
}
}
}
But it triggers the following error:
java.sql.SQLException: ResultSet is from UPDATE. No Data.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:6870)
at com.stockpulse.stockstorm.sentiment.JavaTest.main(JavaTest.java:36)
In other places of my application, this schema works just fine. When I copy this statement to the MySQL console, it works just fine.
Here is the String to init the DB:
config.setJdbcUrl(
"jdbc:mysql://" + cred.getHOST() + "/" + cred.getDB()
+ "?allowMultiQueries=true&characterEncoding=utf-8&useUnicode=true&rewriteBatchedStatements=true&relaxAutoCommit=true"
);
Why is JDBC behaving this way out of the sudden?
Try breaking your statement into
a = "SET #report_model_id = 2; ";
b = "SELECT MAX(report_ts) AS report_ts " +
"FROM `pulse_data`.`key_event_reports` " +
"WHERE report_model_id = #report_model_id ";
And do PreparedStatement.addBatch() for each.
My question is not related to how to do something, it's more of how to help improve performance. I apologize for the long post, but I thought since this is about performance, that i should post all details about what I'm doing to see if anyone can help.
I have to make a program that gets info from 2 different databases, creates a metadata, its corresponding BLOB(pdf file) and zips it.
The metadata file is only created if the BLOB object was found in the database. I have managed to do so, but problem is sometimes I might have up to 80k results on my query and it may take as long as 20 hours to do so, which is ridiculous considering each blob object is no larger than 100 KB.
I have a transactional database (lets call it TEQ8P) where all the ID's and the info for the metadata is stored. I queried the data by date and status (which sucks but i don't have any other filter, that was the requirement)
TEQ8P.openConnection();
Boolean flag = TEQ8P.ExecuteQuery("select tr.legaltransnumber, cc.country_code, tr.transnumber, tr.postingdate, tr.transdate from EQUATE.transheader tr inner join companycode_country cc on tr.tocompanycode = cc.company_code where tr.transtype = 'IC' and tr.transdate between to_date(" + date + ", 'DD/MM/YYYY') and to_date(" + nextday + ", 'DD/MM /YYYY')");
public Boolean ExecuteQuery(String query) {
Statement stmt;
ResultSet rs = null;
try {
stmt = connection.createStatement();
rs = stmt.executeQuery(query);
if(!rs.isBeforeFirst())
return false;
rowset = new CachedRowSetImpl();
rowset.populate(rs);
metadata = rs.getMetaData();
rs.close();
stmt.close();
return true;
} catch (SQLException e) {
HLog.error(e.getMessage());
e.printStackTrace();
return false;
//System.out.println(query);
}
finally
{
closeConnection();
}
}
I am using JAVA 1.5 (per requirement again) so I downloaded the cachedrowsetimp jar from oracle, so once I finish querying data I save it to memory and close the connection.
After that I start moving through the cachedrowset and query every ID on the Warehouse DB. I can't do a select "where in" because there is no way to tell if all id's will be found and an "in" would only return the items that it finds, and I wouldn't know which items it didn't find. But if you have any suggestion please!
So I use preparedStatement to use bind variables on ORACLE and start writing the blob object.
My first question, is there a better way to write blob files? A faster way?
if(flag)
{
String Query = "select wh.transnumber, wh.image from EQUATEWH.legalimage wh where wh.transnumber = ?";
WEQ8I.openConnection();
WEQ8I.setPreparedStmt(Query);
WEQ8I.WriteBlobs(PDF, TEQ8P.getRowsSet(), IC_FILE);
WEQ8I.closePrepStmt();
WEQ8I.closeConnection();
FileUtils.createZip(prop.getProperty("ZIPDIR_IC"), lsize, prop.getProperty("ZIPNAME_IC"));
public void WriteBlobs(String path, CachedRowSetImpl set, IMP_File IC_FILE)
{
ResultSet rs = null;
try
{
while(set.next())
{
pstmt.setString(1, set.getString(3));
rs = pstmt.executeQuery();
if(!rs.isBeforeFirst())
{
System.out.println("invoice " + set.getString(3) + "was not found on W database");
ErrorFile.writeErrorFile(set.getString(3));
}
else
{
//getting the name of the PDF file, if no ID use legaltransnumber
String ID = set.getString(1);
if(ID == null)
{
ID = set.getString(3);
}
while(rs.next())
{
FileOutputStream fos = null;
try
{
Blob blob = rs.getBlob(2);
InputStream is = blob.getBinaryStream();
fos = new FileOutputStream(path + ID + ".pdf");
int i = 0;
while ((i = is.read()) != -1)
{
fos.write(i);
}
fos.close();
is.close();
IC_FILE.fillIMPFile("IC", ID, set.getString(3), set.getString(2), set.getString(5));
}catch (Exception e)
{
e.printStackTrace();
ErrorFile.writeErrorFile(set.getString(3));
}
}
}
rs.close();
}
IC_FILE.writeFile();
} catch (SQLException e)
{
System.out.println("Problem when trying to create Record: " + path);
HLog.error(e.getMessage());
e.printStackTrace();
try
{
ErrorFile.writeErrorFile(set.getString(3));
}catch (Exception ex)
{
ex.printStackTrace();
HLog.error(e.getMessage());
}
}
}
If the query found a result for that ID on the WarehouseDB AND the image is not null (meaning it won't go to the null exception), I create the metadafile which is the IC_FILE.
the IC_FILE does not write a file, it saves everything into memory and when it finishes it writes the file, I thought this could help improve performance since it wouldn't have to do I/O operations on every file, just once, using IC_FILE.writefile().
To create the metadatafile, I also have to (per requirement again) get the container name from a file. to retrieve the container name I have to use 3 fields from the Transactional database, concatenate them and search for them in that file.
this is how I create the IMP file, first to get data from each record:
public void fillIMPFile(String type, String ID, String ID2, String companyCode, String date)
{
date = date.substring(0, 10);
date = date.replace("-", "/");
date = date.substring(5, 7) + "/" + date.substring(8, 10) + "/" + date.substring(0, 4);
String Name = prop.getProperty("NAME");
String info = prop.getProperty(type);
String DOS = Name + info + ID + ".";
String NOTES = Name + " " + info + " ";
info += getContainer(companyCode, date, type);
if(type.equals("IC"))
{
String desc = prop.getProperty("DESC_PDF");
DOS += "pdf";
NOTES += desc + " " + ID + " " + ID2;
buffer += info + "\t" + date + "\t" + date + "\t" + DOS + "\t" + NOTES + "\t"
+ NOTES + "\t" + ID2;
}
To get the containers I use the properties object, but I guess there might be better choices? a hash map maybe?
public String getContainer(String companyCode, String Date, String type)
{
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
Date = sdf.format(cal.getTime());
//mal siempre pondra 2012
String data = type + companyCode + Date;
String container = containers.getProperty(data);
if(container == null)
{
data = type + "WW" + Date;
container = containers.getProperty(data);
}
return container;
}
finaly to write the file:
public void writeFile()
{
try
{
FileWriter fw = new FileWriter(File, true);
BufferedWriter bw = new BufferedWriter(fw);
bw.write(buffer);
bw.close();
}catch (IOException e)
{
e.printStackTrace();
HLog.error(e.getMessage());
}
}
thanks!!
Daniel
fixed...using bind variables and creating more than 1 container file for each year