Good practice to store derived classes in the database - java

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.

Related

Java Servlet Static DAO

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.

How do I call data from a table in a database into a java class in netbeans?

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 ;
}
}

Why does Bluemix dashDB operation throws a SqlSyntaxErrorException with SQLCODE=-1667?

I'm getting this error even though I am not trying to edit the table/column:
com.ibm.db2.jcc.am.SqlSyntaxErrorException: The operation failed because the operation is not supported with the type of the specified table. Specified table: "DASH103985.wajihs". Table type: "ORGANIZE BY COLUMN". Operation: "WITH RS".. SQLCODE=-1667, SQLSTATE=42858
#MultipartConfig
public class DemoServlet extends HttpServlet {
private static Logger logger = Logger.getLogger(DemoServlet.class.getName());
private static final long serialVersionUID = 1L;
#Resource(lookup="jdbc/db2")DataSource dataSource;
private String getDefaultText() {
TweetsCombined = new String(" ");
try {
// Connect to the Database
Connection con = null;
try {
System.out.println("Connecting to the database");
} catch (SQLException e) {
TweetsCombined = "first" +e;
}
// Try out some dynamic SQL Statements
Statement stmt = null;
try {
stmt = con.createStatement();
String tableName = "wajihs";// change table name here to one
// chosen in the first website
String columnName = "msgBody";// msgBody is where the tweets
// are stored
String query = "SELECT * FROM \"" + tableName + "\"";
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
content = rs.getString(columnName) + ". ";
if (content.toLowerCase().contains("RT".toLowerCase())
|| content.toLowerCase().contains("Repost: ".toLowerCase())) {
// do nothing
}
else {
TweetsCombined.concat(content);
}
}
// Close everything off
// Close the Statement
stmt.close();
// close
con.commit();
// Close the connection
con.close();
} catch (Exception e) {
TweetsCombined = "second" +e;
System.out.println(e.getMessage());
}
} catch (Exception e) {
TweetsCombined = "third" + e;
System.out.println(e);
}
return TweetsCombined;
}
As I explained here, dashDB, with its BLU Acceleration features, has certain limitations compared to DB2 without BLU Acceleration. In your case it is that you can only run queries with the CS isolation level against column-organized tables.
Either change your connection configuration to use CS isolation level or create your table(s) while explicitly specifying ORGANIZE BY ROW.

how to pass a java object to oracle stored procedure with following details

I have my ORACLE table with structure as
desc extraction_log1
Name Null
Type
------------------------------ -------- ------------------------------------------------------------ ---------------------------------------------------------------------------------------------------- -----------------------------
ROW_NUM NOT NULL NUMBER
DATE_TIME TIMESTAMP(8)
USER_NAME VARCHAR2(32)
PLATFORM_NAME VARCHAR2(20)
R_OBJECT_ID VARCHAR2(16)
Then I created an object type in oracle as
create or replace type EXTRACTION_LOG_TYPE as object (
USER_NAME VARCHAR2(32),
R_OBJECT_ID VARCHAR2(16),
);
Then I created procedure in a package as
create or replace package body PAC_BEAN is
--The insert procedure will receive EXTRACTION_LOG_TYPE and put it into table EXTRACTION_LOG1.
procedure PRO_INSERT_LOG(ELT in EXTRACTION_LOG_TYPE) is
begin
insert into EXTRACTION_LOG1 ( R_OBJECT_ID, USER_NAME)
values (ELT.R_OBJECT_ID, ELT.USER_NAME);
commit;
exception
when others then
rollback;
end PRO_INSERT_LOG;
end PAC_BEAN;
and coming to my java side I have declared a bean with
public class ExtractionLogType {
//Name declared in Oracle
public static final String ORACLE_OBJECT_NAME = "EXTRACTION_LOG_TYPE";
//The attributes
private String R_OBJECT_ID;
private String USER_NAME;
//setters and getters
public String getR_OBJECT_ID() {
return R_OBJECT_ID;
}
public void setR_OBJECT_ID(String rOBJECTID) {
R_OBJECT_ID = rOBJECTID;
}
public String getUSER_NAME() {
return USER_NAME;
}
public void setUSER_NAME(String uSERNAME) {
USER_NAME = uSERNAME;
}
}
in my Class containing main
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DBLogger{
String dbUrl;
Connection con;
//constructor for creation of connection object
as and when an object of DBLogger is instantiated
public DBLogger(){
dbUrl = "jdbc:oracle:thin#my url";
try {
//load Oracle Driver class
Class.forName("oracle.jdbc.driver.OracleDriver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.err.println("Oracle driver class not found");
}
try {
//instantiate connection object
con = DriverManager.getConnectio (dbUrl,"userId","pwd");
} catch (SQLException e) {
e.printStackTrace();
System.err.println("Connection object to oracle cant be established");
}
}
public static void main(String args[]){
try{
DBLogger db=new DBLogger();
CallableStatement cs = null;
ExtractionLogType elt=new ExtractionLogType();
elt.setR_OBJECT_ID("79479479A900");
elt.setUSER_NAME("Jeevan");
cs = db.con.prepareCall("{call PAC_BEAN.PRO_INSERT_LOG(?)}");
/*
* *code to insert the above object into our Database
*
*/
cs.execute();
System.out.println("insert procedure executed successfully");
db.con.close();
} //end try
catch (SQLException e) {
e.printStackTrace(); }
catch(Exception e) { e.printStackTrace();
}
}
}
I can't figure out the code to make the object get inserted into my database.
can anyone suggest me regarding this.
Thank You.
You will have to define a array descriptor for your database type, this example could help you:
final ArrayDescriptor descriptor = ArrayDescriptor.createDescriptor("EXTRACTION_LOG_TYPE", con);
// create an Object Array
Object[] data = new Object[2];
// set the values in order of appearance
data[0] = elt.getUSER_NAME();
data[1] = elt.getR_OBJECT_ID();
// Create the Array
ARRAY array = new ARRAY(descriptor, con, data);
// put it on your statement
cs.setArray(1, array);
// execute ...
This is terrible idea to create any objects in SYSTEM schema of the database. It is the same bad idea to connect your app straight to this scheme either.
This looks like a lack of privileges disallowing you to get what you want. Create new schema, dedicated user of this schema and then create all required object using this new user (it will be the owner of your objects). This way you can avoid "issue" where you cannot access something you supposed to have an access to.

League Table - SQL Query/JDBC Issue

I currently have a very basic app that interacts with a database (Using netbeans and the jdbc) so that you can add teams, players and scores. I now need to be able to display items from each table together in a League Table/Team (With players) Table etc etc.
My question is how do I go about retrieving the information from the tables and how do I display it, I am literally clueless as to how I should go about it. I'm assuming I need to do a Join or Select statement (I'm a complete SQL novice) and then use a loop to select each table entry and display it in a table somehow?
The only current working features I have are adding to the database, IE add a new team add a new player etc, displaying what is in the tables on the form is where I am stumped.
Any tips or help is much appreciated.
The code I am currently using is this; (I still need to implement a score table and adding records to that, I also created the datbase using the GUI and so have no foreign keys set, is there a way to do this WITHIN netbeans as I have no "Create Table" code anywhere.
package football.game;
/*import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;*/
import football.game.DBconnection;
import java.sql.*;
/**
*
* #author Steffan Caine
*/
public class SportsConnection extends DBconnection {
public SportsConnection(final String dbName)
{
this.connectDatabase(dbName);
}
public void insertPlayer(final Integer PLAYERNUM,
final String PLAYERNAME, final String PLAYERPOS, final Integer TEAMNUM)
{
final String insertStmt = "INSERT INTO APP.PLAYERS (PLAYERNUM, PLAYERNAME, PLAYER_POS, TEAM_ID) VALUES (?,?, ?, ?)";
try
{
PreparedStatement pstmt = getConnection().prepareStatement(insertStmt);
pstmt.setInt(1, PLAYERNUM);
pstmt.setString(2, PLAYERNAME);
pstmt.setString(3, PLAYERPOS);
pstmt.setInt(4, TEAMNUM);
pstmt.executeUpdate();
}
catch (SQLException sqle)
{
System.out.println("Exception when inserting player record: " + sqle.toString());
}
}
public void insertTeam(final String NAME, final String MANAGER, final int ID)
{
final String insertStmt = "INSERT INTO APP.TEAMS (TEAMNAME, MANAGER, TEAM_ID) VALUES (?,?, ?)";
try
{
PreparedStatement pstmt = getConnection().prepareStatement(insertStmt);
pstmt.setString(1, NAME);
pstmt.setString(2, MANAGER);
pstmt.setInt(3, ID);
pstmt.executeUpdate();
}
catch (SQLException sqle)
{
System.out.println("Exception when inserting team record: " + sqle.toString());
}
}
public void printAllRecords()
{
this.setQuery(retrieveQuery);
this.runQuery();
ResultSet output = this.getResultSet();
try
{
if (null != output)
{
while(output.next())
{
String PLAYERNUM = output.getString(1);
String PLAYERNAME = output.getString(2);
System.out.println (PLAYERNUM + "\n" + PLAYERNAME + "\n");
}
}
}
catch (SQLException sqle)
{
System.out.println("Exception when printing all students: " + sqle.toString());
}
}
}
The "retrieveQuery" currently returns an error message, any help getting that part to work would be great as printing the records out in a console would add some much needed (If basic) functionality.
I also have classes for each form (AddPlayer/AddTeam/Navigation) but I am not using constructors to populate the database I am instead using Methods located in a Main class, is this a bad way to go about things as I am not using "Objects" as such?
Thanks.
I see three tables: PLAYER, TEAM, and LEAGUE.
A TEAM has many PLAYERs; a LEAGUE has many TEAMs. These should be one-to-many relationships, so you'll have foreign keys. Here's an example:
CREATE TABLE PLAYER (
int id not null auto increment,
first_name varchar(80),
last_name varchar(80),
int team_id,
primary key(id),
foreign key(team_id) references TEAM(id)
);
CREATE TABLE TEAM (
int id not null auto increment,
name varchar(80),
primary key(id)
);
So you might have Java classes like this:
package model;
public class Player {
private Integer id,
private String name;
// ctors, getters, etc.
}
public class Team {
private Integer id,
private String name,
List<Player> players;
// ctors, getters, etc.
}
You'll have a persistence layer that will have all your SQL in it:
package persistence;
public interface PlayerDao {
Player find(Integer id);
List<Player> find();
Integer save(Player p);
void update(Player p);
void delete(Player p);
}
Here's a sample implementation for PlayerDao:
package persistence;
public class PlayerDaoImpl implements PlayerDao {
private static final String SELECT_ALL = "SELECT id, name FROM PLAYER ";
private static final String SELECT_BY_ID = SELECT_ALL + "WHERE id = ?";
private Connection connection;
public PlayerDaoImpl(Connection connection) {
this.connection = connection;
}
public Player find(Integer id) {
Player p = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = this.connection.prepareStatement(SELECT_BY_ID);
ps.setInteger(1, id);
rs = ps.executeQuery();
while (rs.next()) {
Integer pid = rs.getInteger("id");
String name = rs.getString("name");
p = new Player(id, name);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
DatabaseUtils.close(rs);
DatabaseUtils.close(ps);
}
return p;
}
}
Printing records in consoles or user interfaces would indeed be useful, but that should be done by different classes in different packages. Have a view tier that handles that stuff. Classes should do one thing well. You should think about layering your applications appropriately.

Categories