I've have tried to read about using static or not using static in my web application and wanted to just quickly ask if my implementation is good.
The following is my servlet
Integer total = HousingDAO.getTotal(AppUtils.getId(request));
Integer used = HousingDAO.getUsed(AppUtils.getId(request));
request.setAttribute("total", total);
request.setAttribute("used", used);
request.getRequestDispatcher("system/housing.jsp").forward(request, response);
And this is my DAO
public class HousingDAO {
public static Integer getTotal(String id){
String sql_total = "SELECT count(*) FROM housing " +
"WHERE id = :id ";
try (Connection con = ConnectionManager.getSql2o().open()) {
return con.createQuery(sql_total).addParameter("id", id).executeScalar(Integer.class);
}
}
public static Integer getUsed(String id){
String sql_total = "SELECT count(*) FROM housing " +
"WHERE id = :id AND person IS NOT NULL";
try (Connection con = ConnectionManager.getSql2o().open()) {
return con.createQuery(sql_total).addParameter("id", id).executeScalar(Integer.class);
}
}
}
So these are static, does it need to not be static, like this?
HousingDAO dao = new HousingDAO();
Integer total = dao.getTotal(AppUtils.getId(request));
Integer used = dao.getUsed(AppUtils.getId(request));
request.setAttribute("total", total);
request.setAttribute("used", used);
request.getRequestDispatcher("system/housing.jsp").forward(request, response);
With this DAO
public class HousingDAO {
public Integer getTotal(String id){
String sql_total = "SELECT count(*) FROM housing " +
"WHERE id = :id ";
try (Connection con = ConnectionManager.getSql2o().open()) {
return con.createQuery(sql_total).addParameter("id", id).executeScalar(Integer.class);
}
}
public Integer getUsed(String id){
String sql_total = "SELECT count(*) FROM housing " +
"WHERE id = :id AND person IS NOT NULL";
try (Connection con = ConnectionManager.getSql2o().open()) {
return con.createQuery(sql_total).addParameter("id", id).executeScalar(Integer.class);
}
}
}
Just would like to know if the first is ok, or do I need to do it like the second one?
EDIT
This is the ConnectionManager class
public static Sql2o getSql2o(){
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
return new Sql2o(PropertiesManager.getProperty("dburl")
+ PropertiesManager.getProperty("dbname"),
PropertiesManager.getProperty("dbusername"),
PropertiesManager.getProperty("dbpassword"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
There are rarely any good reasons for using static methods. It is most often used in utility classes and classes that in their nature are singletons, like javas System class.
In your case, having a DAO class with static methods is according to me a bad idea. If the methods are static anything they reference has to be static. What if you want to reuse your DAO class to connect to several different databases?
A better approach is to inject all your dependencies in your DAO class, like the static ConnectionManager, and let the application decide how instances are wired together, not the classes themselves.
So the short answer is, use the second solution, but also remove the static access to ConnectionManager.
Related
I am writing a program that acts as a service and picks up emails from the email queue table, processes them and sends them out. Here is something along how I did it, and it does work fine.
MySqlConnect con = new MySqlConnect();
public PreparedStatement preparedStatement = null;
public Connection con1 = con.connect();
//pick up queue and send email
public void email() throws Exception {
try {
while(true) {
String sql = "SELECT id,user,subject,recipient,content FROM emailqueue WHERE status='Pending' ";
PreparedStatement statement = con1.prepareStatement(sql);
ResultSet rs = statement.executeQuery();
while (rs.next()) {
String subject = rs.getString("subject");
String recipient = rs.getString("recipient");
String content = rs.getString("content");
String id = rs.getString("id");
String username = rs.getString("user");
String emailStatus = "DONE";
String errormsg = sendEmail(recipient, subject, content, id,username);
if (!errormsg.equals("")) {
emailStatus = "FAILED";
}
TerminalLogger.printMsg("Status : " + emailStatus);
}
statement.close();
rs.close();
}
} catch(Exception e) {
e.printStackTrace();
TerminalLogger.printMsg("Exception: "+e.toString());
}
con1.close();
Thread.sleep(2000);
}
Now, I am clearly using JDBC to obtain the result set in the loop and process them as shown. Of course, I also need to specify my database connection in MySqlConnect.java properties. While all this works perfectly fine, I was wondering is there another way of achieving the same goal without using JDBC, i.e. specifying the connection properties?
I was thinking of Java Persistence. I am new to this.
Edit
I have been told to use JPA to achieve this and I have written it in this way:
public void email() throws Exception {
try {
while(true) {
String sql = "select p.id,p.user,p.subject,p.recipient,p.content from Emailqueue p where " +
"status='Pending'";
List<Object[]> list = em.createQuery(sql).getResultList();
for (Object[] obj : list) {
System.out.println(obj[0]);
System.out.println(obj[1]);
System.out.println(obj[2]);
System.out.println(obj[3]);
System.out.println(obj[4]);
}
}
} catch(Exception e) {
e.printStackTrace();
TerminalLogger.printMsg("Exception: " + e.toString());
}
From here, I would pass the parameters I want to the method. Is this way feasible?
Edit 2
Did it a bit different like below:
String id = ejbCon.getSettingsFacade().getid();
String username = ejbCon.getSettingsFacade().getUser();
String subject = ejbCon.getSettingsFacade().getSubject();
String recipient = ejbCon.getSettingsFacade().getRecipient();
String content = ejbCon.getSettingsFacade().getContent();
String errormsg = sendEmail(recipient, subject, content, id,username);
public String getContent() {
try {
String sql="Select content FROM emailqueue WHERE status='Pending'";
if (em == null) {
throw new Exception("could not found subject");
}
return (String) em.createNativeQuery(sql).getSingleResult();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Just a bit idea of how the method looks like, the other methods follow the same concept.
List<EmailQueue> emailList = em.createQuery(sql).getResultList();
for (EmailQueue obj : emailList) {
String emailStatus = "DONE";
String errormsg=sendEmail(obj.getRecipient(), obj.getSubject, obj.getContent(),obj.getId(),obj.getUsername());
if (!errormsg.equals("")) {
emailStatus = "FAILED"
}
TerminalLogger.printMsg("Status : " + emailStatus);
}
}
Before using JPA ,you must read about it WHY JPA
As discussed in the comments above, Spring Batch and Spring JPA is a good choice for your use-case,
you can follow and study about on the internet and follow the official document
Spring JPA tutorial link
Spring Batch tutorial link
Happy Learning, Hope more users would suggest other good options that you can choose from and apply to your use-case post evaluating their pros and cons
i have been using this JDBC conection in all of my class that had to run query but i created a new class which i dont want the constructor with a parameter of the DConnection from JDBC Class(main Database Class).
but i keep on getting NullPointExceptions. Can anyway figur out what that problem may be.
Thanks.
public class UsersDao {
// associating the Database Connection objekt
private DConnector connector;
private final Connection myConn;
// Constructor
public UsersDao() throws CZeitExceptionHand,SQLException {
myConn = connector.getConnenction();
}
public boolean updateUsers(String mitarb, int mid) throws SQLException{
// PreparedStatement myStmt = null;
Statement stmt = myConn.createStatement();
try {
String myStmt = "SELECT Bly "
+ "" + mid + ";";
return stmt.execute(myStmt);
} finally {
close(stmt);
}
}
Example like this Method which is working but in different class
String[][] getAllTheWorkers(DConnector connector) throws CZeitExceptionHand {
try {
Connection connect = connector.getConnenction();
Statement stmt = connect.createStatement();
ResultSet result = stmt.executeQuery("SELECT ");
result.last();
int nt = result.getRow();
result.beforeFirst();
}
return results;
} catch (SQLException e) {
throw new CZeitExceptionHand("Error: " + e);
}
}
The object does not seem to be initialized.
Can you please post which method is not working and from where it is invoked ?
P.S : Unable to add a comment - that is why have answered !
first time posting so sorry if my question is slightly strange.
So I have a project in school that requires us to create java classes using netbeans that open up a window with three options, check stock, purchase item and update stock.
We had a class called stockdata that held the details of 5 different items for us to use in our three classes to check, purchase and update items. The latest stage of our coursework requires us to create a derby database and enter the items into a table.
I have done this with no issues but I am having a problem getting the items from the table back into my classes to use. We were given the following code but I can't get it to work, even using the commented hints.
package stock;
// Skeleton version of StockData.java that links to a database.
// NOTE: You should not have to make any changes to the other
// Java GUI classes for this to work, if you complete it correctly.
// Indeed these classes shouldn't even need to be recompiled
import java.sql.*; // DB handling package
import java.io.*;
import org.apache.derby.drda.NetworkServerControl;
public class StockData {
private static Connection connection;
private static Statement stmt;
static {
// standard code to open a connection and statement to an Access database
try {
NetworkServerControl server = new NetworkServerControl();
server.start(null);
// Load JDBC driver
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
//Establish a connection
String sourceURL = "jdbc:derby://localhost:1527/"
+ new File("UserDB").getAbsolutePath() + ";";
connection = DriverManager.getConnection(sourceURL, "use", "use");
stmt = connection.createStatement();
} // The following exceptions must be caught
catch (ClassNotFoundException cnfe) {
System.out.println(cnfe);
} catch (SQLException sqle) {
System.out.println(sqle);
} catch (Exception e) {
System.out.println(e);
}
}
// You could make methods getName, getPrice and getQuantity simpler by using an auxiliary
// private String method getField(String key, int fieldNo) to return the appropriate field as a String
public static String getName(String key) {
try {
// Need single quote marks ' around the key field in SQL. This is easy to get wrong!
// For instance if key was "11" the SELECT statement would be:
// SELECT * FROM Stock WHERE stockKey = '11'
ResultSet res = stmt.executeQuery("SELECT * FROM Stock WHERE stockKey = '" + key + "'");
if (res.next()) { // there is a result
// the name field is the second one in the ResultSet
// Note that with ResultSet we count the fields starting from 1
return res.getString(2);
} else {
return null;
}
} catch (SQLException e) {
System.out.println(e);
return null;
}
}
public static double getPrice(String key) {
// Similar to getName. If no result, return -1.0
return 0;
}
public static int getQuantity(String key) {
// Similar to getName. If no result, return -1
return 0;
}
// update stock levels
// extra is +ve if adding stock
// extra is -ve if selling stock
public static void update(String key, int extra) {
// SQL UPDATE statement required. For instance if extra is 5 and stockKey is "11" then updateStr is
// UPDATE Stock SET stockQuantity = stockQuantity + 5 WHERE stockKey = '11'
String updateStr = "UPDATE Stock SET stockQuantity = stockQuantity + " + extra + " WHERE stockKey = '" + key + "'";
System.out.println(updateStr);
try {
stmt.executeUpdate(updateStr);
} catch (SQLException e) {
System.out.println(e);
}
}
// close the database
public static void close() {
try {
connection.close();
} catch (SQLException e) {
// this shouldn't happen
System.out.println(e);
}
}
}
Sorry if this seems a stupid question but I am fairly new to Java and was making good progress until this roadblock.
Thanks in advance!
Alex
Searching for "java sql" on Google delivers this link: https://docs.oracle.com/javase/tutorial/jdbc/basics/processingsqlstatements.html
From a connection you can create a statement (you can find this in the link and in your code) , then fetch a result set and loop over that with rs.next(). That should get your started.
Of course you have to make sure that the driver and database are there/running, just saying...
Here netbeans has nothing to do with database. This is a Java-based integrated development environment(IDE) that will help you to reduce syntactic error.
public void dataAccess(){
try {
String connectionUrl = "suitable connection url as per your database";
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
Class.forName("JDBC driver name as per your database");
con = DriverManager.getConnection(connectionUrl, userName, password);
String SQL = "SQL query as per your criteria";
stmt = con.createStatement();
rs = stmt.executeQuery(query);
while (rs.next()) {
// look into ResultSet api and use method as per your requirement
}
rs.close();
}
catch (Exception e) {
//log error message ;
}
}
I'm writing a simple java application (in study purpose) to manage employees and I need an advise: how to store and retrieve data from the database.
Code, that I have wrote so far is too big to put it here, so, in two words:
I have next hierarchy:
abstract class Employee: 4 attributes, getters, setters
class Salaried: 2 new attribute
class Hourly : 2 new attributes
class Director: 3 new attributes
class Manager : 1 new attribute
I have a MySQL data with 1 table (create script):
CREATE TABLE `employee` (
`SSN` int(9) NOT NULL PRIMARY KEY,
`FirstName` varchar(20) NOT NULL,
`LastName` varchar(20) NOT NULL,
`Department` varchar(20) NOT NULL,
`Salary` float(10) NULL,
`OvertimeHours` float(10) NULL,
`HourlyWage` float(10) NULL,
`NumberHours` float(10) NULL,
`Organization` varchar(30) NULL,
`Bonus` float(10) NULL
);
First 4 fields are general for all employees.
Salary and OvertimeHours are attributes of the Salaried class
HourlyWage and NumberHours are attributes of the Hourly class
Salary, Bonus and Organization are attributes of the Director class
Salary also is a attribute of the Manager class
I've created a static class Database to work with the MySQL.
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Connection;
public abstract class Database {
// constants
private static final String DRIVER = "com.mysql.jdbc.Driver";
private static final String DBNAME = "records";
private static final String DBUSER = "root";
private static final String DBPASS = "";
private static final String CONURL = "jdbc:mysql://localhost/" + DBNAME;
// class attributes
private static Connection connection = null;
public static boolean fillEmployee(Employee emp, int ssn)
{
try {
PreparedStatement stm = connection.prepareStatement(
"SELECT FirstName, LastName, Department "
+ "FROM employee "
+ "WHERE SSN = ?"
);
stm.setInt(1, ssn);
ResultSet rs = stm.executeQuery();
if(!rs.next())
return false;
emp.setSocialSecurity(ssn);
emp.setFirstName(rs.getString("FirstName"));
emp.setLastName(rs.getString("LastName"));
emp.setDepartment(rs.getString("Department"));
stm.close();
rs.close();
} catch (Exception e) {
System.out.println(e.getMessage());
System.exit(0);
}
return true;
}
public static boolean deleteEmployee(int ssn){
try {
PreparedStatement stm = connection.prepareStatement(
"DELETE "
+ "FROM employee "
+ "WHERE SSN = ?"
);
stm.setInt(1, ssn);
return (stm.executeUpdate() == 1);
} catch (Exception e) {
System.out.println(e.getMessage());
System.exit(0);
}
return false;
}
// class methods
public static Salaried getSalariedEmployee(int ssn){
Salaried employee = new Salaried();
try {
if(!fillEmployee(employee, ssn))
return null;
PreparedStatement stm = connection.prepareStatement(
"SELECT Salary, OvertimeHours "
+ "FROM employee "
+ "WHERE SSN = ?"
);
stm.setInt(1, ssn);
ResultSet rs = stm.executeQuery();
employee.setSalary(rs.getFloat("Salary"));
employee.setOvertimeHours(rs.getFloat("OvertimeHours"));
stm.close();
rs.close();
} catch (Exception e) {
System.out.println(e.getLocalizedMessage());
System.exit(0);
}
return employee;
}
public static void createConnection() {
if (connection != null)
return;
try {
Class.forName(DRIVER);
connection = DriverManager.getConnection(CONURL, DBUSER, DBPASS);
} catch (Exception e) {
System.out.println(e.getMessage());
System.exit(0);
}
}
public static void closeConnection(){
if (connection == null)
return;
try{
connection.close();
connection = null;
} catch (Exception e) {
System.out.println(e.getMessage());
System.exit(0);
}
}
}
What are you thinking about getSalariedEmployee and fillEmployee methods?
How can I improve the overall design and architecture of my application?
The first thing I would do is stop using static methods for all your Database functions.
Also why is Database an abstract class? Is there another class that extends Database with specific implementations (like MyDatabase or OracleDatabase.
You might consider using static methods to return an instance of a Database and then convert the static methods to public instance methods.
Perhaps you should start with a good reading of the book Patterns of Enterprise Architecture. It has a good chapter covering the different ways in which we typically deal with the database.
You can read quick definitions of these in the companion web site:
Transaction Script
Table Data Gateway
Row Data Gateway
Active Record
Data Mapper
All the patterns have advantages and disadvantages and some of them have entire frameworks that help you write code for them.
I think you could wait for creating the employee object in getSalariedEmployee.
instantiate it only if you find the db object.
Because if you return null when not finding it, you still create the employee object.
I am trying to retrieve different kind of metadata of my Oracle DB from Java code (using basic JDBC). For example, if I want to retrieve the list of tables with _FOO suffix, I can do something like:
Connection connection = dataSource.getConnection();
DatabaseMetaData meta = connection.getMetaData();
ResultSet tables = meta.getTables(connection.getCatalog(), null, "%_FOO", new String[] { "TABLE" });
// Iterate on the ResultSet to get information on tables...
Now, I want to retrieve all the sequences from my database (for example all sequence named S_xxx_FOO).
How would I do that, as I don't see anything in DatabaseMetaData related to sequences?
Do I have to run a query like select * from user_sequences ?
Had the same question. It's fairly easy. Just pass in "SEQUENCE" into the getMetaData().getTables() types param.
In your specific case it would be something like:
meta.getTables(connection.getCatalog(), null, "%_FOO", new String[] { "SEQUENCE" });
You can't do this through the JDBC API, because some databases (still) do not support sequences.
The only way to get them is to query the system catalog of your DBMS (I guess it's Oracle in your case as you mention user_sequences)
You can use the hibernate dialect api for retrieving sequence Name. see : http://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/dialect/Dialect.html
From below example, you can see how to use dialect to get sequence names
public static void main(String[] args) {
Connection jdbcConnection = null;
try {
jdbcConnection = DriverManager.getConnection("", "", "");
printAllSequenceName(jdbcConnection);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(jdbcConnection != null) {
try {
jdbcConnection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void printAllSequenceName(Connection conn) throws JDBCConnectionException, SQLException {
DialectResolver dialectResolver = new StandardDialectResolver();
Dialect dialect = dialectResolver.resolveDialect(conn.getMetaData());
if ( dialect.supportsSequences() ) {
String sql = dialect.getQuerySequencesString();
if (sql!=null) {
Statement statement = null;
ResultSet rs = null;
try {
statement = conn.createStatement();
rs = statement.executeQuery(sql);
while ( rs.next() ) {
System.out.println("Sequence Name : " + rs.getString(1));
}
}
finally {
if (rs!=null) rs.close();
if (statement!=null) statement.close();
}
}
}
}
If you don't desire to use hibernate, then you have to crate custom sequential specific implementation.
Sample code for custom implementation
interface SequenceQueryGenerator {
String getSelectSequenceNextValString(String sequenceName);
String getCreateSequenceString(String sequenceName, int initialValue, int incrementSize);
String getDropSequenceStrings(String sequenceName);
String getQuerySequencesString();
}
class OracleSequenceQueryGenerator implements SequenceQueryGenerator {
#Override
public String getSelectSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName ) + " from dual";
}
#Override
public String getCreateSequenceString(String sequenceName,
int initialValue, int incrementSize) {
return "create sequence " + sequenceName + " start with " + initialValue + " increment by " + incrementSize;
}
#Override
public String getDropSequenceStrings(String sequenceName) {
return "drop sequence " + sequenceName;
}
#Override
public String getQuerySequencesString() {
return "select sequence_name from user_sequences";
}
}
class PostgresSequenceQueryGenerator implements SequenceQueryGenerator {
#Override
public String getSelectSequenceNextValString(String sequenceName) {
return "select " + getSelectSequenceNextValString( sequenceName );
}
#Override
public String getCreateSequenceString(String sequenceName,
int initialValue, int incrementSize) {
return "create sequence " + sequenceName + " start " + initialValue + " increment " + incrementSize;
}
#Override
public String getDropSequenceStrings(String sequenceName) {
return "drop sequence " + sequenceName;
}
#Override
public String getQuerySequencesString() {
return "select relname from pg_class where relkind='S'";
}
}
public void printSequenceName (SequenceQueryGenerator queryGenerator, Connection conn) throws SQLException {
String sql = queryGenerator.getQuerySequencesString();
if (sql!=null) {
Statement statement = null;
ResultSet rs = null;
try {
statement = conn.createStatement();
rs = statement.executeQuery(sql);
while ( rs.next() ) {
System.out.println("Sequence Name : " + rs.getString(1));
}
}
finally {
if (rs!=null) rs.close();
if (statement!=null) statement.close();
}
}
}
public static void main(String[] args) {
Connection jdbcConnection = null;
try {
jdbcConnection = DriverManager.getConnection("", "", "");
printAllSequenceName(new OracleSequenceQueryGenerator(), jdbcConnection);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(jdbcConnection != null) {
try {
jdbcConnection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Given that recent versions of the Oracle JDBC drivers (e.g. 12.1.0.2) don't return sequence information when you call DatabaseMetaData#getTables with types set to ["SEQUENCE"], your best bet is to run the necessary query yourself, e.g.:
SELECT o.owner AS sequence_owner,
o.object_name AS sequence_name
FROM all_objects o
WHERE o.owner LIKE 'someOwnerPattern' ESCAPE '/'
AND o.object_name LIKE 'someNamePattern' ESCAPE '/'
AND o.object_type = 'SEQUENCE'
ORDER BY 1, 2
... where someOwnerPattern and someNamePattern are SQL patterns like the ones you'd use with the LIKE operator (e.g. % matches anything).
This is basically the same as the query run by the driver itself, except that it queries for objects of type SEQUENCE.