目录
Servlet对象的工作原理及其生命周期、service()方法
Servlet
Servlet简介
- Servlet是使用Java语言编写的服务器端程序,可以像JSP一样生成动态的WEB页。
- Servlet主要运行在服务器端,并由服务器调用执行,是一种按照Servlet标准开发的类。
- Servlet采用了多线程的处理方式,并保留了Java的可移植性特点,使得Servlet更易使用且功能更加强大。
什么是Servlet?
Servlet是一个Java编程语言中的接口,主要用于扩展服务器的功能。Servlet可以用来处理HTTP请求,并返回响应给客户端。它们常用于构建动态Web应用程序。
import javax.servlet.*;
import java.io.*;
public class HelloWorldServlet extends GenericServlet {
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
// 设置响应内容类型为文本/html
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("<h1>Hello, World!</h1>");
out.println("</body>");
out.println("</html>");
}
}
Servlet生命周期
Servlet的生命周期包括加载、初始化、服务、销毁四个阶段。
- 加载:当服务器启动或者第一次接收到对某个Servlet的请求时,会加载该Servlet。
- 初始化:加载完成后,服务器会调用Servlet的
init()
方法进行初始化操作。 - 服务:当服务器接收到客户端的请求后,会调用Servlet的
service()
方法处理请求并产生响应。 - 销毁:当服务器关闭或者Servlet不再使用时,服务器会调用Servlet的
destroy()
方法释放资源。
多线程处理
由于Servlet是在服务器端运行的,所以它可以同时处理多个客户端的请求。这意味着Servlet必须能够处理并发情况,因此Servlet默认就是线程安全的。
import javax.servlet.*;
import java.util.concurrent.atomic.AtomicInteger;
public class CounterServlet extends HttpServlet {
private AtomicInteger counter = new AtomicInteger(0);
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int currentCount = counter.incrementAndGet();
resp.getWriter().println("Current count is " + currentCount);
}
}
Servlet处理的基本流程
- 客户端(通常是Web浏览器)通过HTTP协议提出请求。
- Web服务器接收该请求并将它转发给相应的Servlet。
- 如果Servlet尚未加载,Web服务器将其加载到Java虚拟机并执行。
- Servlet接收HTTP请求并执行某些处理。
- Servlet生成响应内容并将其传回给服务器。
- 服务器将从Servlet收到的响应返回给客户端。
import javax.servlet.*;
import java.io.*;
public class HelloServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response)
throws ServletException, IOException {
// 设置响应内容类型为文本/html
response.setContentType("text/html");
// 获取输出流
PrintWriter out = response.getWriter();
// 输出响应内容
out.println("<html>");
out.println("<body>");
out.println("<h1>Hello, Servlet</h1>");
out.println("</body>");
out.println("</html>");
}
}
为了使这个Servlet能够在服务器上运行,我们需要在Web应用的部署描述符(通常为web.xml
)中配置它
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
Servlet程序实现
在整个Servlet程序之中最重要的就是Servlet接口,在此接口下定义了一个GenericServlet的子类,但是一般不会直接继承此类,而是根据所使用的协议选择GenericServlet的子类继承,例如:现在是采用HTTP协议处理的,所以一般而言当需要使用HTTP协议操作时用户自定义的Servlet类都要继承HttpServlet类。
Servlet
接口:这是所有Servlet的基础,定义了Servlet的核心行为。GenericServlet
:这是一个抽象类,实现了Servlet
接口,提供了通用的Servlet功能,但一般不直接使用。HttpServlet
:这是GenericServlet
的一个子类,专门针对HTTP协议进行了优化,大部分情况下,用户自定义的Servlet都会继承此类。- 用户自定义Servlet:在此基础上,我们可以根据需求创建自己的Servlet类。
如何实现一个简单的Servlet:
- 编写一个Servlet对象的类意味着要编写一个特殊的类,这个特殊类是
javax.servlet.http.HttpServlet
的子类。 HttpServlet
类实现了Servlet
接口,包含了响应用户请求的方法。HttpServlet
的子类被称为一个Servlet类。
首先,你需要导入必要的包:
import javax.servlet.*;
import java.io.*;
然后,你可以创建一个继承自HttpServlet
的类,比如MyServlet
public class MyServlet extends HttpServlet {
...
}
接下来,你可能想要覆盖doGet
或doPost
方法,因为它们分别对应HTTP的GET和POST请求
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 这里处理GET请求
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 这里处理POST请求
}
在这些方法中,你可以读取请求数据,处理业务逻辑,然后生成响应。例如,你可以这样处理GET请求:
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应内容类型为文本/html
response.setContentType("text/html");
// 获取输出流
PrintWriter out = response.getWriter();
// 输出响应内容
out.println("<html>");
out.println("<body>");
out.println("<h1>Hello, Servlet</h1>");
out.println("</body>");
out.println("</html>");
}
为了让服务器知道你的Servlet,你需要在web.xml
文件中配置它
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.example.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>
总结一下,Servlet程序实现的基本步骤如下:
- 创建一个继承自
HttpServlet
的类。 - 覆盖
doGet
或doPost
方法,处理HTTP请求。 - 在
web.xml
中配置Servlet,指定其名称和映射路径。
Servlet对象的工作原理及其生命周期、service()
方法
工作原理:
- Servlet对象由Tomcat服务器负责管理,Tomcat服务器通过读取
web.xml
来创建并运行Servlet对象。 - Servlet对象有三个重要的生命周期方法:
init()
,service()
和destroy()
。
生命周期:
- 初始化:当一个Servlet被实例化之后,容器将调用
init()
方法初始化这个对象,初始化是为了让Servlet对象在处理客户端请求前完成一些初始化的工作,例如建立数据库连接、读取资源文件信息等。如果初始化失败,则此Servlet将被直接卸载。 - 处理服务:当有请求提交时,Servlet将调用
service()
方法(doGet()
或doPost()
)进行处理,在service()
方法中,Servlet可以通过ServletRequest
接收客户的请求,也可以利用ServletResponse
设置响应信息。 - 销毁:当WEB容器关闭或者检测到一个Servlet要从容器中被删除时,会自动调用destroy()方法,以便让该实例释放掉所占用的资源。
- 卸载:当一个Servlet调用完destroy()方法后,此实例将等待被垃圾收集器所回收,当要再次使用此Servlet的时候,会重新调用init()方法初始化
service()
方法
service()
方法是一个公共的void方法,接受HttpServletRequest
和HttpServletResponse
作为参数,抛出IOException
和ServletException
异常。- 当Servlet对象创建和初始化后,该对象就调用
service()
方法来处理用户的请求并返回响应。 - 不同的客户请求该Servlet对象时,服务器将启动一个新的线程,在该新线程中调用
service()
方法响应客户的需求。即每个客户的每次请求都导致service()
方法被执行,调用过程在不同的线程中,互不干扰。
首先,你需要导入必要的包
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
然后,你可以创建一个继承自HttpServlet
的类,比如MyServlet
public class MyServlet extends HttpServlet {
...
}
为了实现Servlet的生命周期方法,你需要重载init()
, service()
和 destroy()
方法:
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("Servlet初始化");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("服务客户请求");
}
@Override
public void destroy() {
System.out.println("Servlet销毁");
}
为了让服务器知道你的Servlet,你需要在web.xml
中配置它
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.example.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>
总结一下
Servlet对象的工作原理及生命周期如下:
- 当服务器启动时,会根据
web.xml
中的配置信息创建Servlet实例,并调用init()
方法进行初始化。 - 当客户端发送请求时,服务器会调用
service()
方法处理请求。 - 当服务器关闭时,会调用
destroy()
方法释放资源
service()
方法的主要作用如下:
- 当服务器接收到客户端的请求时,会启动一个新的线程来执行
service()
方法。 service()
方法可以根据请求类型调用doGet()
或doPost()
等方法来处理特定类型的请求。- 每个客户的每次请求都会导致
service()
方法被单独执行,因此不会互相干扰。
Servlet对象的共享变量
Servlet类是HttpServlet
的一个子类,在编写子类时可以声明一些成员变量。当用户请求加载Servlet时,服务器分别为每个用户启动一个线程,在该线程中Servlet调用service()
方法响应客户的需求,而Servlet类的成员变量是被所有线程共享的数据。
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class MyServlet extends HttpServlet {
private int count = 0;
...
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
synchronized (this) {
count++;
System.out.println("当前访问次数:" + count);
}
}
通过JSP页面访问servlet
可以通过JSP页面来请求一个Servlet。也就是说,可以让JSP页面负责数据的显示,而让一个Servlet去做和处理数据有关的事情。
Web服务目录下的JSP页面都可以通过表单或超链接请求该Web服务目录下的某个Servlet。
eg. 创建一个JSP页面,比如index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>访问Servlet示例</title>
</head>
<body>
<form action="MyServlet" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
创建一个Servlet,比如MyServlet.java
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class MyServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
if ("admin".equals(username) && "123456".equals(password)) {
response.sendRedirect("/success.jsp");
} else {
response.sendRedirect("/error.jsp");
}
}
}
通过JSP页面访问Servlet的主要步骤如下:
- 创建一个JSP页面,包含一个表单或者超链接。
- 表单或超链接指向一个Servlet。
- 编写Servlet处理请求。
- 配置
web.xml
。
doGet()方法和doPost()方法
这两个方法都是Servlet类中的方法,它们是处理HTTP请求的主要入口点。在Servlet生命周期中,每当有新的HTTP请求到达Servlet容器时,Servlet引擎就会调用相应的doGet()
或者doPost()
方法来处理这个请求。
doGet()
方法用来处理HTTP的GET请求,而doPost()
方法则用来处理HTTP的POST请求。这两种请求方式的主要区别在于,GET请求的数据会被附加到URL后面,以问号的形式出现;而POST请求的数据则是放在HTTP包体中的。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class MyServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应内容类型
response.setContentType("text/html");
// 获取输出流
PrintWriter out = response.getWriter();
// 输出欢迎信息
out.println("<html>");
out.println("<body>");
out.println("<h1>Welcome to Servlet</h1>");
out.println("</body>");
out.println("</html>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 这里可以处理POST请求特有的逻辑,比如上传文件等
// 然后我们可以调用doGet()方法来处理剩下的逻辑
this.doGet(request, response);
}
}
Servlet跳转
从一个JSP或者是一个HTML页面可以通过表单或超链接跳转进Servlet,那么从Servlet也可以跳转到其他的Servlet、JSP或其他页面。
跳转的两种形式
1.客户端跳转(重定向):地址栏会跳转
客户端跳转,也称为重定向,是一种常见的Web应用程序中的跳转方式。它允许用户从一个Servlet或者JSP页面跳转到另一个Servlet或者JSP页面。这种跳转方式的特点是浏览器会发起一个新的HTTP请求,因此在新页面中无法访问原请求中的数据
在Servlet中,我们通常使用HttpServletResponse
接口的sendRedirect()
方法来进行客户端跳转。
import javax.servlet.http.*;
public class RedirectServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置响应头为重定向
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.setHeader("Location", "http://www.example.com/newPage.jsp");
// 结束响应
response.flushBuffer();
}
}
另外,客户端跳转只能传递session范围内的属性,而不能传递request范围的属性。这是因为,在重定向过程中,浏览器会发起一个新的HTTP请求,原来的request对象已经失效了。如果需要在多个页面之间共享数据,建议使用session对象存储数据。
2.服务器端跳转(请求转发):地址栏不会跳转
服务器端跳转,也被称为请求转发,是一种在Java Web开发中用于在不同Servlet或JSP页面之间进行跳转的方法。
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取RequestDispatcher对象
RequestDispatcher rd = request.getRequestDispatcher("SecondServlet");
// 转发请求
rd.forward(request, response);
}
}
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/SecondServlet")
public class SecondServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 访问来自第一个Servlet的数据
String dataFromFirstServlet = (String) request.getParameter("data");
// 处理数据...
}
}
服务器端跳转的优点在于它可以方便地在不同的Servlet或JSP页面之间共享数据,这对于需要跨页面处理数据的应用程序非常有用。然而,它的缺点是它要求所有的Servlet和JSP页面都在同一个Web应用中,而且必须位于同一台服务器上。
使用session
HTTP协议本身是一种无状态协议,也就是说服务器并不知道哪个请求来自于哪个用户。为了跟踪用户的状态信息,我们需要一种机制来记录每个用户的特定信息。这就是Session的作用。
Session是一种技术,用来保存用户的信息,例如登录状态、购物车等。每个用户都有自己的Session,它们之间互不干扰。Servlet类使用session对象来记录有关连接的信息。
获取用户会话的方法是通过HttpServletRequest
的对象request
调用getSession()
方法来获取用户的会话对象。
一个用户在不同的servlet对象中获取的session对象是完全相同的,不同的用户的session对象互不相同。
import javax.servlet.*;
import javax.servlet.http.*;
public class SessionServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取session对象
HttpSession session = request.getSession(true);
// 如果session不存在,则创建一个新的session
if(session == null){
session = request.getSession();
}
// 设置session的属性
session.setAttribute("username", "John Doe");
// 获取session的属性
String username = (String) session.getAttribute("username");
}
}
需要注意的是,一个用户在不同的servlet对象中获取的session对象是完全相同的,不同的用户的session对象互不相同。这意味着,你可以在一个servlet中设置session的属性,然后在另一个servlet中读取这些属性。
Servlet传递参数到JSP ---使用session
在Servlet中,你可以使用HttpSession
对象来传递参数到JSP页面。
import javax.servlet.*;
import javax.servlet.http.*;
public class ServletExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取session对象
HttpSession session = request.getSession();
// 设置session的属性
session.setAttribute("name", "John Doe");
// 使用客户端跳转
response.sendRedirect("jsp/example.jsp");
}
}
在JSP页面中,我们可以使用EL表达式或者JSTL标签库来获取这个属性
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
<h1>Hello ${sessionScope.name}!</h1> <!-- 使用EL表达式 -->
</body>
</html>
或者
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
<h1>Hello <c:out value="${sessionScope.name}" />!</h1> <!-- 使用JSTL标签库 -->
</body>
</html>
当然,你也可以使用getAttribute()方法来获取这个属性
<%
String name = (String) session.getAttribute("name");
%>
<html>
<body>
<h1>Hello <%=name %>!</h1> <!-- 使用脚本元素 -->
</body>
</html>
需要注意的是,这种方法适用于客户端跳转和服务器端跳转。无论你是使用sendRedirect()
还是forward()
方法,只要用户还在同一个session内,就可以访问到这个属性。
Servlet传递参数到JSP ---使用request
在Servlet中,除了使用session之外,还可以使用request
对象来传递参数到JSP页面。这是一种更有效率的方法,因为它不需要创建新的session,只需要将请求转发给目标页面即可。
import javax.servlet.*;
import javax.servlet.http.*;
public class ServletExample extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置request的属性
request.setAttribute("name", "John Doe");
// 使用服务器端跳转
RequestDispatcher dispatcher = request.getRequestDispatcher("A.jsp");
dispatcher.forward(request, response);
}
}
在JSP页面中,我们可以使用EL表达式或者JSTL标签库来获取这个属性
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
<h1>Hello ${name}!</h1> <!-- 使用EL表达式 -->
</body>
</html>
或者
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<body>
<h1>Hello <c:out value="${name}" />!</h1> <!-- 使用JSTL标签库 -->
</body>
</html>
或者
<%
String name = (String) request.getAttribute("name");
%>
<html>
<body>
<h1>Hello <%=name %>!</h1> <!-- 使用脚本元素 -->
</body>
</html>
JSP与数据库访问
JSP(JavaServer Pages)是一种动态网页技术,可以用来生成HTML、XML或其他类型的文档。在JSP中,可以通过JDBC(Java Database Connectivity)来访问数据库
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MySQLConnection {
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"username",
"password"
);
}
}
一个简单的例子,展示了如何使用JDBC从MySQL数据库中查询数据
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCDemo {
public static void main(String[] args) {
try {
Connection conn = MySQLConnection.getConnection();
String sql = "SELECT * FROM users WHERE id = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 1); // 设置占位符的值
ResultSet rs = pstmt.executeQuery(); // 执行SQL语句
while(rs.next()) { // 遍历结果集
System.out.println(rs.getString("name"));
}
rs.close();
pstmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
JDBC
JDBC概述
JDBC是Java环境中访问数据库的一组API,它由一些Java语言编写的类和接口组成,能方便地向任何关系型数据库发送SQL命令。
JDBC为数据库应用开发人员开发人员提供了一种标准的应用程序设计接口,使开发人员可以用纯Java语言编写完整的数据库应用程序。
操作不同的数据库仅仅是连接方式上的差异而已。
使用JDBC的应用程序一旦与数据库建立连接,就可以使用JDBC提供的API操作数据库。
JDBC数据库进行交互
在JDBC中,要与数据库进行交互,首先要加载并注册相应的数据库驱动。这是通过Driver
接口完成的。Driver
接口定义了一些方法,如connect()
,用于建立与数据库的连接。具体步骤如下:
- 加载驱动:使用
Class.forName()
方法加载数据库驱动。这个方法会查找并初始化指定类,如果该类实现了Driver
接口,那么就会调用其register()
方法,将其实例注册到DriverManager
中。try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
- 创建连接:使用
DriverManager.getConnection()
方法创建与数据库的连接。try { Connection con = DriverManager.getConnection(url, user, password); } catch (SQLException e) { e.printStackTrace(); }
完整代码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCExample {
public static void main(String[] args) {
try {
// 加载并注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 创建与数据库的连接
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"username",
"password"
);
// 使用连接...
con.close(); // 关闭连接
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
DriverManager类
DriverManager
类是JDBC的核心类之一,主要负责管理数据库连接。它的主要功能包括:
- 注册驱动:当一个
Driver
接口的实现类被加载时,DriverManager
会自动调用其register()
方法,将其实例注册到DriverManager
中。 - 建立连接:
DriverManager
维护着一个已注册的Driver
列表,当需要建立数据库连接时,它会遍历这个列表,找到合适的Driver
来建立连接。
getConnection()
方法是DriverManager
的主要方法,用于获取数据库连接。它的常用重载版本有三个:
getConnection(String url)
:返回与给定URL的数据库的连接。
getConnection(String url, String user, String password)
:返回与给定URL的数据库的连接,并使用给定的用户名和密码。
getConnection(String url, Properties info)
:返回与给定URL的数据库的连接,并使用给定的属性。
使用getConnection()
方法获取与MySQL数据库的连接
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JDBCExample {
public static void main(String[] args) {
try {
// 加载并注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 创建与数据库的连接
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"username",
"password"
);
// 使用连接...
con.close(); // 关闭连接
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
创建Statement对象
发送SQL语句主要是通过Statement
对象完成的。Statement
对象由Connection
对象创建,代表一个数据库会话。Statement
对象主要用于执行静态SQL语句,并能返回执行结果。
Statement
接口中有许多方法,常用的有:
executeQuery(String sql)
:执行SQL查询语句,并返回一个ResultSet
对象。
executeUpdate(String sql)
:执行SQL更新语句(插入、删除、修改),并返回受影响的行数。
close()
:关闭Statement
对象。
例如,以下代码创建了一个Statement
对象,并执行了一个查询语句
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCExample {
public static void main(String[] args) {
try {
// 加载并注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 创建与数据库的连接
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"username",
"password"
);
// 创建Statement对象
Statement stmt = con.createStatement();
// 执行查询语句
ResultSet rs = stmt.executeQuery("SELECT * FROM mytable");
// 处理结果集...
rs.close();
stmt.close();
con.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
Statement接口常用方法
Statement是Java数据库连接(JDBC)API中的一个接口,用于执行SQL语句,并返回结果。
- ResultSet executeQuery(String sql) throws SQLException: 这个方法用于执行查询语句(SELECT),并将结果放在ResultSet对象中。ResultSet是一个游标模型,可以逐行访问结果集。
String sql = "SELECT * FROM employees"; Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { System.out.println(rs.getString("name") + ", " + rs.getInt("age")); }
- int executeUpdate(String sql) throws SQLException: 这个方法用于执行修改或插入语句(INSERT, UPDATE, DELETE),并返回受影响的记录数。
String sql = "DELETE FROM employees WHERE age > 60"; int rowsAffected = stmt.executeUpdate(sql); System.out.println(rowsAffected + " records deleted");
- boolean execute(String sql) throws SQLException: 这个方法用于执行任何类型的SQL语句,包括查询和更新。如果执行成功,返回true;否则返回false。
String sql = "CREATE TABLE employees (id INT PRIMARY KEY, name VARCHAR(50), age INT)"; boolean success = stmt.execute(sql); if (success) { System.out.println("Table created successfully"); } else { System.out.println("Failed to create table"); }
ResultSet接口
ResultSet是Java数据库连接(JDBC)API中的一个接口,表示从数据库查询得到的结果集。当执行了一个查询语句后,Statement或PreparedStatement对象会返回一个ResultSet对象,该对象包含了满足查询条件的所有行。
- ResultSet类定义了访问执行Statement产生的结果集的方法:
- next(): 移动光标到下一行。
- getXXX(int columnIndex): 根据列号获取值。
- getXXX(String columnName): 根据列名获取值
// 假设我们有一个名为employees的表,包含id, name, age三列 String sql = "SELECT * FROM employees"; Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql); // 遍历结果集 while (rs.next()) { // 获取第1列(记住,列是从1开始计数的) int id = rs.getInt(1); // 或者,你可以使用列名来获取值 String name = rs.getString("name"); int age = rs.getInt("age"); System.out.println(id + ": " + name + ", " + age); } // 注意:一定要关闭资源 rs.close(); stmt.close();
- 结果集一般是一个表,其中有查询返回的列标题及相应的值:
- 列标题可以通过getMetaData()方法获得,它返回一个ResultSetMetaData对象,其中包含了列的数量和名称。
ResultSetMetaData meta = rs.getMetaData(); for (int i = 1; i <= meta.getColumnCount(); i++) { System.out.print(meta.getColumnName(i) + "\t"); } System.out.println(); while (rs.next()) { for (int i = 1; i <= meta.getColumnCount(); i++) { System.out.print(rs.getObject(i) + "\t"); } System.out.println(); }
- 列标题可以通过getMetaData()方法获得,它返回一个ResultSetMetaData对象,其中包含了列的数量和名称。
查询操作
与数据库建立连接后,就可以使用JDBC提供的API和数据库交互信息,比如查询、修改和更新数据库中的表等。
import java.sql.*;
public class JdbcExample {
public static void main(String[] args) {
try {
// 加载驱动
Class.forName("com.mysql.jdbc.Driver");
// 创建数据库连接
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydatabase",
"username",
"password"
);
// 创建Statement对象
Statement stmt = conn.createStatement();
// 执行查询语句
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
// 处理查询结果
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println(id + ": " + name + ", " + age);
}
// 关闭资源
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
JDBC与数据库表进行交互的主要方式是使用SQL语句,JDBC提供的API可以将标准的SQL语句发送给数据库,实现与数据库的交互
try {
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM employees WHERE name = ?");
pstmt.setString(1, "John Doe"); // 设置第一个参数为"John Doe"
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println(id + ": " + name + ", " + age);
}
rs.close();
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
处理查询结果的方法
ResultSet对象一次只能看到一个数据行,使用next()方法使光标走到下一行,获得一行数据后,只要将位置索引或字段名传递给getXxx方法就可获得字段值。
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
while (rs.next()) { // 每次调用next()方法,光标就会移动到下一行
int id = rs.getInt(1); // 使用位置索引来获取第一列的值
String name = rs.getString("name"); // 使用字段名来获取第二列的值
System.out.println(id + ": " + name);
}
无论字段是何种属性,都可以使用getString(col)方法返回字段值的字符串表示
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
while (rs.next()) {
String idStr = rs.getString(1); // 将整型字段转换为字符串
String name = rs.getString("name"); // 直接获取字符串字段
System.out.println(idStr + ": " + name);
}
当使用getXxx方法查看一行记录时,不可以颠倒字段的顺序。
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
while (rs.next()) {
String name = rs.getString("name"); // 先获取name字段
int id = rs.getInt(1); // 再获取id字段
System.out.println(id + ": " + name);
}
模糊查询
条件查询:通过在SQL语句中WHERE子句中指定查询条件来实现条件查询
String sql = "SELECT * FROM employees WHERE salary > 5000"; // 查询工资大于5000的员工
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt(1);
String name = rs.getString("name");
double salary = rs.getDouble("salary");
System.out.println(id + ": " + name + ", " + salary);
}
模糊查询:通过用SQL语句操作符LIKE进行模式匹配,使用%代替0个或多个字符,用下划线_代替一个字符,来实现模糊查询。
String sql = "SELECT * FROM employees WHERE name LIKE '张%'; // 查询名字以'张'开头的员工
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt(1);
String name = rs.getString("name");
System.out.println(id + ": " + name);
}
String sql = "SELECT * FROM employees WHERE name LIKE '_明%'; // 查询名字第二个字是'明'的员工
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt(1);
String name = rs.getString("name");
System.out.println(id + ": " + name);
}
更新、添加与删除操作
通过Statement对象调用executeUpdate(SQL语句)执行更新、添加和删除记录的SQL语句来实现更新、添加和删除等操作。
// 更新一条记录
String sql = "UPDATE employees SET salary = 8000 WHERE name='张三'";
int rowsAffected = stmt.executeUpdate(sql); // 返回受影响的行数
// 添加一条记录
sql = "INSERT INTO employees(name, salary) VALUES('李四', 7000)";
rowsAffected = stmt.executeUpdate(sql);
// 删除一条记录
sql = "DELETE FROM employees WHERE name='王五'";
rowsAffected = stmt.executeUpdate(sql);
更新、添加和删除记录的SQL语法:
- UPDATE <表名> SET <字段名>=新值 WHERE <条件子句>
- INSERT INTO 表(字段列表) VALUES (对应的具体记录)
- DELETE FROM <表名> WHERE <条件子句>
UPDATE employees SET salary = 8000 WHERE name='张三';
INSERT INTO employees(name, salary) VALUES('李四', 7000);
DELETE FROM employees WHERE name='王五';
事务
事务由一组SQL语句组成,所谓“事务处理”是指:应用程序保证事务中的SQL语句要么全部都执行,要么一个都不执行。
Connection con = ...; // 假设已经获得了数据库连接
con.setAutoCommit(false); // 关闭自动提交
try {
con.createStatement().executeUpdate("UPDATE employees SET salary = 8000 WHERE name='张三'");
con.createStatement().executeUpdate("INSERT INTO employees(name, salary) VALUES('李四', 7000)");
con.commit(); // 提交事务
} catch (SQLException e) {
con.rollback(); // 回滚事务
}
事务是保证数据库中数据完整性与一致性的机制。JDBC事务处理步骤如下:
- setAutoCommit(boolean autoCommit)方法:为了能进行事务处理,必须关闭连接对象 con 的默认设置。
- commit()方法:连接对象 con 调用commit()方法就是让事务中的SQL语句全部生效。
- rollback()方法:连接对象 con 调用rollback()方法,撤销引起数据发生变化的SQL语句操作,将数据库中的数据恢复到commit()方法执行之前的状态。
con.setAutoCommit(false); // 关闭自动提交 try { con.createStatement().executeUpdate("UPDATE employees SET salary = 8000 WHERE name='张三'"); con.createStatement().executeUpdate("INSERT INTO employees(name, salary) VALUES('李四', 7000)"); con.commit(); // 提交事务 } catch (SQLException e) { con.rollback(); // 回滚事务 }