JavaWeb通过JDBC连接MySQL数据库
一、JDBC简介
JDBC是Java DataBase Connectivity(Java数据库连接)的简写,它是一套用于执行SQL语句的Java API,它由一组用Java语言编写的类和接口组成,是Java程序访问数据库的标准规范。
通过JDBC提供的API,应用程序可以连接到数据库,并使用SQL语句完成对数据库中数据的插入、删除、更新、查询等操作。
有了JDBC,开发人员无需为访问不同的数据库而编写不同的应用程序,只需使用JDBC编写一个通用程序即可。
应用程序在使用JDBC访问特定的数据库时,需要与不同的数据库驱动进行连接。
JDBC提供接口,而驱动是接口的实现,没有驱动将无法完成数据库连接。
每个数据库提供商都需要提供自己的驱动,用来连接本公司的数据库。
1、JDBC的体系结构
JDBC的体系结构由三层组成,具体如下:
- JDBC API:面向程序,供Java程序开发人员使用。
- JDBC Driver Manager:注册数据库驱动,供Java程序开发人员使用。
- JDBC Driver API:面向数据库,供数据库厂商使用。
其中,JDBC API通过Driver Manager(驱动管理器)实现与数据库的透明连接,提供获取数据库连接、执行SQL语句、获得结果等功能。JDBC API使开发人员获得了标准的、纯Java的数据库程序设计接口,为在Java程序中访问任意类型的数据库提供支持。
JDBC Driver Manager(驱动管理器)为应用程序装载数据库驱动,确保使用正确的驱动来访问每个数据源。JDBC Driver Manager的一个特色功能是,它能够支持连接到多个异构数据库的多个并发驱动程序。
JDBC Driver API提供了数据库厂商编写驱动程序时必须实现的接口。
JDBC扩展了Java的能力,它可以让开发人员在开发数据库程序时真正实现"一次编写,处处运行",例如,企业可以通过JDBC程序让使用不同操作系统的员工在互联网上连接到几个全球数据库上,而这几个全球数据库可以是不相同的。
2、JDBC的常用API
JDBC定义了一系列操作数据库的接口和类,这些接口和类位于java.sql包中。
1. Driver接口
Driver接口是所有JDBC驱动程序必须要实现的接口,该接口提供给数据库厂商使用。
在编写JDBC程序时,必须先装载特定数据库厂商的驱动程序,装载驱动程序通过java.lang.Class类中的静态方法forName()实现。
2. DriverManager类
DriverManager类用于加载JDBC驱动并创建与数据库的连接,DriverManager类的常用方法:
方法名称 |
功能描述 |
registerDriver(Driver driver) |
注册数据库的驱动程序 |
getConnection (String url,String user,String password) |
获取数据库连接 |
3.Connection接口
Connection接口表示Java程序和数据库的连接,Java程序和数据库的交互是通过Connection接口来完成的。Connection接口的常用方法:
方法名称 |
功能描述 |
createStatement() |
创建向数据库发送sql的Statement对象 |
prepareStatement(String sql) |
创建向数据库发送预编译sql的PrepareSatement对象 |
prepareCall(String sql) |
创建执行存储过程的CallableStatement对象 |
4.Statement接口
Statement接口用于向数据库发送SQL语句,Statement接口提供了三个执行SQL语句的方法:
方法名称 |
功能描述 |
execute(String sql) |
运行语句,返回是否有结果集 |
executeQuery(String sql) |
运行select语句,返回ResultSet结果集 |
executeUpdate(String sql) |
运行insert/update/delete操作,返回更新的行数 |
5. PreparedStatement接口
继承自Statement接口,用于执行预编译的SQL语句,PreparedStatement接口提供了一些对数据库进行基本操作的方法:
方法名称 |
功能描述 |
executeQuery() |
运行select语句,返回ResultSet结果集 |
executeUpdate() |
运行insert/update/delete操作,返回更新的行数 |
addBatch() |
把多条sql语句放到一个批处理中 |
executeBatch() |
向数据库发送一批sql语句执行 |
6. CallableStatement接口
继承自PreparedStatement接口,由方法prepareCall()创建,用于调用SQL存储过程。CallableStatement接口提供了一些对数据库进行基本操作的方法:
方法名称 |
功能描述 |
wasNull() |
查询最后一个读取的OUT参数是否为SQL类型的Null值 |
setNull(String parameterName,int sqlType) |
将指定参数设置为SQL类型的NULL |
getInt(int parameterIndex ) |
以Java语言中int值的形式获取数据库中Integer类型参数的值 |
setString(String parameterName,String x) |
将指定参数设置为给定的Java类型的String值 |
registerOutParameter(int parameterIndex, int sqlType) |
按顺序位置parameterIndex将OUT参数注册为SQL类型 |
7. ResultSet接口
ResultSet接口表示执行select查询语句获得的结果集,该结果集采用逻辑表格的形式封装。ResultSet接口中提供了一系列操作结果集的方法:
方法名称 |
功能描述 |
getString(int index)、getString(String columnName) |
获得在数据库里是varchar、char等类型的数据对象 |
getFloat(int index)、getFloat(String columnName) |
获得在数据库里是Float类型的数据对象 |
getDate(int index)、getDate(String columnName) |
获得在数据库里是Date类型的数据 |
getBoolean(int index) 、getBoolean(String columnName) |
获得在数据库里是Boolean类型的数据 |
getObject(int index)、getObject(String columnName) |
向数据库发送一批sql语句执行 |
next() |
移动到下一行 |
previous() |
移动到前一行 |
absolute(int row) |
移动到指定行 |
beforeFirst() |
移动resultSet的最前面 |
afterLast() |
移动到resultSet的最后面 |
ResultSet对象维护了一个指向表格数据行的指针,指针默认在第一行之前,调用next()或previous()等移动指针的方法,可以使指针指向具体的数据行,进而调用getObject()方法获取指定的查询结果。
8. ResultSetMetaData接口
ResultSetMetaData接口用于获取关于ResultSet 对象中列的类型和属性信息的对象。ResultSetMetaData接口的常用方法:
方法名称 |
功能描述 |
getColumCount() |
返回所有字段的数目 |
getColumName(int colum) |
根据字段的索引值取得字段的名称 |
getColumType (int colum) |
根据字段的索引值取得字段的类型 |
3、JDBC URL
JDBC URL提供了一种标识数据库的方法,它可以使JDBC程序识别指定的数据库并与之建立连接。
在编写JDBC程序时, 无需关注JDBC URL的形成过程,只需使用与所用的数据库一起提供的URL即可。
JDBC URL的标准语法(以MySQL为例):
jdbc:mysql://<host>:<port>/<database_name>?property1=value1&property2=value2
注意: 需要操作记录为了避免乱码应该加上属性 useUnicode=true&characterEncoding=utf8 ,比如:
jdbc:mysql://192.168.1.99:3306/report?useUnicode=true&characterEncoding=utf8
JDBC URL由协议、子协议、主机端口、数据库名称、参数等组成。其中,JDBC URL中的协议总是jdbc,子协议因数据库厂商的不同而有所差异,在本例中为mysql,主机为数据库所在主机地址,端口为MySQL数据库的默认端口号3306,参数多为连接属性的配置信息,包括数据库的用户名、密码、编码、套接字连接的超时等,JDBC URL的常用参数:
参数类型 |
参数名称 |
user |
数据库用户名,用于连接数据库 |
password |
用户密码,用于连接数据库 |
useUnicode |
是否使用Unicode字符集,如果参数characterEncoding设置为gb2312或gbk,本参数值必须设置为true |
characterEncoding |
当useUnicode设置为true时,指定字符编码。比如可设置为gb2312、gbk、utf8 |
autoReconnect |
当数据库连接异常中断时,是否自动重新连接 |
autoReconnectForPools |
是否使用针对数据库连接池的重连策略 |
failOverReadOnly |
自动重连成功后,连接是否设置为只读 |
maxReconnectsautoReconnect |
重试连接的次数 |
initialTimeoutautoReconnect |
两次重连之间的时间间隔,单位:秒 |
connectTimeout |
和数据库服务器建立socket连接时的超时,单位:毫秒。 0表示永不超时,适用于JDK 1.4及更高版本 |
socketTimeoutsocket |
操作(读写)超时,单位:毫秒。 0表示永不超时 |
二、动手实践
0、数据准备
在MySQL的db_test数据库中创建数据表tb_users。MySQL版本是5.7.33。
DROP TABLE IF EXISTS tb_users; CREATE TABLE tb_users ( id int PRIMARY KEY AUTO_INCREMENT, name varchar(255) NOT NULL, password varchar(255) NOT NULL, email varchar(255) NOT NULL, birthday varchar(255) NOT NULL ); INSERT INTO tb_users (name, password, email, birthday) VALUES ('zhangsan', '123', 'zhangsan@163.com', '1980-01-03'); INSERT INTO tb_users (name, password, email, birthday) VALUES ('lisi', '456', 'lisi@163.com', '1988-11-13'); INSERT INTO tb_users (name, password, email, birthday) VALUES ('wangwu', '789', 'wangwu@163.com', '1990-05-23');
1、创建项目(Eclipse中实现)
创建一个Dynamic Web Poject
2、准备工作
(1)下载MySQL数据库驱动文件:https://downloads.mysql.com/archives/c-j/
(2)下载后解压缩,复制mysql-connector-java-5.1.49.jar文件,到项目lib目录中。
(3)使用鼠标右键单击该JAR包,在弹出框中选择【Build Path】→【Add to Build Path】,此时Eclipse会将该JAR包发布到类路径下。
加入驱动后的项目结构如图所示:
mysql-connector-java-5.1.49-bin.jar和mysql-connector-java-5.1.49.jar有什么区别?
使用上是没区别的一样的,都可以用,带-bin的文件里在编译的的时候里面多了几个编译用的校验文件而已。
3、编写代码
编写一个JDBC程序需要完成六个步骤,具体如下。
- 加载并注册数据库驱动(Driver类) Class.forName("com.mysql.jdbc.Driver");
- 获取数据库连接(Connection对象)
/* 协议:子协议://主机:端口/数据库名 */ String url = "jdbc:mysql://localhost:3306/db_test"; // MySQL数据库的用户名与密码,安装时自己设置,用户名为root,密码为1234 String user = "root"; String pwd = "1234"; Connection connection = DriverManager.getConnection(url, user, pwd);
- 获取SQL语句执行者(Statement对象) Statement statement = connection.createStatement();
- 执行SQL语句 ResultSet resultSet = statement.executeQuery("SELECT * FROM tb_users;");
- 操作结果集(ResultSet对象)
while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); String password = resultSet.getString("password"); String email = resultSet.getString("email"); String birthday = resultSet.getString("birthday"); System.out.println(id + "," + name + "," + password + "," + email + "," + birthday); }
- 回收数据库资源 resultSet.close(); resultSet = null; statement.close(); statement = null; connection.close(); connection = null;
import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; 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("/DBServlet") public class DBServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* 协议:子协议://主机:端口/数据库名 */ String url = "jdbc:mysql://localhost:3306/db_test"; // MySQL数据库的用户名与密码,安装时自己设置,用户名为root,密码为1234 String user = "root"; String pwd = "1234"; Connection connection = null; Statement statement = null; ResultSet resultSet = null; try { // 1.加载驱动//com.mysql.jdbc.Driver /* * DriverManager.registerDriver(new Driver()); 用这种方法会加载两次驱动,也就是说会创建两个drive对象 */ Class.forName("com.mysql.jdbc.Driver"); // 2.获取连接 connection = DriverManager.getConnection(url, user, pwd); // 3.获取用于向数据库发送SQL的Statement对象 statement = connection.createStatement(); // 4.执行sql,获取数据 resultSet = statement.executeQuery("SELECT * FROM tb_users;"); // 5.操作结果集,解析数据 while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); String password = resultSet.getString("password"); String email = resultSet.getString("email"); String birthday = resultSet.getString("birthday"); System.out.println(id + "," + name + "," + password + "," + email + "," + birthday); response.getWriter().append(id + "," + name + "," + password + "," + email + "," + birthday + "<br />"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { } // 6.关闭连接,释放资源 if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } resultSet = null; } if (statement != null) { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } statement = null; } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } connection = null; } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
4、IDEA实现
(1)新建项目
(2)添加框架支持(英文版是Add Framework Support...)
(3)勾选Web应用程序
(4)项目创建成功
(5)发布项目
方法一:在项目上点右键,选择“运行”
打开浏览器,地址栏输入http://localhost:8080/JDBCWeb
方法二:在index.jsp上点右键,选择“运行”
打开浏览器,地址栏输入http://localhost:8080/JDBCWeb_war_exploded/
(6)添加MySQL驱动
按照上面的方法到MySQL :: Download MySQL Connector/J (Archived Versions)下载驱动
然后选择“项目结构”
选择库library,点击+号,选择Java,选中下载的驱动程序jar
(7)创建Servlet
先添加servlet-api.jar依赖
在src目录上创建软件包package,名为com.sdbi.servlet
在包下创建Servlet类,名为DBServlet,继承于HttpServlet,添加注解@WebServlet("/DBServlet"),重写doGet()和doPost()方法,去掉super.doGet(req, resp)和super.doPost(req, resp)的调用。
package com.sdbi.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/DBServlet") public class DBServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet()..."); log("doGet()..."); // 设置网页响应类型 resp.setContentType("text/html; charset=utf-8"); resp.getWriter().println("通过JDBC访问MySQL"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); System.out.println("doPost()..."); log("doPost()..."); } }
运行程序,浏览器地址栏打开localhost:8080/JDBCWeb/DBServlet
Servlet可以运行了,我们接着编写JDBC部分的代码,和前面基本一样。
package com.sdbi.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.sql.*; @WebServlet("/DBServlet") public class DBServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doGet()..."); log("doGet()..."); // 设置网页响应类型 resp.setContentType("text/html; charset=utf-8"); resp.getWriter().println("通过JDBC访问MySQL<br />"); /* 协议:子协议://主机:端口/数据库名 */ String url = "jdbc:mysql://localhost:3306/db_test"; // MySQL数据库的用户名与密码,安装时自己设置,用户名为root,密码为1234 String user = "root"; String pwd = "1234"; Connection connection = null; Statement statement = null; ResultSet resultSet = null; try { // 1.加载驱动//com.mysql.jdbc.Driver /* * DriverManager.registerDriver(new Driver()); 用这种方法会加载两次驱动,也就是说会创建两个drive对象 */ Class.forName("com.mysql.jdbc.Driver"); // 2.获取连接 connection = DriverManager.getConnection(url, user, pwd); // 3.获取用于向数据库发送SQL的Statement对象 statement = connection.createStatement(); // 4.执行sql,获取数据 resultSet = statement.executeQuery("SELECT * FROM tb_users;"); // 5.操作结果集,解析数据 while (resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); String password = resultSet.getString("password"); String email = resultSet.getString("email"); String birthday = resultSet.getString("birthday"); System.out.println(id + "," + name + "," + password + "," + email + "," + birthday); resp.getWriter().append(id + "," + name + "," + password + "," + email + "," + birthday + "<br />"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { } // 6.关闭连接,释放资源 if (resultSet != null) { try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } resultSet = null; } if (statement != null) { try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } statement = null; } if (connection != null) { try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } connection = null; } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("doPost()..."); log("doPost()...");
doGet(req, resp); } }
运行查看结果