How do I generate the connection to the database between postgres and Java?
You have two ways of doing it. The first thing is to open the connection manually. This, in turn, has two ways, depending on whether the driver connecting to your database supports JDBC 4 or not.
If does not support JDBC 4, you should run the following:
public Connection getConnection() throws Exception {
String urlDatabase = "jdbc:postgresql://localhost:5432/midatabase";
Class.forName("org.postgresql.Driver"); //cargar el driver manualmente
conn = DriverManager.getConnection(urlDatabase, "usuario", "password");
}
If the driver supports JDBC 4 then you no longer need to load the class, so the code is reduced:
public Connection getConnection() throws Exception {
String urlDatabase = "jdbc:postgresql://localhost:5432/midatabase";
conn = DriverManager.getConnection(urlDatabase, "usuario", "password");
}
This first form is for small console, desktop, personal or "toy" applications. For applications that you are going to send to production, that you intend to sell, that should be more professional, you should not use the first form, since each time you run DriverManager#getConnection
a physical connection to the engine is opened of database (expensive operation) and each time the connection is closed via Connection#close
this physical connection is closed. Executing this operation multiple times affects the performance of the application. Therefore, the solution is to use a pool of connections through the interface DataSource
Beware, there are other libraries that already implement this interface and store the connections so you do not need to reinvent the wheel. To achieve this, you use one of two options:
If your application or applications are going to reside in an application server (JBoss, Wildfly, WebLogic, IBM Was, etc.) or a servlet container (Tomcat, Jersey, etc.), you can configure a pool of connections and then get it via JNDI. The configuration of the connection pool depends on each application server or servlet container, but in your Java code you would get the connection in this way:
public Connection getConnection() throws Exception {
final String DATASOURCE_CONTEXT = "..."; //nombre de tu pool de conexiones
Context initialContext = new InitialContext();
DataSource datasource = (DataSource)initialContext.lookup(DATASOURCE_CONTEXT);
return datasource.getConnection();
}
If your application runs on console, on desktop or you just do not like to depend on configuring the pool of connections in the container, then you can use a DataSource
. The implementation of this interface will open a group of physical connections to the databases and keep them open while your application keeps running, so you can reuse the connections in multiple operations. This increases the performance of your application.
There are several libraries that provide this functionality such as HikariCP, C3PO, Apache Commons DBCP, etc. Basically, they provide a class that implements the DataSource
interface so that you end up calling this instance and getting the connection there directly. Here is an example with HikariCP (personally, my favorite). The configuration is done as follows:
public DataSource getDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/midatabase");
config.setUsername("usuario");
config.setPassword("password");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
HikariDataSource ds = new HikariDataSource(config);
}
public Connection getConnection(DataSource dataSource) {
return dataSource.getConnection();
}
The above design allows: a method to create the DataSource
and the client of that class to ensure that it is created only once. Then, the method below allows you to use an instance of DataSource
to get the connection. An example using as base the previous code and using singleton would be:
//los enum en Java son singleton por defecto
public enum ConexionesBaseDatos {
private final DataSource dataSource;
POSTGRES;
private ConexionesBaseDatos() {
dataSource = getDataSource("jdbc:postgresql://localhost:5432/midatabase", "usuario", "password");
}
private DataSource getDataSource(String constr, String usuario, String password) {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(constr);
config.setUsername(usuario);
config.setPassword(password);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
HikariDataSource ds = new HikariDataSource(config);
}
public Connection getConnection() {
return dataSource.getConnection();
}
}
Keep in mind that this design is just an example. There may be other ways to achieve this, and using dependency injection frameworks such as Spring or Guice, a different and more flexible design is achieved.
IMPORTANT
Whichever method you choose to get your instance of Connection
, ALWAYS you must close the used connection, that is, ALWAYS you must call the Connection#close
method. An example:
Connection conn = null;
try {
conn = getConnection(); //utilizando cualquiera de los métodos de arriba
//usar la variable con...
} finally {
if (conn != null) {
conn.close();
}
}
Or using try-with-resources
from Java 7, where the block try
can automatically call the close
method for you, it would be like this:
try (Connection conn = getConnection()) {
//usar la variable conn...
}
When Connection#close
is called from the first method, the physical connection to the database is closed. When called from the second method, the physical connection returns to the connection pool, enabling the connection to be reused in subsequent calls.
How do I generate the queries so that when I select the save info button it is saved in the postgres database?
You have to generate the queries manually. Java and JDBC do not know the structure of your table and do not know how the fields should be inserted. For this, if you are going to work with JDBC, you can use the following design:
public class EntidadDao {
public Connection conn;
public EntidadDao(Connection conn) {
this.conn = conn;
}
public void guardaEntidad(Entidad entidad) {
String sql = "INSERT INTO entidad (nombre, description) VALUES (?, ?)";
try (PreparedStatement pstmt = con.prepareStatement(sql) {
pstmt.setString(1, entidad.getNombre());
pstmt.setString(2, entidad.getDescripcion());
pstmt.executeUpdate();
} catch (Exception e) {
//lanzar RuntimeException para tener código más limpio
throw new RuntimeException("Error al guardar entidad.", e);
}
}
}
public class EntidadServicio {
public void guardaEntidad(Entidad entidad) {
Connection conn = null;
try (conn = ConexionesBaseDatos.POSTGRES.getConnection()) {
//iniciar una transacción, buena práctica
conn.setAutoCommit(false);
//abrir un bloque de manejo de excepciones
try {
//creas todos los Daos con la misma conexión para manejar
//la misma transacción
EntidadDao entidadDao = new EntidadDao(conn);
entidadDao.guardaEntidad(entidad);
//si todo funcionó sin problemas, se realiza el commit
conn.commit();
} catch (Exception e) {
//si hubo algún problema, se realiza un rollback
conn.rollback();
}
//se cierra la transacción
conn.setAutoCommit(true);
}
}
}
Remember that the design presented here is basic, it should serve as a basis to create a design more suited to your application. Also, if you use dependency injection frameworks such as Spring or Guice, you can achieve a more decoupled design between classes.
There are frameworks like Hibernate and JPA that can create the scripts of INSERT
, UPDATE
, SELECT
for you according to the structure of the table, but it is too much information for this answer.