Java.Servlet.How can we organize a database connection, provide logging in a servlet?

✅ Problem:

  • You need a database connection in your servlet.
  • You want to log information, warnings, errors (instead of just printing to console).

If you just open a Connection inside every servlet → it’s inefficient and dangerous (resource leaks, no pooling, etc.).

If you just System.out.println() → it’s unprofessional for real systems (no levels, no files, no timestamps).

✅ Solution Overview:

TaskHow
Manage database connectionsUse a Connection Pool (like HikariCP, Tomcat JDBC Pool, etc.)
LoggingUse a logging framework (like SLF4J with Logback or java.util.logging)
Manage connections in servletsUse connection pool + dependency injection or ServletContextListener

✅ Step 1: Organize Database Connections

Instead of opening a new connection every time, you initialize a connection pool once and then borrow connections.

🍀 Easiest Way:

Use connection pooling via Tomcat DataSource + JNDI.

You configure the DataSource in Tomcat’s context.xml:

<Context>
  <Resource name="jdbc/MyDB" 
            auth="Container"
            type="javax.sql.DataSource"
            maxTotal="20"
            maxIdle="10"
            maxWaitMillis="-1"
            username="dbuser"
            password="dbpassword"
            driverClassName="com.mysql.cj.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/mydatabase"/>
</Context>

In your servlet:

import javax.naming.InitialContext;
import javax.naming.Context;
import javax.sql.DataSource;
import java.sql.Connection;

// Inside your servlet
Context initContext = new InitialContext();
DataSource ds = (DataSource) initContext.lookup("java:comp/env/jdbc/MyDB");
Connection conn = ds.getConnection();
// use conn

Benefit:

  • Fast (connections are reused).
  • Safe (no resource leaks if you close properly).
  • Managed (Tomcat controls number of connections).

✅ If you don’t want to use JNDI (for example in a standalone app), use HikariCP connection pool manually:

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydatabase");
config.setUsername("dbuser");
config.setPassword("dbpassword");

HikariDataSource ds = new HikariDataSource(config);

// later: ds.getConnection();

You can initialize this once in a ServletContextListener, so it’s shared between servlets.

✅ Step 2: Logging properly

Forget about System.out.println(). Use SLF4J + Logback (modern combo) or at least java.util.logging.

Example with SLF4J (common standard):

In your servlet:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyServlet extends HttpServlet {
    private static final Logger logger = LoggerFactory.getLogger(MyServlet.class);

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.info("Processing request for {}", request.getRequestURI());
        
        try {
            // db logic
        } catch (Exception e) {
            logger.error("Database error", e);
        }
    }
}

Benefits:

  • INFO, DEBUG, WARN, ERROR levels.
  • Logs can be sent to files, console, remote servers.
  • Can format them easily (timestamps, user IDs, etc.).

✅ Step 3: Where to initialize database pool?

Best practice:

  • Use a ServletContextListener to initialize your database pool when app starts.
  • Store the DataSource into ServletContext attributes.
  • Servlets retrieve it from there.

Example:

Context Listener:

import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
import com.zaxxer.hikari.HikariDataSource;

@WebListener
public class AppContextListener implements ServletContextListener {
    private HikariDataSource ds;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        ds.setUsername("user");
        ds.setPassword("pass");
        
        sce.getServletContext().setAttribute("DataSource", ds);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        if (ds != null) {
            ds.close();
        }
    }
}

Then inside any servlet:

DataSource ds = (DataSource) getServletContext().getAttribute("DataSource");
try (Connection conn = ds.getConnection()) {
    // use conn safely
}

✅ Summary Plan for Professional Servlets:

AreaBest Practice
Database connectionConnection Pool (DataSource)
Connection lifecycleOpen in servlet, close after use (try-with-resources)
LoggingSLF4J + Logback or similar
InitializationUse ServletContextListener
Error handlingCatch and log exceptions properly
Resource closingAlways close Connection, ResultSet, PreparedStatement

🌟 Visual Diagram:

[App Startup]
    ↓
[ContextListener] → creates ConnectionPool (DataSource)
    ↓
[Servlets] → get DataSource → get Connection → work → close Connection
    ↓
[Logging] → all events, errors, debug info
This entry was posted in Без рубрики. Bookmark the permalink.