In short
Advanced Java (Jakarta EE web tier) is the standard Java stack for server-side web applications: JDBC talks to relational databases, Servlets handle HTTP requests inside a container such as Apache Tomcat, and JSP generates the HTML response. It matters because it is the layer every higher framework sits on - Spring MVC is a servlet, Hibernate is JDBC underneath - so interviewers test it to check whether a candidate understands what the framework is doing. It is a full university paper in MCA/BCA/B.Tech CS (AICTE model curriculum, UGC CBCS) and appears in UGC-NET Computer Science; GATE CS does not examine it, but almost every Indian IT service recruiter (TCS, Infosys, Wipro, Cognizant, Capgemini, HCLTech, LTIMindtree, Accenture India) asks servlet lifecycle, PreparedStatement and session tracking in the technical round. Legacy and government Java applications across banking, insurance and NIC-built portals still run on exactly this stack.
Explained
JDBC architecture and drivers
- JDBC (Java Database Connectivity) is a Java API (
java.sql,javax.sql) of interfaces; the database vendor supplies the implementation (the driver). The application codes against the interface, so the same code runs on MySQL, PostgreSQL or Oracle. - DriverManager is the old factory for connections; DataSource (
javax.sql.DataSource) is the preferred one because it supports connection pooling and distributed transactions. - Driver types:
- Type 1 - JDBC-ODBC bridge: translates JDBC to ODBC; platform-dependent, obsolete (the bundled bridge was removed in Java 8).
- Type 2 - Native API: Java calls a vendor C/C++ client library (e.g. Oracle OCI); fast but needs the client installed on every machine.
- Type 3 - Network protocol: driver talks to a middleware server which talks to the database; useful through firewalls, extra hop.
- Type 4 - Thin / pure Java: speaks the database's wire protocol directly; platform-independent, no client install - the only type used in practice (
mysql-connector-j,ojdbc11,postgresql).
- Since JDBC 4.0 no
Class.forName()is needed: the driver JAR declares itself inMETA-INF/services/java.sql.Driverand is auto-loaded by the service-provider mechanism. Exam answers still expect you to knowClass.forName("com.mysql.cj.jdbc.Driver"). - Core interfaces:
Driver,Connection,Statement,PreparedStatement,CallableStatement,ResultSet,ResultSetMetaData,DatabaseMetaData,SQLException,Blob,Clob,RowSet.
JDBC programming: the seven steps, statements and result sets
- Load/register the driver (optional since JDBC 4.0). 2. Get a
Connectionvia a URL, e.g.jdbc:mysql://localhost:3306/placement?useSSL=false. 3. Create a statement. 4. Execute the SQL. 5. Process theResultSet. 6. CloseResultSet, statement, connection - use try-with-resources so closing happens even on exception. 7. HandleSQLException(getMessage(),getSQLState(),getErrorCode()). - Execution methods:
executeQuery()returns aResultSet(SELECT);executeUpdate()returns anintrow count (INSERT/UPDATE/DELETE/DDL);execute()returnsbooleanwhen the statement type is unknown;executeLargeUpdate()returnslong. - Statement sends raw SQL - recompiled every time, and string-concatenated values make it vulnerable to SQL injection.
- PreparedStatement is pre-compiled with
?placeholders set bysetInt,setString,setDate,setNull; it is faster on repeated calls, handles quotes and special characters, and is the standard defence against SQL injection. Placeholders are 1-based. - CallableStatement calls stored procedures:
{call get_cgpa(?, ?)}, withregisterOutParameter()for OUT/INOUT parameters. - ResultSet navigation:
next(), and for scrollable setsprevious(),first(),last(),absolute(n),relative(n). Columns are read by index (1-based) or by label -getString("name"). - ResultSet types:
TYPE_FORWARD_ONLY(default),TYPE_SCROLL_INSENSITIVE(scrollable, does not see others' committed changes),TYPE_SCROLL_SENSITIVE. Concurrency:CONCUR_READ_ONLY(default) orCONCUR_UPDATABLE(supportsupdateRow(),insertRow(),deleteRow()). - Metadata:
ResultSetMetaDatagivesgetColumnCount(),getColumnName(),getColumnTypeName()- used to render a generic table;DatabaseMetaDatagives product name, version, supported features. - LOBs:
Blobfor binary (images, PDFs) andClobfor large text; alsosetBinaryStream()for streaming large files. - RowSet (
javax.sql.rowset): aResultSetthat is also a JavaBean -CachedRowSetis disconnected and serialisable, so it can be passed between tiers after the connection is closed.
Transactions, batching and pooling
- A connection is auto-commit true by default - every statement commits. For a multi-statement unit of work:
setAutoCommit(false)→ statements →commit(), orrollback()in the catch block.Savepoint sp = con.setSavepoint()androllback(sp)give partial rollback. - ACID - Atomicity, Consistency, Isolation, Durability - is what the transaction guarantees. Isolation is set with
con.setTransactionIsolation(...).
| Isolation level | Dirty read | Non-repeatable read | Phantom read |
|---|---|---|---|
| TRANSACTION_READ_UNCOMMITTED | possible | possible | possible |
| TRANSACTION_READ_COMMITTED | prevented | possible | possible |
| TRANSACTION_REPEATABLE_READ | prevented | prevented | possible |
| TRANSACTION_SERIALIZABLE | prevented | prevented | prevented |
- Defaults differ by database - InnoDB/MySQL defaults to REPEATABLE READ, PostgreSQL and Oracle to READ COMMITTED;
TRANSACTION_NONEmeans no transaction support. - Batch update:
addBatch()repeatedly thenexecuteBatch()sends many statements in one network round trip; returns anint[]of counts, throwsBatchUpdateExceptionon failure. Combine withrewriteBatchedStatements=trueon MySQL for real gains. - Connection pooling: opening a TCP connection plus authentication costs tens of milliseconds, so a pool (HikariCP, Tomcat JDBC, Apache DBCP, or a container
Resourceincontext.xml) keeps connections open and lends them out.connection.close()on a pooled connection returns it to the pool - it does not close the socket. Leaking connections (not closing) exhausts the pool and hangs the application. - Fetch size (
setFetchSize(n)) controls rows per round trip;setMaxRows()caps rows returned. For huge result sets, stream row by row instead of loading all into memory.
Servlets: lifecycle, API and configuration
- A servlet is a Java class that runs inside a web container and handles requests over a protocol - normally HTTP. It replaced CGI, where each request forked a new OS process; a servlet is a single object serving many requests in separate threads, so it is far lighter, but its instance fields are shared and must be treated as not thread-safe.
- Hierarchy:
Servlet(interface) →GenericServlet(protocol-independent, implements all butservice()) →HttpServlet(implementsservice()to dispatch by HTTP method). You overridedoGet,doPost,doPut,doDelete,doHead; neverservice()in normal code. - Lifecycle: (1) class loaded on first request or at startup if
<load-on-startup>is set; (2) instantiated once; (3)init(ServletConfig)called once for one-time setup; (4)service()called per request, concurrently; (5)destroy()called once before the container removes the instance. Reloading the application creates a fresh instance. - ServletConfig vs ServletContext:
ServletConfigholds init parameters of one servlet (getInitParameter);ServletContextis one per web application, holds context init parameters, application-scope attributes,getRealPath(),getResourceAsStream(),log(), and is the usual home for shared objects like aDataSource. - Request:
getParameter,getParameterValues(checkboxes/multi-select),getParameterMap,getHeader,getCookies,getSession,getRemoteAddr,getPartfor uploads (@MultipartConfig),setAttributefor passing data to a forwarded page. - Response:
setContentType("text/html;charset=UTF-8"),getWriter()(text) orgetOutputStream()(binary - never both),setHeader,addCookie,sendRedirect,sendError,setStatus. - Deployment: either the deployment descriptor
WEB-INF/web.xml(<servlet>,<servlet-name>,<servlet-class>,<servlet-mapping>,<url-pattern>,<welcome-file-list>,<error-page>,<session-config>) or annotations since Servlet 3.0 -@WebServlet("/login"),@WebFilter,@WebListener. web.xml wins over annotations when both exist;metadata-complete="true"disables annotation scanning. - WAR structure: application root (JSPs, static files) +
WEB-INF/web.xml+WEB-INF/classes(compiled classes) +WEB-INF/lib(JARs). Anything underWEB-INFis not directly reachable by a browser - the standard place to hide JSPs behind a controller. - Forward vs redirect:
RequestDispatcher.forward()is server-side, one request, URL unchanged, request attributes survive, target must be in the same application;include()embeds the target's output.response.sendRedirect()sends 302 with aLocationheader, the browser makes a second request, URL changes, attributes are lost, any URL allowed - used after a POST (POST-redirect-GET) to prevent duplicate submission. - Filters (
doFilter(req, res, chain)) intercept requests and responses for cross-cutting work - authentication checks, logging, compression, encoding, CORS; chained in the order of<filter-mapping>in web.xml (annotation order is not guaranteed). - Listeners react to container events:
ServletContextListener(contextInitialized/contextDestroyed- start and stop a pool),HttpSessionListener(count live users),ServletRequestListener,*AttributeListener. - Asynchronous servlets (Servlet 3.0):
req.startAsync()releases the container thread while a slow task runs, so long waits do not consume the thread pool. Servlet 4.0 added HTTP/2 server push; Servlet 6.x is current in Jakarta EE 10/11. - Namespace: from **Jakarta EE 9 the packages moved
javax.servlet→jakarta.servlet** - Tomcat 9 and earlier usejavax, Tomcat 10+ usejakarta. Mixing them is the commonest build failure for students today; university question papers still writejavax.
Session tracking
HTTP is stateless, so state between requests must be carried explicitly. Four techniques:
- Cookies - small name-value pairs stored by the browser;
new Cookie("id", v),setMaxAge(seconds)(negative = session cookie, 0 = delete),setHttpOnly(true),setSecure(true). Fail if the user blocks cookies. - Hidden form fields -
<input type="hidden">; works only across form submissions, visible in page source. - URL rewriting - append the id to every link:
response.encodeURL("next.jsp")adds;jsessionid=...only when cookies are unavailable. Session ids in URLs leak through logs and referrers. - HttpSession - the container's own mechanism and the one to use:
request.getSession()creates a session if absent,getSession(false)returnsnullif absent (the correct check for "is the user logged in?"). API:setAttribute,getAttribute,removeAttribute,getId,setMaxInactiveInterval(sec),invalidate()on logout. Default timeout in Tomcat is 30 minutes, set in<session-config><session-timeout>(in minutes). - The session lives in server memory, keyed by the JSESSIONID cookie. In a cluster you need sticky sessions or session replication; stateless token schemes are covered under a separate topic.
- Objects kept in a session should be
Serializableso the container can persist or replicate them.
JSP: lifecycle, syntax and MVC
- A JSP is an HTML page with embedded Java, which the container translates into a servlet source file, compiles, loads and runs. So JSP is a servlet - the difference is who writes the Java. Translation happens once, on first request or when the file changes (
.javaand.classappear under Tomcat'sworkdirectory). - Lifecycle: translation → compilation → class loading → instantiation →
jspInit()→_jspService()per request →jspDestroy(). You may overridejspInit/jspDestroybut never_jspService. - Scripting elements:
<%! int count; %>declaration (becomes an instance field - shared, hence a thread-safety trap);<% ... %>scriptlet (code inside_jspService);<%= expr %>expression (printed);<%-- --%>JSP comment (not sent to the browser, unlike<!-- -->). - Directives:
<%@ page language="java" contentType="text/html;charset=UTF-8" import="java.util.*" session="true" errorPage="err.jsp" isErrorPage="false" buffer="8kb" isELIgnored="false" %>;<%@ include file="header.jsp" %>merges at translation time (static);<%@ taglib uri="..." prefix="c" %>declares a tag library. - Nine implicit objects:
request(HttpServletRequest),response,out(JspWriter),session,application(ServletContext),config,pageContext,page(this),exception(only whenisErrorPage="true"). - Standard actions:
<jsp:include page="x.jsp"/>includes at request time (dynamic, separate request dispatch);<jsp:forward/>;<jsp:param/>;<jsp:useBean id="s" class="dao.Student" scope="session"/>with<jsp:setProperty>/<jsp:getProperty>. - Four scopes: page (this page only) < request (across forward/include) < session (one user) < application (all users).
- Expression Language (EL):
${student.name},${param.email},${sessionScope.user},${empty list},${a + b}- calls getters without scriptlets and searches page→request→session→application scope. Implicit EL objects includeparam,paramValues,header,cookie,initParam,pageContext. - JSTL replaces scriptlets with tags: core (
c:if,c:choose/when/otherwise,c:forEach,c:set,c:out- which escapes HTML and so prevents XSS,c:url,c:redirect), fmt (fmt:formatNumber,fmt:formatDate, i18n bundles), fn (string functions), and sql (demo only - never in production code). Custom tags extendSimpleTagSupportand are described in a.tldfile. - Model 1 vs Model 2: Model 1 puts logic, data access and presentation in the JSP - fine only for a tiny page. Model 2 = MVC: a servlet is the controller, a JavaBean/POJO plus a DAO is the model, and the JSP is the view holding no Java, only EL and JSTL. This is the architecture every exam answer and interview expects, and the pattern Spring MVC later standardised.
- DAO pattern: one class per table/entity encapsulating all SQL, returning POJOs; keeps the servlet free of JDBC and makes the database swappable.
- Current practice: JSP is still specified in syllabi and maintained in legacy Indian enterprise systems, but new Java projects use Spring Boot with Thymeleaf or a JSON API plus a JavaScript front end. The servlet and JDBC layers underneath remain exactly as described.
Key points
- JDBC - interface-based API; the vendor's Type 4 thin driver supplies the implementation.
- Type 4 driver - pure Java, speaks the DB wire protocol; the only type in real use.
- PreparedStatement - pre-compiled, parameterised with 1-based
?, prevents SQL injection, faster on repeats. - CallableStatement - invokes stored procedures, needs
registerOutParameterfor OUT values. - executeQuery / executeUpdate / execute - ResultSet / row count / boolean.
- try-with-resources - closes
Connection,Statement,ResultSeteven on exception; closing a pooled connection returns it to the pool. - Transaction -
setAutoCommit(false), thencommit()orrollback();Savepointfor partial rollback. - Isolation levels - READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE trade concurrency for consistency.
- Batch update -
addBatch/executeBatchcuts network round trips by one to two orders of magnitude. - Servlet lifecycle - one instance,
init()once,service()per request on many threads,destroy()once. - Thread safety - servlet instance variables are shared; keep per-request state in local variables.
- ServletConfig vs ServletContext - per-servlet parameters vs one-per-application shared state.
- forward vs sendRedirect - one server-side request, attributes kept, same app vs new browser request, 302, URL changes.
- HttpSession + JSESSIONID - server-side state keyed by a cookie, with URL rewriting as fallback;
getSession(false)to test an existing session. - Filters and listeners - cross-cutting interception and container lifecycle hooks declared by annotation or web.xml.
- JSP is a servlet - translated, compiled, then
jspInit→_jspService→jspDestroy; nine implicit objects. - include directive vs jsp:include - static merge at translation time vs dynamic dispatch at request time.
- EL + JSTL + MVC Model 2 - no Java in the view; servlet controller, POJO/DAO model, JSP view.
- Jakarta namespace -
javax.servletup to Tomcat 9,jakarta.servletfrom Tomcat 10 / Jakarta EE 9.
Formulas and examples
Container capacity (req/s) = maxThreads / mean response time (s) - the ceiling before requests queue.
Concurrent sessions ≈ login rate (logins/s) × session timeout (s); session memory = sessions × bytes per session.
Batch time ≈ (rows / batch size) × (RTT + batch size × per-row server time).
Round trips for a result set ≈ ceil(rows / fetchSize); network time = round trips × RTT.
- Connection pool sizing. A placement portal serves 200 database queries per second; each query holds a connection for 25 ms.
- N = 200 × 0.025 = 5 connections busy on average; configure about 10 for bursts.
- A common error is to set the pool to 200 "because there are 200 threads": 200 open connections multiply database memory and context switching while 5 do the work.
- Batch insert versus row-by-row. Load 10,000 student records; network RTT to the database is 2 ms, server-side insert cost 0.1 ms per row.
- Row by row: 10,000 × (2 + 0.1) = 21,000 ms = 21.0 s.
- Batch of 500: 10,000/500 = 20 batches; each batch = 2 + 500 × 0.1 = 52 ms → 20 × 52 = 1,040 ms = 1.04 s.
- Speed-up = 21,000/1,040 ≈ 20×, almost all of it from eliminated round trips.
- Fetch size. A report reads 50,000 rows with RTT 2 ms.
- Default fetchSize 10 → 5,000 round trips × 2 ms = 10 s of pure network wait.
setFetchSize(500)→ 100 round trips × 2 ms = 0.2 s; memory cost is only 500 rows buffered.
- Session memory. 3 logins per second, session timeout 30 min (1,800 s), 12 KB of attributes per session.
- Live sessions ≈ 3 × 1,800 = 5,400; memory = 5,400 × 12 KB = 64,800 KB ≈ 63 MB of heap just for sessions.
- Cutting the timeout to 15 min halves it to about 32 MB - which is why
<session-timeout>is a capacity decision, not a cosmetic one.
- Thread pool ceiling. Tomcat
maxThreads=200, mean response time 150 ms → capacity = 200/0.150 ≈ 1,333 req/s. At 1,600 req/s the accept queue grows without limit and users see timeouts; either cut response time (indexes, caching) or usestartAsync()so threads are not parked on I/O.
// DAO using try-with-resources, PreparedStatement and a container DataSource
public List<Student> findByBranch(String branch) throws SQLException {
String sql = "SELECT roll_no, name, cgpa FROM student WHERE branch = ? ORDER BY cgpa DESC";
List<Student> list = new ArrayList<>();
try (Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setString(1, branch); // 1-based, injection-safe
ps.setFetchSize(500);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next())
list.add(new Student(rs.getString("roll_no"),
rs.getString("name"),
rs.getBigDecimal("cgpa")));
}
}
return list; // connection returns to the pool here
}
// Transaction: two updates must succeed together
con.setAutoCommit(false);
try { debit.executeUpdate(); credit.executeUpdate(); con.commit(); }
catch (SQLException e) { con.rollback(); throw e; }
finally { con.setAutoCommit(true); }
// MVC Model 2 controller (Jakarta namespace, Tomcat 10+)
@WebServlet("/students")
public class StudentServlet extends HttpServlet {
private StudentDAO dao;
@Override public void init() { dao = new StudentDAO(lookupDataSource()); }
@Override protected void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
if (req.getSession(false) == null) { res.sendRedirect("login.jsp"); return; }
req.setAttribute("students", dao.findByBranch(req.getParameter("branch")));
req.getRequestDispatcher("/WEB-INF/views/students.jsp").forward(req, res);
}
}
<%-- View: no Java, only EL and JSTL; c:out escapes HTML --%>
<%@ taglib uri="jakarta.tags.core" prefix="c" %>
<table>
<c:forEach var="s" items="${students}">
<tr><td><c:out value="${s.rollNo}"/></td>
<td><c:out value="${s.name}"/></td>
<td>${s.cgpa}</td></tr>
</c:forEach>
<c:if test="${empty students}"><tr><td>No records</td></tr></c:if>
</table>
| Aspect | Statement | PreparedStatement | CallableStatement |
|---|---|---|---|
| SQL | Built as a string | Pre-compiled with ? | {call proc(?,?)} |
| Injection risk | High | Safe if parameters are bound | Safe |
| Repeated execution | Recompiled each time | Compiled once, reused | Runs in the DB |
| Typical use | One-off DDL | Almost everything | Legacy stored procedures |
| forward() | sendRedirect() | |
|---|---|---|
| Who acts | Container, server-side | Browser, after 302 |
| Requests | One | Two |
| URL in address bar | Unchanged | Changes |
| Request attributes | Preserved | Lost (use session or query string) |
| Target | Same web application | Any URL |
| Servlet | JSP | |
|---|---|---|
| Written as | Java class | HTML page with tags |
| Strength | Control logic, flow | Presentation |
| Change requires | Recompile and redeploy | Container re-translates automatically |
| Role in MVC | Controller | View |
Where it is used
- Indian IT services and captives - TCS, Infosys, Wipro, Cognizant, Capgemini, HCLTech and LTIMindtree maintain large volumes of servlet/JSP/JDBC code for banking, insurance and telecom clients; maintenance and migration projects are a steady entry-level hiring stream.
- Banking and financial back ends - core banking portals, net-banking channels and payment switches built on Java EE application servers (WebLogic, WebSphere, JBoss/WildFly, Tomcat) with JDBC to Oracle or DB2.
- Government and PSU portals - NIC and state e-governance applications (examination results, land records, tenders, recruitment portals) are commonly Java web applications on Tomcat with JDBC to PostgreSQL or Oracle.
- University and campus systems - ERP, admission, attendance and placement portals; also the standard MCA/BCA mini-project and lab stack (Tomcat + MySQL + JDBC + JSP).
- Job roles - Java Backend Developer, Java Full Stack Developer, Application Support Engineer, Oracle/Java migration consultant; JDBC and servlet internals are also tested for Spring Boot roles.
- Foundation layer - Spring's
DispatcherServlet, Struts, JSF and Hibernate/JPA all sit on servlets and JDBC, so this knowledge transfers directly to modern frameworks.
Interview questions
- Q: Why is PreparedStatement preferred over Statement? A: It is pre-compiled so repeated executions are faster, and parameters are bound rather than concatenated, which prevents SQL injection and handles quotes, dates and nulls correctly.
- Q: How many times are
init(),service()anddestroy()called? A:init()once per servlet instance,service()once per request (concurrently on many threads),destroy()once before the instance is removed. - Q: Are servlets thread-safe? A: No - one instance serves all requests, so instance and static fields are shared; keep request state in local variables and avoid
SingleThreadModel, which is deprecated and does not scale. - Q: Difference between
ServletConfigandServletContext? A:ServletConfigcarries init parameters for a single servlet;ServletContextis one object per web application used for application-wide parameters, shared attributes and resources. - Q: When would you use
sendRedirect()instead offorward()? A: When the target is outside the application, or after a successful POST (POST-redirect-GET) so a browser refresh does not resubmit the form. - Q: How does the container track a session without cookies? A: By URL rewriting -
response.encodeURL()appends;jsessionid=...to links when the browser does not return the cookie. - Q: Is JSP faster than a servlet? A: Neither; a JSP is translated into a servlet and compiled once, so after the first request the performance is the same - only the first request pays translation cost.
- Q: Difference between the include directive and
<jsp:include>? A: The directive merges the file at translation time into one servlet (static, sees the page's variables); the action dispatches to the resource at request time, so changes are picked up and parameters can be passed. - Q: What happens if you forget to close a JDBC connection taken from a pool? A: It is never returned, the pool is gradually exhausted and later requests block or time out - a classic production leak, avoided by try-with-resources.
- Q: What does
request.getSession(false)return and why use it? A: The existing session ornull; it avoids creating a new session when you only want to check whether the user is already logged in. - Q: How do you insert 1 lakh rows efficiently? A: Turn off auto-commit, use a
PreparedStatementwithaddBatch()in chunks of a few hundred to a few thousand,executeBatch(), then commit - this removes per-row round trips and per-row commits. - Q: Why does code compiled against
javax.servletfail on Tomcat 10? A: Jakarta EE 9 renamed the packages tojakarta.servlet; the old classes are absent, so you must recompile against the Jakarta API or run on Tomcat 9. - Q: Where should JSPs be placed in an MVC application and why? A: Under
WEB-INF/views, because the container refuses direct browser access toWEB-INF, forcing every request through the controller servlet.
Common mistakes
- Building SQL by string concatenation (
"... WHERE id='" + id + "'"), creating an injection hole, and then claiming "I validated the input". - Treating JDBC indexes as 0-based -
setString(0, ...)orgetString(0)throws; they start at 1. - Keeping per-user data in a servlet instance field or a JSP declaration (
<%! %>), so one user sees another's data under concurrency. - Forgetting
setAutoCommit(false)and then expectingrollback()to undo anything. - Calling
sendRedirect()after already writing to the response, or using bothgetWriter()andgetOutputStream()-IllegalStateException. - Expecting request attributes to survive a redirect, or writing code after
forward()/sendRedirect()without returning from the method. - Writing
<session-timeout>in seconds (it is minutes) andsetMaxInactiveInterval()in minutes (it is seconds). - Filling JSPs with scriptlets and JDBC calls instead of EL, JSTL and a DAO - marked down in exams and rejected in code review.
Related topics
Spring Boot and microservices development · REST APIs · Authentication and authorisation: sessions, OAuth and JWT · Database management systems and SQL · Hibernate/JPA and ORM · Web servers, application servers and deployment (Tomcat, WAR)