【MySQL】JDBC编程
文章目录
- 一、什么是 JDBC?
- JDBC 的核心作用
- JDBC 工作流程
- 二、开发环境准备(Maven 项目)
- 1. 配置 Maven 阿里云镜像
- 2. 引入 MySQL 驱动依赖
- 三、JDBC 核心 API
- 1. DriverManager(传统连接)
- Driver类(驱动类)
- 2. DataSource(连接池)
- DriverManager VS DataSource
- 3. Connection(连接对象)
- 4. Statement(执行对象)
- 5. ResultSet(结果集)
- 四、SQL 注入
- 什么是 SQL 注入?
- 解决方案
- 五、完整代码
- 基础版
- DataSourse , Preparement 优化
- 把建立连接和关闭资源封装成对象
一、什么是 JDBC?
JDBC(Java Data Base Connectivity)是 Java 提供的一套数据库操作接口标准,用来统一连接数据库、发送 SQL、处理结果。
特点:
- 面向接口编程,不关心底层数据库类型
- 切换数据库只需要换驱动包
- 是所有 ORM 框架(MyBatis、Hibernate)的底层基础
JDBC 的核心作用
- 建立数据库连接
- 发送 SQL 语句
- 接收并处理执行结果
- 关闭资源
JDBC 工作流程
正常来说,访问数据库的重要步骤如下,JDBC也提供了这些接口:
- 确定数据库服务器的地址和端口号(数据源)
- 建立连接,确定用户名,密码(数据库连接)
- 发送要执行的SQL(执行对象)
- 接收返回结果(结果集)
- 关闭连接(释放资源,关闭连接)
数据库厂商提供了JDBC具体的实现类,Java程序员只需要利用接口来写程序。
加载驱动 → 建立连接 → 创建 Statement → 执行 SQL → 处理结果 → 释放资源二、开发环境准备(Maven 项目)
Maven类似于应用商店,在maven仓库中维护了所有Java工程所用到的依赖。maven仓库是国外的,可以用阿里的镜像。
1. 配置 Maven 阿里云镜像
加速依赖下载,在settings.xml的<mirrors>中加入:
<mirror><id>aliyunmaven</id><mirrorOf>*</mirrorOf><name>阿里云公共仓库</name><url>https://maven.aliyun.com/repository/public</url></mirror>2. 引入 MySQL 驱动依赖
pom.xml:
<dependencies><!-- MySQL 8.x 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency></dependencies>三、JDBC 核心 API
1. DriverManager(传统连接)
Class.forName("com.mysql.cj.jdbc.Driver");Connectionconnection=DriverManager.getConnection(url,user,password);Driver类(驱动类)
2. DataSource(连接池)
DataSource通过一个连接池去管理很多个连接,当需要执行sql时拿出一个空的连接,用完返还给连接池。是更高效、支持连接复用,企业开发标准用法
MysqlDataSourcedataSource=newMysqlDataSource();dataSource.setURL(url);dataSource.setUser(user);dataSource.setPassword(password);DriverManager VS DataSource
DriverManagergetConnection每次获取的是一个物理连接,每执行一次都会打开一个会话窗口,新建连接,用完销毁,性能低Datasourse一个连接可以执行很多SQL,直到关闭数据源。连接可复用,关闭只是归还,性能极高
3. Connection(连接对象)
代表一次数据库会话,用于创建 Statement。
4. Statement(执行对象)
- Statement:静态 SQL,存在 SQL 注入风险
- PreparedStatement:预编译 SQL,解决sql注入问题
- CallableStatement:执行存储过程
5. ResultSet(结果集)
封装select查询结果,用next()遍历,getXXX(列名/下标)取值。
四、SQL 注入
什么是 SQL 注入?
用户输入恶意字符串,破坏原有 SQL 逻辑,实现越权查询/删改数据。
示例:
select*fromstudentwherename=''or/**/1=1;#' and class_id=1直接查出所有数据:
解决方案
PreparedStatement + 占位符 ?
Statement执行静态的sql语句,PreparedStatement可以预处理sql执行对象。参数会被安全转义,从根本杜绝注入。
五、完整代码
功能:根据 name 查询学生
基础版
packageorg.daisy;importjava.sql.*;importjava.text.MessageFormat;importjava.util.Scanner;publicclassdemo01_DriverManager{staticScannerin=newScanner(System.in);publicstaticvoidmain(String[]args)throwsClassNotFoundException,SQLException{//1. 加载数据库厂商提供的驱动// "com.mysql.cj.jdbc.Driver" 通过完全限定名加载指定的类到JVMClass.forName("com.mysql.cj.jdbc.Driver");//2. 建立连接Connectionconnection=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test20260422?characterEncoding=utf8"+"&allowPublicKeyRetrieval=true&useSSL=false","root","pullmecloser00");//3. 创建statement对象//sql语句通过connection发送Statementstatement=connection.createStatement();//4. 定义sql语句System.out.println("input name:");Stringname=in.nextLine();Stringsql="select studentID,sn,name,mail,classID from student where name ='"+name+"';";//5. 执行sql语句,获取结果集ResultSetresultSet=statement.executeQuery(sql);//6. 遍历结果集// resultSet.next() 如果有下一条数据就返回truewhile(resultSet.next()){//获取学生ID,sql中的int对应Java中的intintstuId=resultSet.getInt(1);StringstuSn=resultSet.getString(2);StringstuName=resultSet.getString(3);StringstuMail=resultSet.getString(4);StringstuClassId=resultSet.getString(5);System.out.println(MessageFormat.format("学生编号 = {0},学号 = {1},学生姓名 = {2},邮箱 = {3},班级 = {4}",stuId,stuSn,stuName,stuMail,stuClassId));}//7. 释放资源,关闭连接resultSet.close();statement.close();connection.close();}}DataSourse , Preparement 优化
packageorg.daisy;importcom.mysql.cj.jdbc.MysqlDataSource;importjavax.sql.*;importjava.text.MessageFormat;importjava.util.Scanner;publicclassdemo02_DataSource{staticScannerin=newScanner(System.in);publicstaticvoidmain(String[]args)throwsSQLException{// 定义mysql数据源对象MysqlDataSourcemysqlDataSource=newMysqlDataSource();//设置数据库连接串,用户名,密码mysqlDataSource.setURL("jdbc:mysql://127.0.0.1:3306/test20260422?characterEncoding=utf8"+"&allowPublicKeyRetrieval=true&useSSL=false");mysqlDataSource.setUser("root");mysqlDataSource.setPassword("pullmecloser00");//定义jdbc数据源对象DataSourcedataSource=mysqlDataSource;//1. 通过数据源获取数据库连接Connectionconnection=dataSource.getConnection();//2. 获取预处理sql执行对象//定义要执行的sql语句Stringsql="select studentID,sn,name,mail,classID from student where name = ?";//sql执行对象PreparedStatementpreparedStatement=connection.prepareStatement(sql);//用户输入查询信息System.out.println("input name:");Stringname=in.nextLine();//3. 用真实值来替换占位符//序号1对应第一个占位符preparedStatement.setString(1,name);//4. 执行sql,获取结果//结果集对象ResultSetresultSet=preparedStatement.executeQuery();//遍历结果while(resultSet.next()){//获取学生ID,sql中的int对应Java中的intintstuId=resultSet.getInt(1);StringstuSn=resultSet.getString(2);StringstuName=resultSet.getString(3);StringstuMail=resultSet.getString(4);StringstuClassId=resultSet.getString(5);System.out.println(MessageFormat.format("学生编号 = {0},学号 = {1},学生姓名 = {2},邮箱 = {3},班级 = {4}",stuId,stuSn,stuName,stuMail,stuClassId));}//5. 关闭资源,释放连接resultSet.close();preparedStatement.close();connection.close();}}把建立连接和关闭资源封装成对象
DBUtil类
packageorg.daisy.DBUtil;importcom.mysql.cj.jdbc.MysqlDataSource;importjavax.sql.DataSource;importjava.sql.Connection;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;publicclassDBUtil{/** * 构造方法私有化,禁止其他类创建DBUtil对象,是单例模式的一个重要特征 */privateDBUtil(){}//数据源privatestaticDataSourcedataSource=null;//连接串,用户名,密码privatestaticStringURL="jdbc:mysql://127.0.0.1:3306/test20260422?characterEncoding=utf8"+"&allowPublicKeyRetrieval=true&useSSL=false";privatestaticStringuser="root";privatestaticStringpassword="pullmecloser00";//类加载到JVM时,执行数据源的初始化static{MysqlDataSourcemysqlDataSource=newMysqlDataSource();mysqlDataSource.setURL(URL);mysqlDataSource.setUser(user);mysqlDataSource.setPassword(password);dataSource=mysqlDataSource;}/** * 获取数据库连接 * @return * @throws SQLException */publicstaticConnectiongetConnection()throwsSQLException{returndataSource.getConnection();}/** * 释放资源,关闭连接 * @param resultSet * @param statement * @param connection * @throws SQLException */publicstaticvoidclose(ResultSetresultSet,Statementstatement,Connectionconnection)throwsSQLException{if(resultSet!=null)resultSet.close();if(statement!=null)statement.close();if(connection!=null)connection.close();}}Insert类
packageorg.daisy;importorg.daisy.DBUtil.DBUtil;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.SQLException;importjava.util.Scanner;publicclassdemo03_Insert{staticScannerin=newScanner(System.in);publicstaticvoidmain(String[]args)throwsSQLException{//1. 获取数据库连接Connectionconnection=DBUtil.getConnection();//2. 定义sqlStringsql="insert student (sn,name,mail,classID) values (?,?,?,?)";//3. 定义预处理对象PreparedStatementstatement=connection.prepareStatement(sql);//4. 用真实数据填充占位符System.out.println("input sn:");Stringsn=in.nextLine();System.out.println("input name:");Stringname=in.nextLine();System.out.println("input mail:");Stringmail=in.nextLine();System.out.println("input classId:");StringclassId=in.nextLine();statement.setString(1,sn);statement.setString(2,name);statement.setString(3,mail);statement.setString(4,classId);//5. 执行并判断 executeUpdate返回结果是受影响的行数introw=statement.executeUpdate();if(row==1)System.out.println("insert successfully");elseSystem.out.println("insert fail");//6. 关闭资源DBUtil.close(null,statement,connection);}}