How to load global settings frequently used in application in Java - java

1) In my application we have a table which stores some settings detail which are used heavily for every functionality.Basically some conditions are set up in this table which are checked.
Now currently what we are doing is making DB call every now and then to fetch the details and check the condition.This has resulted in lot of DB calls and repetitive calls for the same condition.There are quite a lot of condition records in this table.We need to change this to make it perform better.
2) In my previous project also i had same requirement where we have a configuration table where such settings are configured,there we implemented it like load the configuration from table at start up of application and store them in System.setProperty(name,value)..and later use System.getProperty(name) to retrieve it.In case any settings is changed we update this in its System property.This worked like a charm.
However,in my current case(point 1 above) I don't think my prev way is best way to do it because lot of records present in the table having lot of columns.
Can anyone suggest a way how to achieve such kind of behavior in Java? Some of them I can think of is
1) Using System.setProperty like I explained.
2) Using caching like EHCache - standalone or with hibernate(as we are using hibernate).
Any better way to store such global settings of application so as to avoid DB calls?

Best way to do it using Ehcache(but I have never implemented it). And you should not play with System property it may cause conflict with other system properties.
How I did it in my case I have created a bean class which is having properties as yor table column like autoid, name, address, mobile.
public Map<Integer, PersonBean> getTag()
{
Map<Integer, PersonBean> map= new HashMap<Integer, PersonBean>();
Connection conn =getConnection();
Statement st=null;
ResultSet rs=null;
try
{
String sql = "select autoid,name, address, mobile from person";//person table
st = conn.createStatement();
rs = st.executeQuery(sql);
while(rs.next()){
int tagid=rs.getInt("autoid");
String name=rs.getString("name");
String address=rs.getString("address");
String mobile=rs.getString("mobile");
PersonBean tagdeatilbean= new PersonBean(auotoid,name, address, mobile);
map.put(rs.getInt("autoid"), tagdeatilbean);
}
return map;
}
catch (SQLException e) {
}
finally
{
}
}
and bean class
public class PersonBean
{
private int autoid;
private String name;
private String address;
private String mobile;
public PersonBean(int autoid, String name, String address, String mobile)
{
this.autoid=autoid;
.....
....
}
//setter
//getter
}
If this is web application then you can load this cache map in init method and call the value according to autuid of row from map.

Related

How to implement one to many with jdbc

I'm trying to write a program to manage some clients. Each client has reservations, and each reservation has items.I know that I have one to many relationship, but I cannot figure out how to do that.
I'm not using Spring, only JDBC.
Without a database I did it like that:
public class Client {
private String _fullName;
private String _address;
private String _email;
private String _phoneNumber;
private List<Reservation> _reservations;
}
public class Reservation {
private List<Item> _items;
private int _totalSum;
private boolean _toDeliver;
private String _date;
}
public class Item {
//primary key.
private int _id;
private int _price;
private String _name;
}
Do I have to declare these Lists? Is it possible to do that without Spring, Hibernate and other stuff? I just want to know how design my program.
Yes, you can do everything just with a JDBC database driver.
The first thing you have to do is to design your database, that is your tables and constraints and etc.
Then you go back to Java and query your database using the JDBC.
A common approach to this is creating a DAO class, where you can decouple your database query from your code. It goes something like this:
public String getUserName(String userId) throws SQLException {
String sql = "SELECT name FROM user WHERE user_id = ?";
try (Connection connection = getConnection();
PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, userId);
try (ResultSet rs = stmt.executeQuery()) {
String name = rs.getString("name");
return name;
}
}
}
This is just a simple example, there's no error handling here, neither dealing with empty query results, there are better examples online to illustrate how to make a DAO and create a connection. Depending on where you are running this code, you would prefer using a Connection Pool for efficiency (another thing to read more about).
In your use case, you would have the DAO get the data to make your Item, create a new Item and return it from the DAO. There are plenty of examples of this online, if you have further questions, don't hesitate to ask.

Jdbc template crud operations

So I have the first steps of a webapp, have class Doctor and I want to perform some operations like view all, insert, delete, etc. :
public class Doctor {
public String firstName;
public String lastName;
public int id;
public Doctor(){
}
public Doctor(int id, String first, String last){
setId(id);
setFirstName(first);
setLastName(last);
}
// getters and setters
Here is an implementation of one method from my interface Service. They are all pretty much the same with the appropriate sql queries. I tried following several different tutorials.
public class DAOImpl implements DAO{
public void insertUpdateDoctor(Doctor doctor){
String sql = "INSERT INTO doc_flight.docflight_doctors(id, first_name,last_name)" + "Values(?,?,?)";
jdbcTemplateObject.update(sql,new Object[]{doctor.getId(),doctor.getFirstName(),doctor.getLastName()});
Heres the part in main where I try to call it. The program doesn't even try to enter the method, it doesn't come up in debug and moves to the next method I try in main, view all, which works. Presumably, I'm not calling the method correctly and tried rewriting all parts several times. Help?!
Doctor test = new Doctor(17,"jack", "sparrow");
service.insertUpdateDoctor(test);
The issue itself it's not pretty clear for me.
If the problem is that when calling this:
Doctor test = new Doctor(17,"jack", "sparrow");
service.insertUpdateDoctor(test);
The runtime is not getting inside insertUpdateDoctor, just check how you are instantiating the object service
if the problem is that it's not executing correctly the sql statement, try by using a PreparedStatement (it's a good practice) by doing something like:
String connectionStr = StringUtils.format("INSERT INTO %s.docflight_doctors(id, first_name,last_name) Values(?,?,?)", this.databaseName);
try (Connection connection = this.dataSource.getConnection();
PreparedStatement preparedStatement = connection.prepareStatement(connectionStr)) {
preparedStatement.setInt(1, doctor.getId());
preparedStatement.setString(2, doctor.getFirstName());
preparedStatement.setString(3, doctor.getLastName());
preparedStatement.execute();
connection.commit();
} catch (Exception ex) {
this.logger.error(String.format("Error when inserting: %s", ex.toString()));
}
Hope it may help you.
For me I would not write this class from scratch, I would prefer to generate it in few clicks and save my time using The Cloud Wizard:
Go to https://codegen.cloud-wizard.com
Click on Java
From the technologies section press on Java SE
Select JDBC Class transformer.
In the metadata section enter a name for the JDBC Class e.g. (DoctorDao)
Add some fields e.g. first name and last name
Press on generate code and you will get your class ready and working as expected.

Java and MySQL: More than 'max_user_connections' exception

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).

Mapping ResultSet to Pojo Objects

Well that's really embarrassing I have made a standard pojo class and its dao class for data retrieval purpose. I am having a difficulty to understand a basic procedure to how to handle a customized query data to Pojo class.
let's say my User class is
public class User{
private int userId;
private String username;
private int addressId;
}
public class Address{
private int addressId;
private String zip;
}
public class UserDAO{
public void getUserDetails(){
String getSql = select u.userId, u.username, a.zipcode from user u, address a where u.addressId = a.addressId;
//no pojo class is now specific to the resultset returned. so we can't map result to pojo object
}
}
now how I should model this with my pojo class as if using String to manage this then concept of object oriented vanishes, also complexity would increase in the future as well. kindly guide!
Update for Further Explanation
We know that we can map same table objects with same pojo class, but when the query is customized and there is a data returned which doesn't map to any specific class then what would be the procedure? i.e. should we make another class? or should we throw that data in a String variable? kindly give some example as well.
For this purpose you can use one of implementation of JPA. But as you want to do it manually I will give you small example.
UPD:
public class User {
private int userId;
private String username;
private Address address; // USE POJO not ID
}
public class Address{
private int addressId;
private String zip;
List<User> users;
}
public User getUserById(Connection con, long userId) {
PreparedStatement stmt;
String query = "select u.user_id, u.user_name, a.id, a.zip from user u, address a where a.address_id = u.id and u.id = ?";
User user = new User();
Address address = new Address;
try {
stmt = con.prepareStatement(query);
stmt.setLong(1, userId);
ResultSet rs = stmt.executeQuery();
address.setId(rs.getInt("id"));
address.setZip(rs.getString("zip");
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("user_name"));
user.setAddressId(rs.getInt("address_id"));
user.setAddress(address); // look here
} catch (SQLException e) {
if (con != null) {
try {
System.err.print("Transaction is being rolled back");
con.rollback();
} catch (SQLException excep) {
}
}
} finally {
if (stmt != null) {
stmt.close();
}
}
return user;
}
You shouldn't do new POJO for that query, you should write normal query. And remember - your object model is main, tables in DB is just a way to save data of your application.
We know that we can map same table objects with same pojo class, but when the query is customized and there is a data returned which doesn't map to any specific class then what would be the procedure? i.e. should we make another class?
JPA dynamic instantiation allows you to define a query with a POJO whose constructor specifies only the fields and types you want from the database.
This will perform a JPA selection which will return a List.
If you need to change the query later and the columns are unchanged, your POJO will still work.
If you change the columns, then also change the POJO accordingly.
NOTE:
You must specify fully qualified package and constructor arguments.
Type User must be a JPA-mapped or JPA-annotated entity class.
The entityManager is in JPA EntityManagerFactory.
TypedQuery<User> q;
String sql = "select new com.stuff.User(
int u.userId, String u.username, String a.zipcode)
from User u, Address a where u.addressId = a.addressId";
List<User> list = entityManager.createQuery(sql).getResultList();
for(User u : list) {
doStuff(u);
}
Dynamic instantiation is also handy when you want to select specified columns, but avoid those columns with large data, such as BLOB types.
For example, maybe you want a list of proxy POJO's which represent the fully populated thing, but are themselves not fully populated.
You present the proxy list, and when the user selects one, then you do another query to get the fully populated object.
Your mileage may vary.
There's many ORM frameworks that can do this including Hibernate, myBatis, JPA and spring-JDBC
spring-jdbc and myBatis give you granular control over the SQL whereas with JPA and Hibernate you are usually abstracted away from the SQL.
I suggest you do some reading and figure out which one you like before rolling your own solution.
Your question:
We know that we can map same table objects with same pojo class,
but when the query is customized and there is a data returned
which doesn't map to any specific class then what would be the procedure?
If you have 100 kinds of SQL which returns different combination of columns, could it be to create 100 different POJOs? The answer is "NO, stop using POJO".
This library qood is designed to solve this problem, you can try it.

How to use Spring jdbc templates (jdbcTemplate or namedParameterJDBCTem) to retrieve values from database

Few days into Spring now. Integrating Spring-JDBC into my web application. I was successfully able to preform CRUD operations on my DB, impressed with boiler-plate code reduction. But I am failing to use the query*() methods provided in NamedParameterJDBCTemplate. Most of the examples on the internet provide the usage of either RowMapper or ResultSetExtractor. Though both uses are fine, it forces me to create classes which have to implement these interfaces. I have to create bean for every type of data I am loading for the DB (or maybe I am mistaken).
Problem arises in code section where I have used something like this:
String query="select username, password from usertable where username=?"
ps=conn.prepareStatement(query);
ps.setString(username);
rs=ps.executeQuery();
if(rs.next()){
String username=rs.getString("username");
String password=rs.getString("password")
//Performs operation on them
}
As these values are not stored in any bean and used directly, I am not able to integrate jdbcTemplate in these kind of situations.
Another situation arises when I am extracting only part of properties present in bean from my database.
Example:
public class MangaBean{
private String author;
private String title;
private String isbn;
private String releaseDate;
private String rating;
//getters and setters
}
Mapper:
public class MangaBeanMapper implements RowMapper<MangaBean>{
#Override
public MangaBean mapRow(ResultSet rs, int arg1) throws SQLException {
MangaBean mb=new MangaBean();
mb.setAuthor(rs.getString("author"));
mb.setTitle(rs.getString("title"));
mb.setIsbn(rs.getString("isbn"));
mb.setReleaseDate(rs.getString("releaseDate"));
mb.setRating(rs.getString("rating"));
return mb;
}
}
The above arrangement runs fine like this:
String query="select * from manga_data where isbn=:isbn"
Map<String, String> paramMap=new HashMap<String, String>();
paramMap.put("isbn", someBean.getIsbn());
return template.query(query, paramMap, new MangaBeanMapper());
However, if I only want to retrieve two/three values from my db, I cannot use the above pattern as it generates a BadSqlGrammarException: releaseDate does not exist in ResultSet . Example :
String query="select title, author where isbn=:isbn"
Map<String, String> paramMap=new HashMap<String, String>();
paramMap.put("isbn", someBean.getIsbn());
return template.query(query, paramMap, new MangaBeanMapper());
Template is an instance of NamedParameterJDBCTemplate. Please advice me solutions for these situations.
The other answers are sensible: you should create a DTO bean, or use the BeanPropertyRowMapper.
But if you want to be able to have more control than the BeanPropertyRowMapper, (or reflection makes it too slow), you can use the
queryForMap
method, which will return you a list of Maps (one per row) with the returned columns as keys. Because you can call get(/* key that is not there */) on a Map without throwing an exception (it will just return null), you can use the same code to populate your object irrespective of which columns you selected.
You don't even need to write your own RowMapper, just use the BeanPropertyRowMapper that spring provides. The way it works is it matches the column names returned to the properties of your bean. Your query has columns that match your bean exactly, if it didn't you would use an as in your select as follows...
-- This query matches a property named matchingName in the bean
select my_column_that doesnt_match as matching_name from mytable;
The BeanPropertyRowMapper should work with both queries you listed.
Typically, yes : for most queries you would create a bean or object to transform the result into. I would suggest that more most cases, that's want you want to do.
However, you can create a RowMapper that maps a result set to a map, instead of a bean, like this. Downside would be be losing the type management of beans, and you'd be relying on your jdbc driver to return the correct type for each column.
As #NimChimpskey has just posted, it's best to create a tiny bean object : but if you really don't want to do that, this is another option.
class SimpleRowMapper implements RowMapper<Map<String, Object>> {
String[] columns;
SimpleRowMapper(String[] columns) {
this.columns = columns;
}
#Override
public Map<String, Object> mapRow(ResultSet resultSet, int i) throws SQLException {
Map<String, Object> rowAsMap = new HashMap<String, Object>();
for (String column : columns) {
rowAsMap.put(column, resultSet.getObject(column));
}
return rowAsMap;
}
}
In yr first example I would just create a DTO Bean/Value object to store them. There is a reason its a commonly implemented pattern, it takes minutes to code and provides many long term benefits.
In your second example, create a second implementation of rowmapper where you don;t set the fields, or supply a null/subsitute value to mangabean where necessary :
#Override
public MangaBean mapRow(ResultSet rs, int arg1) throws SQLException {
MangaBean mb=new MangaBean();
mb.setAuthor(rs.getString("author"));
mb.setTitle(rs.getString("title"));
/* mb.setIsbn("unknown");*/
mb.setReleaseDate("unknown");
mb.setRating(null);
return mb;
}

Categories