I am designing a MVC JAVAFX program that has intensive database connection. I dont know where to put the database connection details. Whether I should define the connection details info in a Model form and process the connection as a controller or should I put them together in one single model file.
In the long run I need that connection as a session throughout the program until the user logoff.
Is there any simple example that I could study for this matter. I know using hibernate is the best way but im still learning Java FX and I need someguidance about this.
Thanks.
At the moment I'm also at an JavaFX application with an database connection. The way I chose is the following: Create a SQL-Controller-Class. This class should contain everything handling your SQL-Data(For example: a connect-method to open a connection - a close-method is also not wrong). Use this class in all your controller classes to get the data you need or save the data you have.
Here an little example
The SQLController class could look like that:
public class SqlController {
//Put you connection string with pw, user, ... here
private static final String YOUR_CONNECTION_STRING = "";
public boolean openConnection() {
boolean result;
try {
// Open your connection
result = true;
} catch (Exception e) {
result = false;
}
return result;
}
public boolean closeConnection() {
boolean result;
try {
// Close your connection
result = true;
} catch (Exception e) {
result = false;
}
return result;
}
public YourData getSomeData(){
//get The Data you want.
return YourData;
}
}
You could use the controller in any method of your UI-Controller.
public void handelSomeUiThing()
{
SqlController sc = new SqlController();
sc.openConnection();
YourData = sc.getSomeData();
sc.closeConnection();
}
Hope that helps!
PS: Everyone has his own programming-style. You have to see what fits for your application and what is the most comfortable way for you.
If you're using MVC, download the Spring Boot dependency and put it in your application.properties...
Related
I have designed and implemented a simple webstore based on traditional MVC Model 1 architecture using pure JSP and JavaBeans (Yes, I still use that legacy technology in my pet projects ;)).
I am using DAO design pattern to implement my persistence layer for a webstore. But I am not sure if I have implemented the classes correctly in my DAO layer. I am specifically concerned about the QueryExecutor.java and DataPopulator.java classes (mentioned below). All the methods in both these classes are defined as static which makes me think if this is the correct approach in multithreaded environment. Hence, I have following questions regarding the static methods.
Will there be synchronization issues when multiple users are trying to do a checkout with different products? If answer to the above question is yes, then how can I actually reproduce this synchronization issue?
Are there any testing/tracing tools available which will actually show that a specific piece of code will/might create synchronization issues in a multithreaded environment? Can I see that a User1 was trying to access Product-101 but was displayed Product-202 because of non thread-safe code?
Assuming there are synchronization issues; Should these methods be made non-static and classes instantitable so that we can create an instance using new operator OR Should a synchronized block be placed around the non thread-safe code?
Please guide.
MasterDao.java
public interface MasterDao {
Product getProduct(int productId) throws SQLException;
}
BaseDao.java
public abstract class BaseDao {
protected DataSource dataSource;
public BaseDao(DataSource dataSource) {
this.dataSource = dataSource;
}
}
MasterDaoImpl.java
public class MasterDaoImpl extends BaseDao implements MasterDao {
private static final Logger LOG = Logger.getLogger(MasterDaoImpl.class);
public MasterDaoImpl(DataSource dataSource) {
super(dataSource);
}
#Override
public Product getProduct(int productId) throws SQLException {
Product product = null;
String sql = "select * from products where product_id= " + productId;
//STATIC METHOD CALL HERE, COULD THIS POSE A SYNCHRONIZATION ISSUE ??????
List<Product> products = QueryExecutor.executeProductsQuery(dataSource.getConnection(), sql);
if (!GenericUtils.isListEmpty(products)) {
product = products.get(0);
}
return product;
}
}
QueryExecutor.java
public final class QueryExecutor {
private static final Logger LOG = Logger.getLogger(QueryExecutor.class);
//SO CANNOT NEW AN INSTANCE
private QueryExecutor() {
}
static List<Product> executeProductsQuery(Connection cn, String sql) {
Statement stmt = null;
ResultSet rs = null;
List<Product> al = new ArrayList<>();
LOG.debug(sql);
try {
stmt = cn.createStatement();
rs = stmt.executeQuery(sql);
while (rs != null && rs.next()) {
//STATIC METHOD CALL HERE, COULD THIS POSE A SYNCHRONIZATION ISSUE ???????
Product p = DataPopulator.populateProduct(rs);
al.add(p);
}
LOG.debug("al.size() = " + al.size());
return al;
} catch (Exception ex) {
LOG.error("Exception while executing products query....", ex);
return null;
} finally {
try {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (cn != null) {
cn.close();
}
} catch (Exception ex) {
LOG.error("Exception while closing DB resources rs, stmt or cn.......", ex);
}
}
}
}
DataPopulator.java
public class DataPopulator {
private static final Logger LOG = Logger.getLogger(DataPopulator.class);
//SO CANNOT NEW AN INSTANCE
private DataPopulator() {
}
//STATIC METHOD DEFINED HERE, COULD THIS POSE A SYNCHRONIZATION ISSUE FOR THE CALLING METHODS ???????
public static Product populateProduct(ResultSet rs) throws SQLException {
String productId = GenericUtils.nullToEmptyString(rs.getString("PRODUCT_ID"));
String name = GenericUtils.nullToEmptyString(rs.getString("NAME"));
String image = GenericUtils.nullToEmptyString(rs.getString("IMAGE"));
String listPrice = GenericUtils.nullToEmptyString(rs.getString("LIST_PRICE"));
Product product = new Product(new Integer(productId), name, image, new BigDecimal(listPrice));
LOG.debug("product = " + product);
return product;
}
}
Your code is thread-safe.
The reason, and the key to thread-safety, is your (static) methods do not maintain state. ie your methods only use local variables (not fields).
It doesn't matter if the methods are static or not.
Assuming there are synchronization issues; Should these methods be made non-static and classes instantitable so that we can create an instance using new operator
This won't help. Multiple threads can do as they please with a single object just as they can with a static method, and you will run into synchronization issues.
OR Should a synchronized block be placed around the non thread-safe code?
Yes this is the safe way. Any code inside of a synchronized block is guaranteed to have at most one thread in it for any given time.
Looking through your code, I don't see many data structures that could possibly be shared amongst threads. Assuming you had something like
public final class QueryExecutor {
int numQueries = 0;
public void doQuery() {
numQueries++;
}
}
Then you run into trouble because 4 threads could have executed doQuery at the same moment, and so you have 4 threads modifying the value of numQueries - a big problem.
However with your code, the only shared class fields is the logging class, which will have it's own thread-safe synchronization built in - therefore the code you have provided looks good.
There is no state within your code (no mutable member variables or fields, for example), so Java synchronisation is irrelevant.
Also as far as I can tell there are no database creates, updates, or deletes, so there's no issue there either.
There's some questionable practice, for sure (e.g. the non-management of the database Connection object, the wide scope of some variables, not to mention the statics), but nothing wrong as such.
As for how you would test, or determine thread-safety, you could do worse than operate your site manually using two different browsers side-by-side. Or create a shell script that performs automated HTTP requests using curl. Or create a WebDriver test that runs multiple sessions across a variety of real browsers and checks that the expected products are visible under all scenarios...
We persist a graph in a piece of code and then have another code, that tries to retrieve it. We open our transacitons with this Spring bean. Anyone who wants to access the database always calls the getGraph() method of this bean.
public class OrientDatabaseConnectionManager {
private OrientGraphFactory factory;
public OrientDatabaseConnectionManager(String path, String name, String pass) {
factory = new OrientGraphFactory(path, name, pass).setupPool(1,10);
}
public OrientGraphFactory getFactory() {
return factory;
}
public void setFactory(OrientGraphFactory factory) {
this.factory = factory;
}
/**
* Method returns graph instance from the factory's pool.
* #return
*/
public OrientGraph getGraph(){
OrientGraph resultGraph = factory.getTx();
resultGraph.setThreadMode(OrientBaseGraph.THREAD_MODE.ALWAYS_AUTOSET);
return resultGraph;
}
}
(I was unable to quite understand the thread_mode fully, but I think it should not be related to the problem.)
The code, that persists the graph commits and shuts down, as you can see here:
OrientDatabaseConnectionManager connMan; //this is an injected bean from above.
public boolean saveGraphToOrientDB(
SparseMultigraph<SocialVertex, SocialEdge> graph, String label) {
boolean isSavedCorrectly = false;
OrientGraph graphO = connMan.getGraph();
try {
graphDBinput.saveGraph(graph, label, graphO);
// LOG System.out.println("Graph was saved with label "+label);
isSavedCorrectly = true;
} catch (AlreadyUsedGraphLabelException ex) {
Logger.getLogger(GraphDBFacade.class.getName()).log(Level.SEVERE, null, ex);
} finally {
graphO.shutdown(); //calls .commit() automatically normally, but commit already happens inside.
}
return isSavedCorrectly;
}
This commit works well - the data are always persisted, I checked everytime in the orientdb admin interface, and the first persisted graph is always viewable okay. It might be important to note, that during the saving the label used defines new class (thus modifying schema, as I understand it) and uses it for the persisted graph.
The retrieval of the graph looks something like this:
#Override
public SocialGraph getSocialGraph(String label) {
OrientGraph graph = connMan.getGraph();
SocialGraph socialGraph = null;
try {
socialGraph = new SocialGraph(getAllSocialNodes(label, graph), getAllSocialEdges(label, graph));
} catch (Exception e) {
logger.error(e);
} finally {
graph.shutdown();
}
return socialGraph;
}
public List<Node> getAllSocialNodes(String label, OrientGraph graph) {
return constructNodes(graphFilterMan.getAllNodesFromGraph(label, graph));
}
public Set<Vertex> getAllNodesFromGraph(String graphLabel, OrientGraph graph) {
Set<Vertex> labelledGraph = new HashSet<>();
try{
Iterable<Vertex> configGraph = graph.getVerticesOfClass(graphLabel);
for(Vertex v : configGraph){ //THE CODE CRASHES HERE, WITH "CLASS WITH NAME graphLabel DOES NOT EXIST
labelledGraph.add(v);
}
} catch(Exception ex){
logger.error(ex);
graph.rollback();
}
return labelledGraph;
}
So the problem is, that when we persist a new graph with a new class, say "graph01" and then we want to retrieve it, it goes okay. Later, we create a "graph02" and we want to retrieve it, but it crashes, as commented above - OrientDb tells you, that the class with "graph02" name does not exist.
It does exist in the admin interface at the time, however, when I debug, the class actually is not in the schema right after call of factory.getTx()
Right at the beginning, when we get a transaction graph instance from the factory, we get a graph with a context in which the rawGraph's underlying database's metadata have the schema proxy delegate schema shared classes WITHOUT the new class, which I can apparently see commited in the database.
Or here on picture:
There should be one more class in the schema. The one that was persisted (and commited ) a while ago - which can also be seen in the orientDb admin interface (not present in the variable)
What I presume is happening is that the pool, from which the factory gets the transaction has somewhat cached schema or something. It does not refresh the schema, when we add a new class.
Why does the schema not show the new class, when we are trying to get the new graph out? Does schema not get refreshed?
I found here in schema documentation that
NOTE: Changes to the schema are not transactional, so execute them outside a transaction.
So should we create the new class outside a transaction and then we would get an update in the schema in the context?
//Maybe I am understanding the concepts wrong - I got in contact with OrientDb just yesterday and I am to find out the problem in an already written code.
Db we use is a remote:localhost/socialGraph
OrientDB of version 1.7.4
We noticed in our code about the same issue, schema changes aren't visible in pooled connections.
We also have a sort of factory that gets a connection. What we do is keep a schema version number, and each time we have some operation that changes the schema, we bump the number and when a new connection is opened, we check the schema version, if it is changed.
When the schema is changed, we reload the schema, close the pool and recreate it. The method is proven for us to work (we are currently on version 2.0.15).
Here's the relevant code:
private static volatile int schemaVersion = -1;
private OPartitionedDatabasePool pool;
protected void createPool() {
pool = new OPartitionedDatabasePool(getUrl(), getUsername(), getPassword());
}
#Override
public synchronized ODatabaseDocumentTx openDatabase() {
ODatabaseDocumentTx db = pool.acquire();
//DatabaseInfo is a simple class put in a static contect that holds the schema version.
DatabaseInfo databaseInfo = CurrentDatabaseInfo.getDatabaseInfo();
ODocument document = db.load((ORID) databaseInfo.getId(), "schemaVersion:0", true);
Integer version = document.field("schemaVersion");
if (schemaVersion == -1) {
schemaVersion = version;
} else if (schemaVersion < version) {
db.getMetadata().getSchema().reload();
schemaVersion = version;
pool.close();
createPool();
db = pool.acquire();
}
return db;
}
In the end the problem was, that we had two liferay projects, each had its own spring application context in its WAR file and when we deployed these projects as portlets within Liferay, the two projects created two contexts, in each having one OrientDatabaseConnectionManager.
In one context the schema was being changed. And even though I reset the connection and reloaded the schema, it only happened with the connection manager / factory in one context. The retrieving of the graph was happening in the portlet of the other project though, resulting in an outdate schema (which was not reloaded, because the reloading happened in the other spring context) - thus the error.
So you have to be careful - either share one spring application context with beans for all your portlets (which is possible by having a parent application context, you can read more about it here)
OR
check for changes in the schema from within the same project which you will also use to retrieve the data later.
For university, it is my excercise to develop a multiplayer game with Java. The communication between the clients shall not be handled with sockets or the like, but with the help of a MySQL database where the clients are adding their steps in the game. Because it is a game of dice, not a lot of queries are needed. (approximiately 30 queries per gaming session are needed).
I never used MySQL in connection with Java before, so this maybe is a beginner's fault. But actually, I often get an exception during the execution of my java project.
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: User my_username already has more than 'max_user_connections' active connections
My queries are executed in a DatabaseHelper.java class. The results are returned and evaluated in another class of the project. Since I use an MVC pattern, I evaluate the results in a controller or model class.
This for example is one of my quers in the DatabaseHelper.java class. The other queries are similar:
private static Connection conn;
private Connection getConn() {
return conn;
}
public void db_connect() throws ClassNotFoundException, SQLException{
// JDBC Klassen laden
Class.forName(dbClassName);
// Verbindungsversuch auf 5 Sekunden setzen
DriverManager.setLoginTimeout(5);
this.setConn(DriverManager.getConnection(CONNECTION,p)); // p contains the username and the database
}
public void db_close(){
try {
this.getConn().close();
} catch (SQLException e) {
if(GLOBALVARS.DEBUG)
e.printStackTrace();
}
}
public String[] query_myHighscores(int gameid, PlayerModel p) throws SQLException{
List<String> rowValues = new ArrayList<String>();
PreparedStatement stmnt;
if(gameid == GLOBALVARS.DRAGRACE)
stmnt = this.getConn().prepareStatement("SELECT score FROM highscore WHERE gid = ? and pname = ? ORDER BY score ASC LIMIT 0,3");
else
stmnt = this.getConn().prepareStatement("SELECT score FROM highscore WHERE gid = ? and pname = ? ORDER BY score DESC LIMIT 0,3");
stmnt.setInt(1, gameid);
stmnt.setString(2, p.getUname());
ResultSet rs = stmnt.executeQuery();
rs.beforeFirst();
while(rs.next()){
rowValues.add(rs.getString(1));
}
stmnt.close();
rs.close();
return (String[])rowValues.toArray(new String[rowValues.size()]);
}
The CONNECTION string is a string which looks like jdbc:mysql://my_server/my_database
In the HighscoreGUI.java class, I request the data like this:
private void actualizeHighscores(){
DatabaseHelper db = new DatabaseHelper();
try{
db.db_connect();
String[] myScoreDragrace = db.query_myHighscores(GLOBALVARS.GAME1); // id of the game as parameter
// using the string
} finally {
db.db_close();
}
So I tried:
Closing the statement and the ResultSet after each query
Used db_close() to close the connection to the dabase in the finally-block
Never returning a ResultSet (found out this may become a performance leak)
The stacktrace leads in the DatabaseHelper.java class to the line
this.setConn(DriverManager.getConnection(CONNECTION,p));
But I cannot find my mistake why I still get this exception.
I cannot change every settings for the database since this is a shared host. So I'd prefer a solution on Java side.
The problem is that you exceed your allowed set of connections to that database. Most likely this limit is exactly or very close to "1". So as soon as you request your second connection your program crashes.
You can solve this by using a connection pooling system like commons-dbcp.
That is the recommended way of doing it and the other solution below is only if you may not use external resources.
If you are prohibited in the external code that you might use with your solution you can do this:
Create a "Database" class. This class and only this class ever connects to the DB and it does so only once per program run. You set it up, it connects to the database and then all the queries are created and run through this class, in Java we call this construct a "singleton". It usually has a private constructor and a public static method that returns the one and only instance of itself. You keep this connection up through the entire livetime of your program and only reactivate it if it gets stall. Basically you implement a "Connection Pool" for the specific case of the pool size "1".
public class Database {
private static final Database INSTANCE = new Database();
private Database() {}
public static Database getInstance() {
return INSTANCE;
}
// add your methods here.
}
When the program terminates, close the Connection (using a shutdown hook).
I am trying to create a library which manages data. Part of it is storing stuff in databases. Since I don't know what the user of library wants to store, I am using generics. Here is my method to read a database table.
public <TEntity extends SyncableBase> List<TEntity> loadItems(Class clazz) {
List<TEntity> listToReturn = new ArrayList<TEntity>();
DatabaseHelperBase dbHelper = getDbHelper();
Dao<TEntity, Integer> dao;
try {
dao = dbHelper.getDao(clazz); //Is this approach correct?
listToReturn = dao.queryForAll(); //This doesn't work
} catch (SQLException e){
e.printStackTrace();
}
return listToReturn;
}
And somewhere in my app (which consumes this library) I call this method like so:
List<ToDoCategory> catList = mirrorservice.<ToDoCategory>loadItems(ToDoCategory.class);
No matter what I do, the empty ArrayList is returned to catList. I tried similar approach with queryForId too. That didn't work either. Meanwhile, my add is working just fine!
I suspect that there is something wrong with the way I'm creating Dao. What is the problem?
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 12 years ago.
Before i go any further it would be nice to know if there is any major design flaws in my program so far. Is there anything worth changing before i continue?
Model
package model;
import java.sql.*;
import java.util.*;
public class MovieDatabase {
#SuppressWarnings({ "rawtypes", "unchecked" })
public List queryMovies() throws SQLException {
Connection connection = null;
java.sql.Statement statement = null;
ResultSet rs = null;
List results = new ArrayList();
try {
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "password");
statement = connection.createStatement();
String query = "SELECT * FROM movie";
rs = statement.executeQuery(query);
while(rs.next()) {
MovieBean bean = new MovieBean();
bean.setMovieId(rs.getInt(1));
bean.setTitle(rs.getString(2));
bean.setYear(rs.getInt(3));
bean.setRating(rs.getInt(4));
results.add(bean);
}
} catch(SQLException e) {
}
return results;
}
}
Servlet
public class Service extends HttpServlet {
#SuppressWarnings("rawtypes")
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("Movies!");
MovieDatabase movies = new MovieDatabase();
try {
List results = movies.queryMovies();
Iterator it = results.iterator();
while(it.hasNext()) {
MovieBean movie = new MovieBean();
movie = (MovieBean)it.next();
out.println(movie.getYear());
}
}
catch(SQLException e) {
}
}
}
Bean
package model;
#SuppressWarnings("serial")
public class MovieBean implements java.io.Serializable {
protected int movieid;
protected int rating;
protected int year;
protected String title;
public MovieBean() {
}
public void setMovieId(int movieidVal) {
movieid = movieidVal;
}
public void setRating(int ratingVal) {
rating = ratingVal;
}
public void setYear(int yearVal) {
year = yearVal;
}
public void setTitle(String titleVal) {
title = titleVal;
}
public int getMovieId() {
return movieid;
}
public int getRating() {
return rating;
}
public int getYear() {
return year;
}
public String getTitle() {
return title;
}
}
Here are a couple of suggestions:
Your MovieDatabase has the Connection creation embedded inside it. You don't use a Connection pool that way.
You embed the connection parameters (e.g., driver class, URL, etc.) inside your code. Best to externalize them.
You don't clean up any JDBC resources. This is guaranteed to bring you grief.
You have empty catch blocks. This is a heinous error. Log the stack trace. You'll have no way of knowing if anything is wrong as coded.
MovieBean? Names matter - make it Movie.
Your default constructor does nothing at all, and it's the only constructor you provide. Your String reference to title will be null. I think you should have one constructor that initializes all the fields properly.
Your Service should not extend Servlet. I think you should have a POJO interface and an implementation that has nothing to do with HTTP. You can't use this service (or test it) without the web.
Another empty catch block - you're asking for trouble. When will you learn to print the stack trace?
I wouldn't have a MovieDatabase; I'd go with a MovieDao interface that had CRUD operations, like this:
package persistence;
public interface MovieDao
{
List<Movie> find();
Movie find(int id);
List<Movie> find(String title);
void save(Movie movie);
void update(Movie movie);
void delete(Movie movie);
}
Much of the following is style, not necessarily the 'right' way, and certainly not the only way.
I'd move the database connection
to a try block in the servlet's #doGet. I'd pass the
connection to
MovieDatabase#queryMovies. The
reason is, what happens if in that same request you need
to do another query using another
class? Your connection is in
MovieDatabase and another class
would have no access to it. If you had a situation where both classes could update the database, you'd be unable to roll back the entire transaction. Not good.
I'd add a commit statement at the end of the 'success' path in #doGet
I'd add after try block containing the database connection an exception block, wherein I'd issue a rollback. So if there's an exception, a rollback would be performed every time.
I'd close the database connection in
#doGet's finally block. This is most important. edit - see the pseudocode below for an example
If you don't move the connection into the servlet, then straight
away you should close that
connection in #queryMovies' finally
clause.
If this were a larger project, I'd use Hibernate and its tools to
generate DAOs and models. Hibernate
would generate for you a class and
method that would return a
collection of MovieBeans to you.
You wouldn't have to do anything but
invoke it. Auto-generated database
access code is good.
I'd add a JSP and put the collection you're building into the request. Then your jsp could iterate over the collection and format it as appropriate. This moves the presentation of the information out of the servlet, which is a coordinator of action, not a formatter of data in the MVC model.
If you implemented the above suggestions, it would probably drop your number of lines of code by 50% or more. Learning Hibernate can be a headache, so it wouldn't necessarily be easier or faster the first time. The reason it reduces the lines of code (while doing pretty much the same work) is that generated code is pretty much right and coders don't have to worry about it.
I use the following pattern in my servlets all the time. This is pseudocode, not real java.
Connection conn = null;
try {
conn.getConnection(...);
// your implementation here
conn.commit();
} catch (Exception e) {
conn.rollback();
} finally {
conn.close();
}
The point is that the database connection can always be passed to workers, work is always committed unless something goes wrong. If something goes wrong, there's guaranteed to be a rollback. In either case, the database connection is closed when its all over.
It's pretty simple and straightforward, no big issues. The only thing I would point out is that you're doing a SELECT * then refer to the result set by column index. This is not a problem at this stage but if your schema changes (say, a field gets added in the middle) then your code will break. I would explicitly select the column names:
SELECT id, title, year, rating FROM movie
There are many things wrong (many have already pointed out most of them). Seems like the code is written in 90's. I strongly suggest you read about layered architecture, separation of concerns, MVC, DAO pattern. Then you will answer the question yourself and I will up vote your answer ;-).