I am facing problem. We are writting Java application as school project and we are supposed to use threads. Obviously, the application is not as complex to require threads, but we have to have them.
We decided to use threads for database communication, but we are not sure, how to use them for single methods. We created Database Transfer Object with some methods to insert entities into DB. How to use Runnable for single methods, please? To be more specific, we would like to create Runnable in methods and then add it to thread pool, but then, we would be able to get returns back.
public class EmployeeDTO {
private Employee employee;
private Connection conn;
private int id_employee;
/**
* Database connection
* #throws ClassNotFoundException
* #throws SQLException
*/
public EmployeeDTO() throws ClassNotFoundException, SQLException {
DatabaseConnection dbcon = new DatabaseConnection();
conn = dbcon.getConnection();
}
public EmployeeDTO(Employee employee) throws ClassNotFoundException, SQLException {
this.employee = employee;
DatabaseConnection dbcon = new DatabaseConnection();
conn = dbcon.getConnection();
}
/**
* Insert new Employee into database and sets it's id
* #param emp
* #throws SQLException
*/
public void insertEmployee(Employee emp) throws SQLException {
setEmployee(emp);
PreparedStatement pr = conn.prepareStatement("INSERT INTO employees "
+ "(nickname,name,surname,password_emp) "
+ "VALUES (?,?,?,?)", PreparedStatement.RETURN_GENERATED_KEYS);
pr.setString(1, employee.getNickname());
pr.setString(2, employee.getName());
pr.setString(3, employee.getSurname());
pr.setString(4, employee.getPassword());
pr.executeUpdate();
ResultSet rs = pr.getGeneratedKeys();
while (rs.next()) {
employee.setId_employee(rs.getInt(1));
}
}
/**
* Delete an employee from database
* #param id
* #throws SQLException
*/
public void deleteEmployee(int id) throws SQLException {
PreparedStatement pr = conn.prepareStatement("DELETE FROM employees WHERE id_employee=?");
pr.setInt(1, id);
pr.executeUpdate();
}
}
To be more specific, we would like to create Runnable in methods and then add it to thread pool, but then, we would be able to get returns back.
Sounds like you want to submit Callable tasks (not Runnable) to a thread pool. When you submit a Callable<T> task to an ExecutorService, you get back a Future<T> object that you can use at a later time to wait for the result of the task.
You may want to do something like below. Your insertEmployee method will be called from call method.
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.Callable;
public class EmployeeDTO implements Callable<String> {
private Employee employee;
private Connection conn;
private int id_employee;
/**
* Database connection
* #throws ClassNotFoundException
* #throws SQLException
*/
public EmployeeDTO() throws ClassNotFoundException, SQLException {
DatabaseConnection dbcon = new DatabaseConnection();
conn = dbcon.getConnection();
}
public EmployeeDTO(Employee employee) throws ClassNotFoundException, SQLException {
this.employee = employee;
DatabaseConnection dbcon = new DatabaseConnection();
conn = dbcon.getConnection();
}
/**
* Insert new Employee into database and sets it's id
* #param emp
* #throws SQLException
*/
public void insertEmployee(Employee emp) throws SQLException {
setEmployee(emp);
PreparedStatement pr = conn.prepareStatement("INSERT INTO employees "
+ "(nickname,name,surname,password_emp) "
+ "VALUES (?,?,?,?)", PreparedStatement.RETURN_GENERATED_KEYS);
pr.setString(1, employee.getNickname());
pr.setString(2, employee.getName());
pr.setString(3, employee.getSurname());
pr.setString(4, employee.getPassword());
pr.executeUpdate();
ResultSet rs = pr.getGeneratedKeys();
while (rs.next()) {
employee.setId_employee(rs.getInt(1));
}
}
/**
* Delete an employee from database
* #param id
* #throws SQLException
*/
public void deleteEmployee(int id) throws SQLException {
PreparedStatement pr = conn.prepareStatement("DELETE FROM employees WHERE id_employee=?");
pr.setInt(1, id);
pr.executeUpdate();
}
/**
* Computes a result, or throws an exception if unable to do so.
*
* #return computed result
* #throws Exception if unable to compute a result
*/
public String call() throws Exception {
insertEmployee(employee);
return "SUCCESS";
}
}
In other class you can use the ExecutorService like below
try{
Set<Callable<String>> callables = new HashSet<Callable<String>>();
EmployeeDTO employee = new EmployeeDTO(emp);
callables.add(employee);
ExecutorService executorService = Executors.newFixedThreadPool(1);
List<Future<String>> futures = executorService.invokeAll(callables);
}catch (ExecutionException eEx) {
eEx.getMessage();
}finally{
executorService.shutdown();
}
Related
I'm having an issue with getting the value of stored ArrayList<String> as VARCHAR[] in the database.
Somehow, when I'm debugging, I can see that the value returning from the database is:
I am expecting to store an ArrayList<String> by converting it to VARCHAR[] and when reading from the DB I expect to convert VARCHAR[] to ArrayList<String>
Code:
public Message<ArrayList<String>> getPlayersInSession(Object data) throws SQLException, ClassNotFoundException {
String sessionCode = (String) data;
Session session = PostgreSQLJDBC.sessionJDBCInstance().getSession(sessionCode);
//session.getPlayers() is the problem I have
return new Message<>(Message.RequestCode.RECEIVE_PLAYERS_IN_SESSION, session.getPlayers());
(Message.RequestCode.RECEIVE_PLAYERS_IN_SESSION, players);
}
public class Session {
private int _id;
private String _code;
private ArrayList<String> _players;
private ArrayList<Pair<String, String>> _leaderboard;
public Session() {
_code = "";
_players = new ArrayList<>();
_leaderboard = new ArrayList<>();
}
...
}
public class SessionJDBC implements SessionSQL {
private final Connection _connection;
public SessionJDBC(String url, String user, String password) throws ClassNotFoundException, SQLException {
Class.forName("org.postgresql.Driver");
_connection = DriverManager.getConnection(url, user, password);
if (!sessionTableExists()) createTable();
}
#Override
public void createTable() throws SQLException {
String sql = "CREATE TABLE session(" +
"id SERIAL PRIMARY KEY," +
"code VARCHAR," +
"players VARCHAR[]," +
"leaderboard VARCHAR[]" +
")";
PreparedStatement ps = _connection.prepareStatement(sql);
ps.executeUpdate();
}
#Override
public void addSession(Session session) throws SQLException {
String sql = "INSERT INTO session(code, players, leaderboard)"
+ "VALUES (?,?,?)";
PreparedStatement ps = _connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, session.getCode());
ps.setArray(2, _connection.createArrayOf("VARCHAR", session.getPlayers().toArray()));
ps.setArray(3, _connection.createArrayOf("VARCHAR", session.getLeaderboard().toArray()));
ps.executeUpdate();
ResultSet generatedKeys = ps.getGeneratedKeys();
if (generatedKeys.next()) {
session.setId(generatedKeys.getInt(1));
}
}
#Override
public void removeSession(Session session) throws SQLException {
String sql = "DELETE FROM session WHERE id = ?";
PreparedStatement ps = _connection.prepareStatement(sql);
ps.setInt(1, session.getId());
ps.executeUpdate();
}
#Override
public Session getSession(String code) throws SQLException {
return getAllSessions().stream().filter(session -> session.getCode().equals(code)).findFirst().orElse(null);
}
#Override
public ArrayList<Session> getAllSessions() throws SQLException {
ArrayList<Session> array = new ArrayList<>();
ResultSet result = _connection.prepareStatement("SELECT * FROM session").executeQuery();
while (result.next()) {
Session session = new Session();
session.setCode(result.getString("code"));
session.setId(result.getInt("id"));
session.setPlayers(new ArrayList(Collections.singletonList(result.getArray("players"))));
session.setLeaderboard(new ArrayList(Collections.singletonList(result.getArray("leaderboard"))));
array.add(session);
}
result.close();
return array;
}
#Override
public boolean sessionTableExists() throws SQLException {
DatabaseMetaData dbm = _connection.getMetaData();
ResultSet tables = dbm.getTables(null, null, "session", null);
return tables.next();
}
}
I don't know how the code example compiles given that the ArrayList shown in the debugger is actually of type ArrayList<PgArray> rather than ArrayList<String>.
The problem is occurring in these lines:
session.setPlayers(new ArrayList(Collections.singletonList(result.getArray("players"))));
session.setLeaderboard(new ArrayList(Collections.singletonList(result.getArray("leaderboard"))));
For a start result.getArray("players") is returning a java.sql.Array object, more specifically a PgArray implementation. To get the real underlying data you need to do:
(String[])result.getArray("players").getArray();
The next problem is that you are using Collections.singletonList(). What this does is produce an ArrayList with only one element. Instead what you should use is Arrays.asList. Full solution:
session.setPlayers(new ArrayList(Arrays.asList((String[])result.getArray("players").getArray)));
session.setLeaderboard(new ArrayList(Arrays.asList((String[])result.getArray("leaderboard").getArray)));
Another thing that is interesting about this code is that you are selecting all rows from the table and then filtering in memory by streaming over the results. Why not select on the code field in an SQL query?
Have implemented a DAO pattern with Hikari connection pool
Made the best use of the DAO design pattern.
Have created singleton class which returns the object of a class with a public connection if the object of the singleton class is NULL> object is again created thereby getting the connection
queries to call the static method of the singleton class to obtain public connection and prepared statements are closed in try-with-resources.
application is live for more than 12hrs after few requests queries are not getting executed
"The connection is closed."
public class DatabaseConnection {
//Constants
String url = "jdbc:mysql://localhost:3306/";
String driver="com.mysql.jdbc.Driver";
String userName = "root";
String password = "#";
private static HikariDataSource dataSource;
public Connection conn;
public static DatabaseConnection db;
/**
* A static method which uses HikariDataSource Connection Pooling library to connect with the MySQL Database.
* Accepts and Sets few JDBC details like User Name,Password,URL,Driver Name and many more.
* #return This methods returns HikariDataSource
* #throws SQLException and CasbnException
*/
public DatabaseConnection() throws SQLException,CasbnExceptions {
try {
//create the object of HikariDataSource
dataSource=new HikariDataSource();
//set up the JDBC details (username,password,url,driver)
System.out.println("Inside DatabaseConnection constructor..");
dataSource.setDriverClassName(driver);
dataSource.setJdbcUrl(url);
dataSource.setUsername(userName);
dataSource.setPassword(password);
this.conn=dataSource.getConnection();
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static DatabaseConnection getCon() throws CasbnExceptions, SQLException
{
if(db==null)
{
System.out.println("Inside getCon() and if block...");
db=new DatabaseConnection();
}
return db;
}
}
public class DAO_Implementation implements DAOFactory {
//Declare all the SQL queries as private static and final
//getCompany query
private static final String getCompanyName="SELECT company_name FROM #.company_register where email=?";
#Override
public String getCompanyName(String Email) throws SQLException {
try
(PreparedStatement pst = DatabaseConnection.getCon().conn
.prepareStatement(getCompanyName)){
pst.setString(1, Email);
ResultSet rs = pst.executeQuery();
rs.next();
Name=rs.getString(1);
}
catch(Exception e)
{
e.printStackTrace();
}
return Name;
}
#Override
public Pojos Individual_Company_detail(String CompanyName) throws SQLException{
try
(PreparedStatement pst = DatabaseConnection.getCon().conn
.prepareStatement(CompanyDetail);){
pst.setString(1, CompanyName);
ResultSet rs = pst.executeQuery();
if(rs.next()==true)
{
Pojos Po=new Pojos();
Po.setCompanyID(rs.getInt(1));
Po.setUserCount(rs.getInt(2));
Po.setPlan(rs.getString(3));
Po.setDateofSub(rs.getString(4));
Po.setSubscriptionID(rs.getString(5));
Po.setVaildTill(rs.getString(6));
return Po;
}
else
{
Pojos Po=new Pojos();
Po.setErrorMessage(CompanyName +" Has not registered to of our Plan and no Recent Transactions");
return Po;
}
}
}
Currently you are returning the same connection all the time using .conn
remove conn from DatabaseConnection and add a different method which getConnection from Hikari datasource every time
This way Hikari will handle connection pooling
public static Connection getConnection() {
return dataSource.getConnection();
}
And open Connection resource separately so it will be closed:
try
(Connection conn = DatabaseConnection.getConnection();
PreparedStatement pst = conn.prepareStatement(CompanyDetail))
public class DatabaseConnection {
String url = "jdbc:mysql://localhost:3306/";
//String dbName = ""
String driver="com.mysql.jdbc.Driver";
String userName = "root";
String password = "";
private static HikariDataSource dataSource;
public static DatabaseConnection db;
public DatabaseConnection() throws SQLException,CasbnExceptions {
try {
//create the object of HikariDataSource
dataSource=new HikariDataSource();
//set up the JDBC details (username,password,url,driver)
System.out.println("Inside DatabaseConnection constructor..");
dataSource.setDriverClassName(driver);
dataSource.setJdbcUrl(url);
dataSource.setUsername(userName);
dataSource.setPassword(password);
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException
{
if(db==null)
{
db=new DatabaseConnection();
}
return dataSource.getConnection();
}
}
I'm learning to program in java and the use of servlet and jsp page.
I have some trouble understanding how I can make the connection with the database.
In particular I have a Java page called Database.java where I create the connection with the database and in which there are all the functions that are performed.
And I created a page called Prenotation.java where I have to do some actions. My problem is that I would not like to leave the database connection on this page (as you can see from the code) but I would like to make the connection via the Database.java page.
I've tried several times but I do not understand how I can do it.
Can you give me some advice? Thank you.
Database.java
package db;
import java.math.BigDecimal;
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.concurrent.TimeUnit;
import entity.*;
public class Database {
private Connection connection = null;
private PreparedStatement statement = null;
private ResultSet rs = null;
private String dbname = "Hotel";
String nomeutente = "root";
String password = "123456789";
private static Database db = null;
public static synchronized Database getDatabase() {
if (db == null) {
db = new Database();
}
return db;
}
private Database() {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/" + dbname
+ "?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC",
nomeutente, password);
} catch (Exception exc) {
exc.printStackTrace();
}
}
public Connection getConnection() {
return connection;
}
public boolean checkUser(String email, String password) throws SQLException {
boolean result = false;
String query = "select password from users where email=?";
statement = connection.prepareStatement(query);
statement.setString(1, email);
rs = statement.executeQuery();
if (rs.next() && password.equals(rs.getString("password"))) {
result = true;
}
rs.close();
statement.close();
return result;
}
public boolean existingMail(String email) throws SQLException {
String query = "select * from users where email=?";
boolean result = true;
statement = connection.prepareStatement(query);
statement.setString(1, email);
rs = statement.executeQuery();
if (rs.next()) {
result = true;
} else {
result = false;
}
rs.close();
statement.close();
return result;
}
public boolean insertUtente(Utente u,String password) throws SQLException {
String query = "INSERT INTO users (email,nome,cognome,luogodinascita,datadinascita,indirizzo,password) VALUES (?,?,?,?,?,?,?)";
if(existingMail(u.getEmail())) {
return false;
}
statement = connection.prepareStatement(query);
statement.setString(1, u.getEmail());
statement.setString(2, u.getNome());
statement.setString(3, u.getCognome());
statement.setString(4, u.getLuogodinascita());
statement.setString(5, u.getDatadinascita());
statement.setString(6, u.getIndirizzo());
statement.setString(7, password);
statement.execute();
statement.close();
return true;
}
public Utente getUtente(String email) throws SQLException {
String query= "select * from users where email=?";
statement = connection.prepareStatement(query);
statement.setString(1, email);
rs=statement.executeQuery();
if(!rs.next()) {
return null;
}
Utente u=new Utente(email,rs.getString("nome"),rs.getString("cognome"),rs.getString("datadinascita"),rs.getString("luogodinascita"),rs.getString("indirizzo"));
rs.close();
statement.close();
return u;
}
public boolean modificaPassword(String email, String password) throws SQLException {
String query="UPDATE users SET password='"+password+"' WHERE email='"+email+"'";
Statement statement=connection.createStatement();
statement.executeUpdate(query);
statement.close();
return true;
}
public boolean modificaProfilo(Utente u) throws SQLException {
String query="UPDATE users SET nome = ?, cognome = ?, datadinascita = ?, luogodinascita = ?, indirizzo = ? WHERE email = ?";
statement = connection.prepareStatement(query);
statement.setString(1, u.getNome());
statement.setString(2, u.getCognome());
statement.setString(3, u.getDatadinascita());
statement.setString(4, u.getLuogodinascita());
statement.setString(5, u.getIndirizzo());
statement.setString(6, u.getEmail());
statement.executeUpdate();
statement.close();
return true;
}}
This instead is the page of which I speak
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.swing.JOptionPane;
import db.Database;
import entity.Prenotazione;
/**
*
* #author OOPs
*/
public class Prenotation extends HttpServlet {
private static final String ResultSet = null;
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session=request.getSession();
String idPrenotazione = request.getParameter("idPrenotazione");
String email = request.getParameter("email");
int typeRoom = Integer.parseInt(request.getParameter("typeRoom"));;
String arrivalDate = request.getParameter("arrivalDate");
String departureDate = request.getParameter("departureDate");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
// out.println("driver loaded");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/Hotel?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC","root" ,"123456789");
out.println("Connect");
Statement st = con.createStatement();
// Statement stmt = con.createStatement();
out.println("connection successfull");
int total = 0;
PreparedStatement ps = con.prepareStatement( "SELECT COUNT(*) as total FROM reservation WHERE typeRoom = ? AND (? >= arrivaldate AND ? <= departuredate) OR (? >= arrivaldate AND ? <= departuredate)");
int c = 0;
ps.setInt(++c, typeRoom);
ps.setString(++c, arrivalDate);
ps.setString(++c, departureDate);
ps.setString(++c, arrivalDate);
ps.setString(++c, departureDate);
ResultSet rs = ps.executeQuery();
// ResultSet rs2 = stmt.executeQuery(check);
out.println("<h1> Stringa check eseguito </h1>");
if( total > 0) {
// response.sendRedirect("home.jsp");
response.sendRedirect("PrenotazioneNegata.jsp");
}
else {
st.executeUpdate("insert into reservation (email,typeRoom,arrivalDate,departureDate)values ('"+email+"','"+typeRoom+"','"+arrivalDate+"','"+departureDate+"')");
response.sendRedirect("PrenotazioneAvvenuta.jsp");
}
out.println("<h1> Registrazione Eseguita </h1>");
}catch(Exception e){
out.println("Errore." +e);
}
finally {
out.close();
}
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
/**
* Handles the HTTP <code>GET</code> method.
*
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Handles the HTTP <code>POST</code> method.
*
* #param request servlet request
* #param response servlet response
* #throws ServletException if a servlet-specific error occurs
* #throws IOException if an I/O error occurs
*/
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
/**
* Returns a short description of the servlet.
*
* #return a String containing servlet description
*/
#Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
A web container will typically route requests to the same servlet instance so it needs to be thread safe. Currently, the Database class provides a single connection, which would be used by concurrent requests so it is not thread safe.
Consider creating something like a ConnectionFactory class. For example:
public class ConnectionFactory {
public Connection getConnection() {
// move all the creation code from Database class to here
// create and return a new instance
}
}
Then modify the Database class to use the factory
public class Database {
private final ConnectionFactory connectionFactory;
public Database(ConnectionFactory connectionFactory) {
this.connectionFactory = connectionFactory;
}
// change to private and use the factory
private Connection getConnection() {
return connectionFactory.getConnection();
}
// example method to be used by servlet
public int getTotalReservations(int typeRoom, String arrivalDate, departureDate) {
// query related code currently in serlvet goes here...
}
}
And use the servlet lifecycle init() method to create the objects so the servlet can use it. For example:
public class Prenotation extends HttpServlet {
private Database database;
#Override
public void init() throws ServletException {
super.init();
this.database = new Database(new ConnectionFactory()); // no statics needed!
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session=request.getSession();
String idPrenotazione = request.getParameter("idPrenotazione");
String email = request.getParameter("email");
int typeRoom = Integer.parseInt(request.getParameter("typeRoom"));;
String arrivalDate = request.getParameter("arrivalDate");
String departureDate = request.getParameter("departureDate");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
// use the method from `Database` which knows how to query the DB.
int totalReservations = database.getTotalReservations(typeRoom, arrivalDate, departureDate);
// more processing... and forward to the JSP
}
Note that Database now refers to both a USERS table and a RESERVATTIONS table. It would be better to split these into separate classes, such as UsersQuery and ReservationsQuery. They can both share the same ConnectionFactory instance.
See also:
single responsibility principle
inversion of control (injecting ConnectionFactory into Database)
servlet lifecycle
why static variables (or singletons) are/can be evil
DataSource (instead of the low level ConnectionFactory)
i'm trying to make a DAO class for my Java project.
I've a SQLite Database with only one table "USER".
The schema is:
CREATE TABLE USER(
username VARCHAR(20) NOT NULL PRIMARY KEY,
password VARCHAR NOT NULL,
total_matches INTEGER DEFAULT 0,
victories INTEGER DEFAULT 0,
times_alien INTEGER DEFAULT 0,
times_human INTEGER DEFAULT 0,
total_steps INTEGER DEFAULT 0,
humans_killed INTEGER DEFAULT 0,
aliens_killed INTEGER DEFAULT 0,
kills_as_human INTEGER DEFAULT 0,
kills_as_alien INTEGER DEFAULT 0,
total_escapes INTEGER DEFAULT 0,
total_broken_hatches INTEGER DEFAULT 0,
total_noises INTEGER DEFAULT 0,
online_status VARCHAR(5) NOT NULL DEFAULT "false");
My UserDAOImpl class has findAll(), findByNickname(String nickname), insert, update, delete methods.
I use PreparedStatementto prevent SQL Injection.
My Issue is that if I call my insert(User toInsert) method and then cycle through the findAll() result, I can see the right insertion.
But if I go to the Terminal and open the DB with the SQLite command line, when I execute "SELECT * FROM USER", the previous insertion doesn't shows.
The DB Class:
/**
* The Class DB.
* Gives a connection to the game Database.
*/
public class DB {
/** the singleton instance of the Database. */
private static DB instance = new DB();
/** the path to the database. */
private static final String DBPath = "db/eftaios_DB.db";
/**
* Istantiates a new Database.
*/
private DB(){
/*
*
*/
}
/**
* Create a connection between this class and the database files.
*
* #return the database connection.
* #throws SQLException the SQL exception
*/
public Connection connect() throws SQLException{
Connection dbConnection = null;
try {
Class.forName("org.sqlite.JDBC");
String dbPath = DB.class.getClassLoader().getResource(DBPath).getPath();
dbConnection = DriverManager.getConnection("jdbc:sqlite:"+dbPath);
} catch (ClassNotFoundException e) {
/*
* do nothing, the class is imported in the maven dependencies
*/
} catch (SQLException e) {
throw new SQLException();
}
return dbConnection;
}
The DAO Class is:
/**
* The class UserDAOImpl implements the UserDAOInterface
* It implements a DAO (Data Access Object) for the User table.
* It gives access to the User table on the Database.
* With this class you can perform queries like find, insert, delete and update on the USER table.
*/
public class UserDAOImpl implements UserDAOInterface {
/** the database connection used to query it. */
private Connection dbConnection;
/** the result of a query to the database. */
private ResultSet queryResult;
/** the statement to execute to perform db queries. */
private Statement queryStatement;
/** the prepared statement to execute mysql injection secure queryes. */
private PreparedStatement queryPreparedStatement;
/** the name of the database user's table. */
private static final String USER_TABLE = "USER";
/**
* To user list.
*
* #param qryResult the qry result
* #return the list
* #throws SQLException the SQL exception
*/
private List<User> toUserList(ResultSet qryResult) throws SQLException{
List<User> result = new ArrayList<User>();
/* forall user in result, populate the new user and add it to the users list */
while(qryResult.next()){
User record = new User();
record.setNickname(qryResult.getString(User.NICKNAME_COL_NAME));
record.setPassword(qryResult.getString(User.PASSWORD_COL_NAME));
record.setAliensKilled(qryResult.getInt(User.ALIENS_KILLED_COL_NAME));
record.setHumansKilled(qryResult.getInt(User.HUMANS_KILLED_COL_NAME));
record.setKillsAsAlien(qryResult.getInt(User.KILLS_AS_ALIEN_COL_NAME));
record.setKillsAsHuman(qryResult.getInt(User.KILLS_AS_HUMAN_COL_NAME));
record.setOnlineStatus(qryResult.getBoolean(User.ONLINE_STATUS_COL_NAME));
record.setTimesAlien(qryResult.getInt(User.TIMES_ALIEN_COL_NAME));
record.setTimesHuman(qryResult.getInt(User.TIMES_HUMAN_COL_NAME));
record.setTotalBrokenHatches(qryResult.getInt(User.TOTAL_BROKEN_HATCHES_COL_NAME));
record.setTotalEscapes(qryResult.getInt(User.TOTAL_ESCAPES_COL_NAME));
record.setTotalMatches(qryResult.getInt(User.TOTAL_MATCHES_COL_NAME));
record.setTotalNoises(qryResult.getInt(User.TOTAL_NOISES_COL_NAME));
record.setTotalSteps(qryResult.getInt(User.TOTAL_STEPS_COL_NAME));
record.setVictories(qryResult.getInt(User.VICTORIES_COL_NAME));
result.add(record);
}
return result;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#findAll()
*/
#Override
public List<User> findAll() throws SQLException {
String findAllQuery = "SELECT * FROM "+USER_TABLE;
List<User> users = new ArrayList<User>();
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
this.queryStatement = this.dbConnection.createStatement();
this.queryResult = this.queryStatement.executeQuery(findAllQuery);
users = this.toUserList(queryResult);
this.dbConnection.commit();
this.queryResult.close();
this.queryStatement.close();
this.dbConnection.close();
return users;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#findByNickname(java.lang.String)
*/
#Override
public List<User> findByNickname(String userNickname) throws SQLException {
String findByNicknameQuery = "SELECT * FROM "+USER_TABLE+" WHERE "+User.NICKNAME_COL_NAME+"=?";
List<User> users = new ArrayList<User>();
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
/* preparing the statement to prevent sql injection */
this.queryPreparedStatement = this.dbConnection.prepareStatement(findByNicknameQuery);
this.queryPreparedStatement.setString(1, userNickname);
/* now get the result */
this.queryResult = this.queryPreparedStatement.executeQuery();
users = this.toUserList(queryResult);
this.dbConnection.commit();
this.queryPreparedStatement.close();
this.queryResult.close();
this.dbConnection.close();
return users;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#insert(it.polimi.ingsw.deolacremona.server.model.database.User)
*/
#Override
public boolean insert(User toInsert) throws SQLException {
boolean result = false;
MD5Hasher hasher = new MD5Hasher();
String md5Password = hasher.md5(toInsert.getPassword());
String insertQuery =
"INSERT INTO "+USER_TABLE+" ("+User.NICKNAME_COL_NAME+","+User.PASSWORD_COL_NAME+") VALUES (?,?)";
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
/* preparing the statement to prevent sql injection */
this.queryPreparedStatement = this.dbConnection.prepareStatement(insertQuery);
this.queryPreparedStatement.setString(1, toInsert.getNickname());
this.queryPreparedStatement.setString(2, md5Password);
if(this.queryPreparedStatement.executeUpdate()==1)
result = true;
this.queryPreparedStatement.close();
this.dbConnection.commit();
this.dbConnection.close();
return result;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#update(it.polimi.ingsw.deolacremona.server.model.database.User)
*/
#Override
public boolean update(User toUpdate) throws SQLException {
boolean result = false;
String updateQuery = "UPDATE "+USER_TABLE+" SET "
+ User.ALIENS_KILLED_COL_NAME +"=?,"
+ User.HUMANS_KILLED_COL_NAME +"=?,"
+ User.KILLS_AS_ALIEN_COL_NAME +"=?,"
+ User.KILLS_AS_HUMAN_COL_NAME +"=?,"
+ User.ONLINE_STATUS_COL_NAME +"=?,"
+ User.TIMES_ALIEN_COL_NAME +"=?,"
+ User.TIMES_HUMAN_COL_NAME +"=?,"
+ User.TOTAL_BROKEN_HATCHES_COL_NAME +"=?,"
+ User.TOTAL_ESCAPES_COL_NAME +"=?,"
+ User.TOTAL_MATCHES_COL_NAME +"=?,"
+ User.TOTAL_NOISES_COL_NAME +"=?,"
+ User.TOTAL_STEPS_COL_NAME +"=?,"
+ User.VICTORIES_COL_NAME +"=?"
+ " WHERE "+User.NICKNAME_COL_NAME+"=?";
/* preparing the sql statement to prevent sql injection */
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
this.queryPreparedStatement = this.dbConnection.prepareStatement(updateQuery);
this.queryPreparedStatement.setInt (1, toUpdate.getAliensKilled());
this.queryPreparedStatement.setInt (2, toUpdate.getHumansKilled());
this.queryPreparedStatement.setInt (3, toUpdate.getKillsAsAlien());
this.queryPreparedStatement.setInt (4, toUpdate.getKillsAsHuman());
this.queryPreparedStatement.setBoolean(5, toUpdate.isOnlineStatus());
this.queryPreparedStatement.setInt (6, toUpdate.getTimesAlien());
this.queryPreparedStatement.setInt (7, toUpdate.getTimesHuman());
this.queryPreparedStatement.setInt (8, toUpdate.getTotalBrokenHatches());
this.queryPreparedStatement.setInt (9, toUpdate.getTotalEscapes());
this.queryPreparedStatement.setInt (10, toUpdate.getTotalMatches());
this.queryPreparedStatement.setInt (11, toUpdate.getTotalNoises());
this.queryPreparedStatement.setInt (12, toUpdate.getTotalSteps());
this.queryPreparedStatement.setInt (13, toUpdate.getVictories());
this.queryPreparedStatement.setString (14, toUpdate.getNickname());
if(this.queryPreparedStatement.executeUpdate()==1){
result = true;
}
this.queryPreparedStatement.close();
this.dbConnection.commit();
this.dbConnection.close();
return result;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#updateAdder(it.polimi.ingsw.deolacremona.server.model.database.User)
*/
#Override
public boolean updateAdder(User toUpdate) {
// TODO Auto-generated method stub
return false;
}
/*
* (non-Javadoc)
* #see it.polimi.ingsw.deolacremona.server.model.database.UserDAOInterface#delete(it.polimi.ingsw.deolacremona.server.model.database.User)
*/
#Override
public boolean delete(User toDelete) throws SQLException {
boolean result = false;
String deleteQuery = "DELETE FROM "+USER_TABLE+" WHERE username=?";
this.dbConnection = DB.getDatabase().connect();
this.dbConnection.setAutoCommit(false);
this.queryPreparedStatement = this.dbConnection.prepareStatement(deleteQuery);
this.queryPreparedStatement.setString(1, toDelete.getNickname());
if(this.queryPreparedStatement.executeUpdate()==1){
result = true;
}
this.queryPreparedStatement.close();
this.dbConnection.commit();
this.dbConnection.close();
return result;
}
}
My test main method is:
public static void main(String[] args) throws SQLException, UnknownHostException{
DB database = DB.getDatabase();
database.connect();
MD5Hasher h = new MD5Hasher();
UserDAOImpl d = new UserDAOImpl();
User s = new User();
s.setNickname("davide");
s.setPassword("ciao");
if(d.insert(s))
System.out.println("insert");
// d.delete(s);
for(User x : d.findAll()){
System.out.println("Nickname: "+x.getNickname()+" password: "+x.getPassword()+" matches: "+x.getTotalMatches());
}
}
Thank you for your time.
EDIT: when I cut the database and put it into another directory, exit eclipse, move back the database in his previous directory and reopen eclipse, then all the changes that Java done previously are lost. –
SOLVED: In a Maven Project, all the resources are copied into another directory after the "build" command. I was reading the wrong db.
I would like to have a database connection managing class which I can use for simple SQL commands like SELECT, INSERT etc. by simple calling something like this (class below):
ResultSet test = DataService.getResultSet("SELECT NOW()");
test.first();
System.out.println(test.getString(1));
This is class I've found on web:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Database object to load drivers and perform queries
* #author Abdulsalam Umar blog.salamtura.com
*/
public class DataService {
private static Connection con;
private static final String Driver = "oracle.jdbc.driver.OracleDriver";
private static final String ConnectionString = "Your database connection string";
private static final String user = "username";
private static final String pwd = "password";
/**
* create Database object
*/
public DataService() {
}
/**
* to load the database base driver
* #return a database connection
* #throws SQLException throws an exception if an error occurs
*/
public static Connection loadDriver() throws SQLException {
try {
Class.forName(Driver);
} catch (ClassNotFoundException ex) {
System.out.println(ex.getMessage());
}
con = DriverManager.getConnection(ConnectionString, user, pwd);
return con;
}
/**
* to get a result set of a query
* #param query custom query
* #return a result set of custom query
* #throws SQLException throws an exception if an error occurs
*/
public static ResultSet getResultSet(String query) throws SQLException {
Connection con = loadDriver();
ResultSet rs;
PreparedStatement st = con.prepareStatement(query);
rs = st.executeQuery();
return rs;
}
/**
* to run an update query such as update, delete
* #param query custom query
* #throws SQLException throws an exception if an error occurs
*/
public static void runQuery(String query) throws SQLException {
Connection con = loadDriver();
ResultSet rs;
PreparedStatement st = con.prepareStatement(query);
st.executeUpdate();
}
}
Is this way of returning ResultSet without closing it (and closing the statement) right? How can I return the ResultSet from the method?
Returning result set is not a good idea. So,fetch the required data and make use of collection to return the data.
This answer may be useful
How about passing a callback that takes ResultSet as parameter and let client code do whatever needs to inside it while you make sure that everything is cleaned up afterwards.
This is pattern in used in spring JDBC ResultSetExtractor and RowMapper. Look at this answer.
You can't return ResultSet because it will be closed when method destroyed. But you can get raw data from ResultSet, try this:
public ArrayList<ArrayList<byte[]>> getResultQuery(String query){
ArrayList<ArrayList<byte[]>> tableResult = new ArrayList<>();
ArrayList<byte[]> row;
conn = getConnection(db_url);
try {
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery(query);
int countColumn = resultSet.getMetaData().getColumnCount();
if (countColumn==0) return null;
while (resultSet.next()){
row = new ArrayList<>();
for (int i = 0; i<countColumn; i++){
row.add(i,resultSet.getBytes(i+1));
}
tableResult.add(row);
}
} catch (SQLException e) {
e.printStackTrace();
}
return tableResult;
}
public static Connection getConnection (String db_url){
Connection conn = null;
try{
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
conn = DriverManager.getConnection(db_url);
}catch(Exception e){
e.printStackTrace();
}
return conn;
}
In this, i try to return ArrayList of ArrayList<byte[]>, ArrayList<byte[]> = 1 row in ResultSet. If you want to get some value, just use row.get(i) to get value from column i+1 in ResultSet which look like a 2 dimensions Matrix