网站专业术语中seo意思是/seo关键词排名软件

网站专业术语中seo意思是,seo关键词排名软件,word模板免费网站,扁平化个人网站文章目录 1. JDBC概述1.1 数据的持久化1.2 Java中的数据存储技术1.3 JDBC介绍1.4 JDBC体系结构1.5 JDBC程序编写步骤 2. 获取数据库连接2.1 引入JAR包2.2 要素一:Driver接口实现类2.2.1 Driver接口介绍2.2.2 加载与注册JDBC驱动 2.3 要素二:URL2.4 要素三…

文章目录

  • 1. JDBC概述
    • 1.1 数据的持久化
    • 1.2 Java中的数据存储技术
    • 1.3 JDBC介绍
      • 1.4 JDBC体系结构
      • 1.5 JDBC程序编写步骤
  • 2. 获取数据库连接
    • 2.1 引入JAR包
    • 2.2 要素一:Driver接口实现类
      • 2.2.1 Driver接口介绍
      • 2.2.2 加载与注册JDBC驱动
    • 2.3 要素二:URL
    • 2.4 要素三:用户名和密码
    • 2.5 连接举例
      • 2.5.1 连接方式一
      • 2.5.2 连接方式二
      • 2.5.3 连接方式三
      • 2.5.4 连接方式四
      • 2.5.5 连接方式五(使用properties文件配置参数)
  • 3. 使用PreparedStatement实现CRUD操作
    • 3.1 操作和访问数据库
    • 3.2 使用Statement操作数据表
    • 3.3 PreparedStatement的使用
      • 3.3.1 PreparedStatement介绍
      • 3.3.2 PreparedStatement对比优势
      • 3.3.3 Java与SQL对应数据类型转换表
      • 3.3.4 使用PreparedStatement实现增、改、删、查操作
      • 3.3.4 ResultSet与ResultSetMetaData
      • 3.3.5 资源的释放
      • 3.3.6 preparedStatement使用方式总结
  • 4. 总结
    • 4.1 核心API理解
      • 4.1.1 注册驱动
      • 4.1.2 Connection
      • 4.1.3 Statement
      • 4.1.4 PreparedStatement
      • 4.1.5 ResultSet
    • 4.2 常见问题
      • 4.2.1 资源的管理
      • 4.2.2 SQL语句问题
      • 4.2.3 SQL语句未设置参数问题
      • 4.2.4 用户名或密码错误问题
      • 4.2.5 通信异常


JDBC(Java Database Connectivity)作为 Java 访问数据库的基石,为开发者提供了一种标准、通用的方式来操作各种关系型数据库。本文将深入探讨 JDBC 的相关知识,从其基本概念、体系结构,到如何编写 JDBC 程序以及获取数据库连接等方面进行详细介绍,帮助了解和掌握 JDBC 技术。


1. JDBC概述

1.1 数据的持久化

  • 持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。大多数情况下,特别是企业级应用,数据持久化意味着将内存中的数据保存到硬盘上加以”固化”,而持久化的实现过程大多通过各种关系数据库来完成

  • 持久化的主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中。

    在这里插入图片描述

1.2 Java中的数据存储技术

在Java中,数据库存取技术可分为如下几类:

  • JDBC直接访问数据库
  • JDO (Java Data Object )技术
  • 第三方O/R工具,如Hibernate, Mybatis 等

JDBC是java访问数据库的基石,JDO、Hibernate、MyBatis等只是更好的封装了JDBC。

1.3 JDBC介绍

  • JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这些类库可以以一种标准的方法、方便地访问数据库资源。
  • JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。
  • JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
  • 如果没有JDBC,那么Java程序访问数据库时是这样的:

在这里插入图片描述


  • 有了JDBC,Java程序访问数据库时是这样的:

在这里插入图片描述


  • 总结如下:

在这里插入图片描述

1.4 JDBC体系结构

JDBC接口(API)包括两个层次:

  • 面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
  • 面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。

1.5 JDBC程序编写步骤

在这里插入图片描述

补充:ODBC(Open Database Connectivity,开放式数据库连接),是微软在Windows平台下推出的。使用者在程序中只需要调用ODBC API,由 ODBC 驱动程序将调用转换成为对特定的数据库的调用请求。

步骤总结:

  1. 注册驱动【依赖的驱动类,进行安装】
  2. 获取连接【Connection建立连接】
  3. 创建发送SQL语句对象【Connection创建发送SQL语句的Statement】
  4. 发送SQL语句,并获取返回结果【Statement 发送sql语句到数据库并且取得返回结果】
  5. 结果集解析【结果集解析,将查询结果解析出来】
  6. 资源关闭【释放ResultSet、Statement 、Connection】

2. 获取数据库连接

MySQL官网下载数据库连接驱动jar包:https://downloads.mysql.com/archives/c-j/

  • 对接的mysql数据库是5.7版本的话,可以使用mysql-connector-java-5.1.37-bin.jar
  • 对接的mysql数据库是8.0版本的话,可以使用mysql-connector-java-8.0.27-bin.jar

连接驱动包版本可以根据使用的数据库版本自行选择jar包,没必要一一对应,版本接近即可。

2.1 引入JAR包

这里使用IDEA编辑器进行举例。

  1. 首先在项目或模块下创建一个lib文件夹用于存放依赖库。
  2. 将准备好的连接驱动jar包复制到lib文件夹下。
  3. 右击选择“Add as Library…”的选项创建依赖库。如果界面进行汉化了的话可能叫“添加为库…”。
  4. 在创建依赖库的界面填写和选择一下内容,一般默认就行,确认保存就行了。

2.2 要素一:Driver接口实现类

2.2.1 Driver接口介绍

java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。

  • Oracle的驱动:oracle.jdbc.driver.OracleDriver
  • MySQL的驱动: com.mysql.jdbc.Driver(5.x)/ com.mysql.cj.jdbc.Driver(8.x)

驱动jar包从官网上下载下来之后,解压压缩包,找到对应的jar包拷贝到Java工程的一个目录中。这里习惯上新建一个lib文件夹,和src目录平级。然后选中lib文件夹右键 ——> Add as Library,与项目集成。

2.2.2 加载与注册JDBC驱动

加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名。

Class.forName("com.mysql.jdbc.Driver");Class.forName("com.mysql.cj.jdbc.Driver");     // 8.x

注册驱动:DriverManager 类是驱动程序管理器类,负责管理驱动程序。

  • 使用DriverManager.registerDriver(com.mysql.jdbc.Driver)来注册驱动

  • 但是通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实例。 因为 Driver 接口的驱动程序类都包含了静态代码块,在这个静态代码块中,会调用 DriverManager.registerDriver() 方法 来注册自身的一个实例。

2.3 要素二:URL

JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。JDBC URL的标准由三部分组成,各部分间用冒号分隔。

  jdbc:子协议:子名称- 协议:JDBC URL中的协议总是jdbc - 子协议:子协议用于标识一个数据库驱动程序- 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名

在这里插入图片描述

几种常用数据库的 JDBC URL

  • MySQL的连接URL编写方式:
  • jdbc:mysql://主机名称:mysql服务端口号/数据库名称?参数=值&参数=值
    • jdbc:mysql://localhost:3306/test
    • jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8 (如果JDBC程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)
    • jdbc:mysql://localhost:3306/test?user=root&password=123456
  • Oracle 9i的连接URL编写方式:
  • jdbc:oracle:thin:@主机名称:oracle服务端口号:数据库名称
    • jdbc:oracle:thin:@localhost:1521:test
  • SQLServer的连接URL编写方式:
  • jdbc:sqlserver://主机名称:sqlserver服务端口号:DatabaseName=数据库名称
    • jdbc:sqlserver://localhost:1433:DatabaseName=test

2.4 要素三:用户名和密码

用户名和密码可以用“属性名=属性值”方式,即创建属性变量的方式告诉数据库。
可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接。

2.5 连接举例

2.5.1 连接方式一

public void testConnection1() {try {//1.提供java.sql.Driver接口实现类的对象Driver driver = null;driver = new com.mysql.cj.jdbc.Driver();//2.提供url,指明具体操作的数据String url = "jdbc:mysql://localhost:3306/test";//3.提供Properties的对象,指明用户名和密码Properties info = new Properties();info.setProperty("user", "root");info.setProperty("password", "abc123");//4.调用driver的connect(),获取连接Connection conn = driver.connect(url, info);System.out.println(conn);    // 打印获取连接} catch (SQLException e) {e.printStackTrace();}
}

说明:上述代码中显式出现了第三方数据库的API

2.5.2 连接方式二

	public void testConnection2() {try {//1.实例化DriverString className = "com.mysql.cj.jdbc.Driver";Class clazz = Class.forName(className);Driver driver = (Driver) clazz.newInstance();//2.提供url,指明具体操作的数据String url = "jdbc:mysql://localhost:3306/test";//3.提供Properties的对象,指明用户名和密码Properties info = new Properties();info.setProperty("user", "root");info.setProperty("password", "abc123");//4.调用driver的connect(),获取连接Connection conn = driver.connect(url, info);System.out.println(conn);} catch (Exception e) {e.printStackTrace();}}

说明:相较于方式一,这里使用反射实例化Driver,不在代码中体现第三方数据库的API。体现了面向接口编程思想。

2.5.3 连接方式三

	public void testConnection3() {try {//1.数据库连接的4个基本要素:String url = "jdbc:mysql://localhost:3306/test";String user = "root";String password = "abc123";String driverName = "com.mysql.cj.jdbc.Driver";//2.实例化DriverClass clazz = Class.forName(driverName);Driver driver = (Driver) clazz.newInstance();//3.注册驱动DriverManager.registerDriver(driver);//4.获取连接Connection conn = DriverManager.getConnection(url, user, password);System.out.println(conn);} catch (Exception e) {e.printStackTrace();}}

说明:使用DriverManager实现数据库的连接。体会获取连接必要的4个基本要素。

2.5.4 连接方式四

    public void testConnection4() {try {//1.数据库连接的4个基本要素:String url = "jdbc:mysql://localhost:3306/test";String user = "root";String password = "abc123";String driverName = "com.mysql.cj.jdbc.Driver";//2.加载驱动 (①实例化Driver ②注册驱动)Class.forName(driverName);//Driver driver = (Driver) clazz.newInstance();//3.注册驱动//DriverManager.registerDriver(driver);/*可以注释掉上述代码的原因,是因为在mysql的Driver类中声明有:static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}*///3.获取连接Connection conn = DriverManager.getConnection(url, user, password);System.out.println(conn);} catch (Exception e) {e.printStackTrace();}}

说明:不必显式的注册驱动了。因为在DriverManager的源码中已经存在静态代码块,实现了驱动的注册。


从JDK6开始,不再需要显式地调用 Class.forName() 来加载 JDBC 驱动程序,只要在类路径中集成了对应的jar文件,会自动在初始化时注册驱动程序。但是不要去掉,建议保留。

2.5.5 连接方式五(使用properties文件配置参数)

	public  void testConnection5() throws Exception {//1.加载配置文件InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);//2.读取配置信息String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");//3.加载驱动Class.forName(driverClass);//4.获取连接Connection conn = DriverManager.getConnection(url,user,password);System.out.println(conn);}

其中,配置文件声明在工程的src目录下:【jdbc.properties】

user=root
password=abc123
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.cj.jdbc.Driver

说明:使用配置文件的方式保存配置信息,在代码中加载配置文件。

使用配置文件的好处:

①实现了代码和数据的分离,实现了解耦。如果需要修改配置信息,直接在配置文件中修改,不需要深入代码
②如果修改了配置信息,省去重新编译的过程。

3. 使用PreparedStatement实现CRUD操作

3.1 操作和访问数据库

数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:

  • Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
  • PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。
  • CallableStatement:用于执行 SQL 存储过程。

在这里插入图片描述

3.2 使用Statement操作数据表

通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,能实现对数据表的查询、插入、更新和删除等操作,并且返回执行结果。

Statement 接口中定义了下列方法用于执行 SQL 语句:

int excuteUpdate(String sql)          
// 用于执行 INSERT、UPDATE、DELETE 等 SQL 语句,以及 DDL(数据定义语言)语句,如 CREATE TABLE、ALTER TABLE 等。
// 该方法返回一个整数,表示受影响的行数。如果是 DDL 语句,通常返回 0。ResultSet executeQuery(String sql)    
// 该方法用于执行静态的 SELECT 语句,返回一个 ResultSet 对象,这个对象包含了查询所返回的结果集。Boolean execute(String sql)          
// 可以执行任意的 SQL 语句,包括 SELECT、INSERT、UPDATE、DELETE 以及 DDL 语句。
// 该方法返回一个布尔值,如果第一个结果是 ResultSet 对象(即执行的是查询语句),则返回 true;
// 如果是更新计数或者没有结果,则返回 false。可以通过 getResultSet() 方法获取 ResultSet 对象,通过 getUpdateCount() 方法获取受影响的行数。

使用Statement进行查询操作的代码演示:

package com.test.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;public class StatementTest {// 数据库连接信息private static final String DB_URL = "jdbc:mysql://10.10.20.235:3306/rpa_database";private static final String DB_USER = "root";private static final String DB_PASSWORD = "root";public static void main(String[] args) {Connection conn = null;Statement stmt = null;try {// 注册 JDBC 驱动Class.forName("com.mysql.cj.jdbc.Driver");// 建立数据库连接System.out.println("正在连接数据库...");conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);// 创建 Statement 对象stmt = conn.createStatement();// 查询数据String selectSql = "SELECT * FROM rpa_jnhl_customer_table";ResultSet rs = stmt.executeQuery(selectSql);System.out.println("查询结果:");while (rs.next()) {int id = rs.getInt("id");String account = rs.getString("account");int department_code = rs.getInt("department_code");String erp_code = rs.getString("erp_code");System.out.println("ID: " + id + ", 账号: " + account + ", 部门编码: " + department_code + ", ERP部门编码: " + erp_code);}} catch (Exception e) {e.printStackTrace();} finally {// 关闭资源try {if (stmt != null) stmt.close();} catch (Exception e) {e.printStackTrace();}try {if (conn != null) conn.close();} catch (Exception e) {e.printStackTrace();}}}
}

使用Statement操作数据表存在一些弊端:

  • 性能问题:每次执行 SQL 语句时,数据库都需要对 SQL 语句进行编译和解析。如果多次执行结构相似但参数不同的 SQL 语句,数据库会重复进行编译和解析操作,增加了系统开销,降低了性能。
  • 代码可读性和可维护性差:当 SQL 语句比较复杂,或者需要拼接大量的参数时,使用 Statement 会使代码变得冗长和复杂,降低了代码的可读性和可维护性。
  • 存在SQL注入问题(最主要):如果用户输入的内容包含恶意的 SQL 代码,就可能改变原 SQL 语句的语义,从而执行非预期的操作,这就是 SQL 注入攻击。

SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user='a' OR 1 = ' AND password = ' OR '1' = '1') ,从而利用系统的 SQL 引擎完成恶意行为的做法。

对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来)取代 Statement 就可以了。

在这里插入图片描述

3.3 PreparedStatement的使用

3.3.1 PreparedStatement介绍

PreparedStatement 接口继承自 Statement 接口,主要用于执行预编译的 SQL 语句。相比于 Statement,PreparedStatement 提供了更高效、更安全和更便捷的方式来操作数据库。

  • 预编译机制

PreparedStatement 的核心优势在于预编译机制。当使用 PreparedStatement 时,SQL 语句会先被发送到数据库进行预编译,数据库会对 SQL 语句的语法进行检查和优化,并生成执行计划。之后,无论执行多少次该 SQL 语句,只要语句结构不变,数据库就可以直接使用之前生成的执行计划,避免了重复编译的开销。

......
// 预编译 SQL 语句
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
// 设置参数
pstmt.setString(1, "John");
pstmt.setInt(2, 25);
// 执行 SQL 语句
int rowsInserted = pstmt.executeUpdate();
......

PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数。

  • setXXX(int parameterIndex, XXX value):用于为占位符设置具体的值,parameterIndex 表示占位符的索引(从 1 开始),XXX 表示数据类型,如 setString()setInt()setDouble() 等。

3.3.2 PreparedStatement对比优势

  • 预编译机制避免了重复编译的开销,提高了性能。
  • SQL 语句和参数是分离的,通过 setXXX() 方法设置参数,使代码更加清晰和易于理解。同时,如果需要修改 SQL 语句或参数,只需要修改相应的部分,而不需要像 Statement 那样在拼接的字符串中进行复杂的修改。
  • 使用占位符来表示参数,数据库会将参数作为一个整体进行处理,不会将其解析为 SQL 语句的一部分,从而有效防止了 SQL 注入攻击。

3.3.3 Java与SQL对应数据类型转换表

以下是整合后的 Java 与 SQL 常见数据类型对应关系表格:

SQL 数据类型Java 数据类型说明
整数类型
TINYINTbyteByte用于表示较小范围的整数,通常是 -128 到 127
SMALLINTshortShort表示比 TINYINT 范围稍大的整数,如 -32768 到 32767
INTINTEGERintInteger常用的整数类型,范围一般为 -2147483648 到 2147483647
BIGINTlongLong用于表示大范围的整数
浮点类型
FLOATfloatFloat单精度浮点数,精度相对较低
DOUBLEdoubleDouble双精度浮点数,精度较高
字符类型
CHARString定长字符串,当存储的字符串长度小于定义长度时会用空格填充
VARCHARString变长字符串,仅存储实际长度的字符
TEXT(如 MySQL)String用于存储较长的文本数据
日期和时间类型
DATEjava.sql.Date仅表示日期,不包含时间信息
TIMEjava.sql.Time仅表示时间,不包含日期信息
TIMESTAMPjava.sql.Timestamp包含日期和时间信息,精度较高
布尔类型
BOOLEANbooleanBoolean表示逻辑值,通常为 truefalse
二进制类型
BLOBbyte[]用于存储二进制大对象,如图片、文件等
  • 注意事项
  • 不同数据库系统对 SQL 数据类型的实现可能存在细微差异,例如 TEXT 在不同数据库中的具体长度限制和性能表现可能不同。
  • 在实际开发中,使用 JDBC 从数据库中获取数据时,要注意数据类型的正确转换,避免出现 ClassCastException 等异常。

3.3.4 使用PreparedStatement实现增、改、删、查操作

package com.test.jdbc;
import org.junit.Test;
import java.sql.*;public class PreparedstatementTest {// 插入一条数据@Testpublic void testInsert() throws ClassNotFoundException, SQLException {// 1.注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2.获取连接Connection connection = DriverManager.getConnection("jdbc:mysql://10.10.20.235/rpa_database", "root", "root");// 3.编写sql语句String sql = "Insert into rpa_jnhl_customer_table(id,account,department_code,erp_code) values(?,?,?,?)";// 4.创建PS对象,传入SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);// 5.占位符赋值preparedStatement.setObject(1,27);preparedStatement.setObject(2,"142119");preparedStatement.setObject(3,10119);preparedStatement.setObject(4,"LH234923");// 6.执行sql语句int rows = preparedStatement.executeUpdate();// 7.输出结果if (rows >  0) {System.out.println("数据插入成功!");} else {System.out.println("数据插入失败!");}// 8. 关闭资源preparedStatement.close();connection.close();}   // 更新一条数据@Testpublic void testUpdate() throws ClassNotFoundException, SQLException {// 1.注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2.获取连接Connection connection = DriverManager.getConnection("jdbc:mysql://10.10.20.235/rpa_database", "root", "root");// 3.编写sql语句String sql = "UPDATE rpa_jnhl_customer_table SET id=? WHERE id=?";// 4.创建PS对象,传入SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);// 5.占用符赋值preparedStatement.setObject(1,14);preparedStatement.setObject(2,27);// 6.执行sql语句int rows = preparedStatement.executeUpdate();// 7.输出结果if (rows >  0) {System.out.println("数据更改成功!");} else {System.out.println("数据更改失败!");}// 8. 关闭资源preparedStatement.close();connection.close();  }// 删除一条数据@Testpublic void testDelete() throws ClassNotFoundException, SQLException {// 1.注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2.获取连接Connection connection = DriverManager.getConnection("jdbc:mysql://10.10.20.235/rpa_database", "root", "root");// 3.编写sql语句String sql = "DELETE FROM rpa_jnhl_customer_table WHERE id=?";// 4.创建PS对象,传入SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);// 5.占用符赋值preparedStatement.setObject(1,14);// 6.执行sql语句int rows = preparedStatement.executeUpdate();// 7.输出结果if (rows >  0) {System.out.println("数据删除成功!");} else {System.out.println("数据删除失败!");}// 8. 关闭资源preparedStatement.close();connection.close();}// 查看一条数据@Testpublic void testSelect() throws ClassNotFoundException, SQLException {// 1.注册驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2.获取连接Connection connection = DriverManager.getConnection("jdbc:mysql://10.10.20.235/rpa_database", "root", "root");// 3.编写sql语句String sql = "SELECT id,account,department_code,erp_code FROM rpa_jnhl_customer_table WHERE id=?";// 4.创建PS对象,传入SQL语句PreparedStatement preparedStatement = connection.prepareStatement(sql);// 5.占位符赋值preparedStatement.setObject(1,14);// 6.执行sql语句ResultSet resultSet = preparedStatement.executeQuery();// 7.输出结果System.out.println("查询结果:");while (resultSet.next()) {int id = resultSet.getInt("id");String account = resultSet.getString("account");int department_code = resultSet.getInt("department_code");String erp_code = resultSet.getString("erp_code");System.out.println("ID: " + id + ", 账号: " + account + ", 部门编码: " + department_code + ", ERP部门编码: " + erp_code);}// 8. 关闭资源preparedStatement.close();connection.close();}
}
  • 将查询的数据不进行直接打印输出,而是将其封装到一个List<Map>集合对象中。实现数据从数据库——ResultSet——java的流转。存储思路就是一行数据一个Map集合,key取列名,value取数据。整个查询数据再封装到一个List集合。
package com.test.jdbc;import org.junit.Test;import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class PreparedstatementTest {@Testpublic void testSelect1() throws ClassNotFoundException, SQLException {// 1.注册驱动Class.forName("com.mysql.cj.jdbc.Driver"); // 2.创建连接Connection connection = DriverManager.getConnection("jdbc:mysql://10.10.20.235/rpa_database", "root", "root");// 3.SQL语句String sql = "SELECT * FROM rpa_jnhl_customer_table";// 4.创建ps对象PreparedStatement preparedStatement = connection.prepareStatement(sql);// 5.执行sqlResultSet resultSet = preparedStatement.executeQuery();// 6. 结果集解析List<Map> list = new ArrayList<>();// 获取列的信息对象ResultSetMetaData metaData = resultSet.getMetaData();// 获取总列数int columnCount = metaData.getColumnCount();while (resultSet.next()){Map map = new HashMap();// 自动遍历列,注意,从1开始,小于等于总列数for (int i = 1; i <= columnCount; i++) {// 获取指定列下角标的值Object value = resultSet.getObject(i);// 获取指定列下角标的名称String columnLabel = metaData.getColumnLabel(i);map.put(columnLabel,value);} list.add(map);// 8. 关闭资源preparedStatement.close();connection.close();}}   
}
  • 注意:数据库的链接和关闭等操作是通用重复的,可以进行封装成一个JDBCUtils工具类进行调用即可。这里使用Properties配置文件的方式读取。
/*** @Description 操作数据库的工具类*/
public class JDBCUtils {	/*** @Description 获取数据库的连接*/public static Connection getConnection() throws Exception {// 1.读取配置文件中的4个基本信息InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");// 2.加载驱动Class.forName(driverClass);// 3.获取连接Connection conn = DriverManager.getConnection(url, user, password);return conn;}/*** @Description 关闭连接和Statement的操作*/public static void closeResource(Connection conn,Statement ps){try {if(ps != null)ps.close();} catch (SQLException e) {e.printStackTrace();}try {if(conn != null)conn.close();} catch (SQLException e) {e.printStackTrace();}}/*** @Description 关闭资源操作*/public static void closeResource(Connection conn,Statement ps,ResultSet rs){try {if(ps != null)ps.close();} catch (SQLException e) {e.printStackTrace();}try {if(conn != null)conn.close();} catch (SQLException e) {e.printStackTrace();}try {if(rs != null)rs.close();} catch (SQLException e) {e.printStackTrace();}}
}

使用JDBCUtils工具类实现修改操作。

	//修改customers表的一条记录@Testpublic void testUpdate(){Connection conn = null;PreparedStatement ps = null;try {//1.获取数据库的连接conn = JDBCUtils.getConnection();//2.预编译sql语句,返回PreparedStatement的实例String sql = "update customers set name = ? where id = ?";ps = conn.prepareStatement(sql);//3.填充占位符ps.setObject(1,"莫扎特");ps.setObject(2, 18);//4.执行ps.execute();} catch (Exception e) {e.printStackTrace();}finally{//5.资源的关闭JDBCUtils.closeResource(conn, ps);			}}

说明:针对于表的字段名与类的属性名不相同的情况

  1. 必须声明sql时,使用类的属性名来命名字段的别名;
  2. 使用ResultSetMetaData时,需要使用getColumnLabel()来替换getColumnName()获取列的别名。
  3. 如果sql中没有给字段其别名,getColumnLabel()获取的就是列名。

3.3.4 ResultSet与ResultSetMetaData

  • ResultSet

ResultSet 接口表示数据库查询操作返回的结果集,它是一个包含查询结果的表格,包含了多行数据,每一行数据又包含多个列。可以通过 ResultSet 接口提供的方法来遍历结果集、获取每一行的数据以及对数据进行操作。

ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next() 方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。

【移动光标的方法】

  • next():最为常用的方法。将光标从当前位置向下移动一行,如果下一行存在则返回 true,否则返回 false。常用于遍历结果集。
  • previous():将光标向上移动一行,前提是结果集支持可滚动。
  • first():将光标移动到结果集的第一行,如果结果集不为空则返回 true。
  • last():将光标移动到结果集的最后一行,如果结果集不为空则返回 true。

当指针指向一行时, 可以通过调用 getXxx(int index)getXxx(int columnName) 获取每一列的值。如果不确定数据类型的情况下,可以直接使用 getObject()

注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。

  • ResultSetMetaData

ResultSetMetaData 接口提供了关于 ResultSet 对象中列的元数据信息,例如列的数量、列名、列的数据类型等。通过 ResultSet 的 getMetaData() 方法可以获取 ResultSetMetaData 对象。

【常用方法】

  • getColumnCount():返回结果集中的列数。
  • getColumnName(int column):返回指定列的列名,列索引从 1 开始。
  • getColumnTypeName(int column):返回指定列的数据库特定的类型名称。
  • getColumnLabel(int column):返回指定列的标签(通常是列名或别名)。
  • 两者关系
  • ResultSet 用于存储和操作查询结果的数据,而 ResultSetMetaData 用于获取查询结果的元数据信息。
  • ResultSet 对象可以通过 getMetaData() 方法获取与之关联的 ResultSetMetaData 对象,从而获取结果集的列信息。

3.3.5 资源的释放

在使用 JDBC(Java Database Connectivity)进行数据库操作时,及时关闭使用的资源是非常重要的,这有助于避免资源泄漏和提高系统性能。

  • 关闭顺序

关闭资源时需要遵循一定的顺序,通常是先关闭 ResultSet,再关闭 Statement,最后关闭 Connection。这是因为 ResultSet 依赖于 Statement,而 Statement 依赖于 Connection,如果先关闭了 ConnectionStatementResultSet 就无法正常工作。

通常使用 try-catch-finally 块来确保资源的关闭。以下是一个示例代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;public class JdbcResourceClosingOld {public static void main(String[] args) {Connection conn = null;Statement stmt = null;ResultSet rs = null;try {// 加载数据库驱动Class.forName("com.mysql.cj.jdbc.Driver");// 建立数据库连接conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testdb", "root", "password");// 创建 Statement 对象stmt = conn.createStatement();// 执行查询操作rs = stmt.executeQuery("SELECT * FROM users");// 处理查询结果while (rs.next()) {System.out.println(rs.getString("username"));}} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();} finally {// 关闭 ResultSetif (rs != null) {try {rs.close();} catch (SQLException e) {e.printStackTrace();}}// 关闭 Statementif (stmt != null) {try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}// 关闭 Connectionif (conn != null) {try {conn.close();} catch (SQLException e) {e.printStackTrace();}}}}
}

3.3.6 preparedStatement使用方式总结

  • 使用步骤总结
  1. 注册驱动
  2. 获取连接
  3. 编写SQL语句
  4. 创建preparedstatement并且传入SQL语句结构
  5. 占位符赋值
  6. 发送SQL语句,并且获取结果
  7. 结果集解析
  8. 关闭资源
  • 使用API总结

【注册驱动】

  • 方案1:调用静态方法,但是会注册两次。
    DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
  • 方案2:反射触发(常用)
    Class .forName ("com.mysql.cj.jdbc.Driver");

【获取连接】
获取连接的方法参数填报有3种方式可以选择。
Connection connection = DriverManager.getConnection(参数填报);

  • 3个参数:(String url, String user, string password)
  • 2个参数:(String url, Properties info(user password))
  • 1个参数:(String url?user=账号&password=密码)

【创建Statement】

  • 静态:Statement statement = connection.createstatement();
  • 预编译(推荐):Preparedstatement preparedstatement = connection.preparedStatement(sql语句结构);

【占位符赋值】
preparedstatement.set0bject(值); 值的填写按照 ? 的位置,从1开始,从左到右依次赋值。


【发送sql语司获取结果】

int rows = preparedstatement.executeUpdate();              // 非DQL
Resultset resultset = preparedstatement.executeQuery();    // DQL

【查询结果集解析】

  • 移动光标指向行数据 next(),将结果集的光标从当前位置向下移动一行。通常用于遍历结果集。

  • 获取列的数据 getXXX(列名或索引值),根据列名或列索引获取不同类型的列值,索引值从1开始,获取类型可以是Int、String等,一般使用getObject()

  • 获取列的信息

    • ResultSetMetaData metaData = rs.getMetaData();:获取结果集的元数据,包含列的数量、列名、列的数据类型等信息。
    • int columnCount = metaData.getColumnCount();:获取结果集的总列数。
    • String columnName = metaData.getColumnName(i);:用于返回结果集中指定列的名称,参数 i 表示列的索引,索引从 1 开始。
    • String columnLebal = metaData.getColumnLebal(i);:用于获取结果集中指定列的标签(label)。这里的列标签通常是在 SQL 查询语句里使用 AS 关键字指定的别名,如果没有使用别名,那么列标签一般就是列的实际名称。参数 i 表示列的索引,索引从 1 开始。

【关闭资源】

  • 关闭资源时,都需要调用对象的 close() 方法进行关闭操作。执行时,要遵循先关闭 ResultSet,再关闭 Statement(或 PreparedStatement),最后关闭 Connection 的顺序。

4. 总结

4.1 核心API理解

4.1.1 注册驱动

Class.forName("com.mysql.cj.jdbc.Driver");
  • 在 Java 中,当使用 JDBC(Java Database Connectivity)连接数据库时,需要加载数据库特定的驱动程序,以便与数据库进行通信。加载驱动程序的目的是为了注册驱动程序,使得 JDBC API 能够识别并与特定的数据库进行交互。

  • 从JDK6开始,不再需要显式地调用 Class.forName() 来加载 JDBC 驱动程序,只要在类路径中集成了对应的jar文件,会自动在初始化时注册驱动程序。

4.1.2 Connection

Connection接口是JDBC API的重要接口,用于建立与数据库的通信通道。换而言之,Connection对象不为空,则代表一次数据库连接。

  • 在建立连接时,需要指定数据库URL、用户名、密码参数。
    • URL:jdbc:mysql://localhost:3306/atguigu
      • jdbc:mysql://IP地址:端口号/数据库名称?参数键值对1&参数键值对2

Connection 接口还负责管理事务,Connection 接口提供了 commitrollback 方法,用于提交事务和回滚事务。
在使用JDBC技术时,必须要先获取Connection对象,在使用完毕后,要释放资源,避免资源占用浪费及泄漏。

4.1.3 Statement

Statement 接口用于执行 SQL 语句并与数据库进行交互。它是 JDBC API 中的一个重要接口。通过 Statement 对象,可以向数据库发送 SQL 语句并获取执行结果。

  • 结果可以是一个或多个结果。
    • 增删改:受影响行数单个结果。
    • 查询:单行单列、多行多列、单行多列等结果。

但是Statement 接口在执行SQL语句时,会产生SQL注入攻击问题:当使用 Statement 执行动态构建的 SQL 查询时,往往需要将查询条件与 SQL 语句拼接在一起,直接将参数和SQL语句一并生成,让SQL的查询条件始终为true得到结果。

4.1.4 PreparedStatement

PreparedStatementStatement 接口的子接口,用于执行预编译的 SQL 查询,作用如下:

  • 预编译SQL语句:在创建PreparedStatement时,就会预编译SQL语句,也就是SQL语句已经固定。
  • 防止SQL注入:PreparedStatement 支持参数化查询,将数据作为参数传递到SQL语句中,采用?占位符的方式,将传入的参数用一对单引号包裹起来’',无论传递什么都作为值。有效防止传入关键字或值导致SQL注入问题。
  • 性能提升:PreparedStatement是预编译SQL语句,同一SQL语句多次执行的情况下,可以复用,不必每次重新编译和解析。

实际使用都是基于PreparedStatement进行实现,更安全、效率更高!

4.1.5 ResultSet

ResultSet是 JDBC API 中的一个接口,用于表示从数据库中执行查询语句所返回的结果集。它提供了一种用于遍历和访问查询结果的方式。

  • 遍历结果:ResultSet可以使用 next() 方法将游标移动到结果集的下一行,逐行遍历数据库查询的结果,返回值为boolean类型,true代表有下一行结果,false则代表没有。
  • 获取单列结果:可以通过getXxx的方法获取单列的数据,该方法为重载方法,支持索引和列名进行获取。

4.2 常见问题

4.2.1 资源的管理

在使用JDBC的相关资源时,比如Connection、PreparedStatement、ResultSet,使用完毕后,要及时关闭这些资源以释放数据库服务器资源和避免内存泄漏是很重要的。

4.2.2 SQL语句问题

java.sql.SQLSyntaxErrorException:SQL语句错误异常,一般有几种可能:

  1. SQL语句有错误,检查SQL语句!建议SQL语句在SQL工具中测试后再复制到Java程序中!
  2. 连接数据库的URL中,数据库名称编写错误,也会报该异常!

在这里插入图片描述

4.2.3 SQL语句未设置参数问题

java.sql.SQLException:No value specified for parameter 1

在使用预编译SQL语句时,如果有?占位符,要为每一个占位符赋值,否则报该错误!

在这里插入图片描述

4.2.4 用户名或密码错误问题

连接数据库时,如果用户名或密码输入错误,也会报SQLException,容易混淆!所以一定要看清楚异常后面的原因描述

在这里插入图片描述

4.2.5 通信异常

在连接数据库的URL中,如果IP或端口写错了,会报如下异常:
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

在这里插入图片描述


综上所述,JDBC 技术为 Java 程序与数据库之间的交互搭建了一座坚实的桥梁。通过学习和掌握 JDBC 的基本概念、体系结构以及程序编写步骤,开发者能够更加灵活、高效地进行数据库操作。希望本文能够为使用 JDBC 技术进行数据库开发时提供有益的参考,让在实际项目中能够更加熟练地运用这一强大的工具。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/72542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT入门笔记2

目录 一、前言 二、串口助手实现 2.1、串口 2.1.1、可用串口信息-QSerialPortInfo 2.1.2、打开串口-QSerialPort 2.1.3、串口发送接收信息 2.2、定时器-QTimer 2.3、常用属性类型转换&#xff08;会更新&#xff09; 2.4、子控件组规则命名优化 一、前言 这个是学习Q…

Word 小黑第40套

对应大猫43 主题 -浏览主题 -选择W样式标准文件就行 1级段落和2级段落&#xff08;用项目符号不影响原本段落文字符号 颜色修改为自动&#xff09; 整段变红的 不是把光标定位到红色字体那里 要选择几个红色字体 再创建样式 插入的空白页一定要是下一页&#xff0c;不能插空白…

基于yolo11+flask打造一个精美登录界面和检测系统

这个是使用flask实现好看登录界面和友好的检测界面实现yolov11推理和展示&#xff0c;代码仅仅有2个html文件和一个python文件&#xff0c;真正做到了用最简洁的代码实现复杂功能。 测试通过环境&#xff1a; windows x64 anaconda3python3.8 ultralytics8.3.81 flask1.1.…

SQLMesh系列教程:利用date_spine宏构建日期序列实践指南

引言&#xff1a;为什么需要日期维度表&#xff1f; 在数据分析和报表开发中&#xff0c;日期维度表是不可或缺的基础结构&#xff0c;其中包括一定日期范围的日期序列&#xff0c;每个序列包括对应日期属性&#xff0c;如年季月日、是否周末等。无论是计算日粒度销售额、分析…

【蓝桥杯】省赛:神奇闹钟

思路 python做这题很简单&#xff0c;灵活用datetime库即可 code import os import sys# 请在此输入您的代码 import datetimestart datetime.datetime(1970,1,1,0,0,0) for _ in range(int(input())):ls input().split()end datetime.datetime.strptime(ls[0]ls[1],&quo…

2024浙江大学计算机考研上机真题

2024浙江大学计算机考研上机真题 2024浙江大学计算机考研复试上机真题 2024浙江大学计算机考研机试真题 2024浙江大学计算机考研复试机试真题 历年浙江大学计算机复试上机真题 历年浙江大学计算机复试机试真题 2024浙江大学计算机复试上机真题 2024浙江大学计算机复试机试真题 …

Typora 使用教程(标题,段落,字体,列表,区块,代码,脚注,插入图片,表格,目录)

标题 一个#是一级标题, 2个#是二级标题, 以此类推, 最多可达六级标题 示例 输入#号和标题后回车即可 注意: #和标题内容之间需要存在空格(一个或多个均可), 没有空格就会变成普通文字 标题快捷键 Ctrl数字 1-6 可以快速调成对应级别的标题 (选中文本/把光标放在标题上再按…

C#入门学习记录(三)C#中的隐式和显示转换

C#类型转换&#xff1a;隐式与显式转换的机制与应用 在C#的强类型体系中&#xff0c;数据类型转换是实现数据交互和算法逻辑的基础操作。当数值类型范围存在包含关系&#xff0c;或对象类型存在继承层次时&#xff0c;系统通过预定义的转换规则实现类型兼容处理。隐式转换&…

Linux FILE文件操作2- fopen、fclose、fgetc、fputc、fgets、fputs验证

目录 1.fopen 打开文件 1.1 只读打开文件&#xff0c;并且文件不存在 1.2 只写打开文件&#xff0c;并且文件不存在 1.3 只写打开文件&#xff0c;并且文件存在&#xff0c;且有内容 1.4 追加只写打开文件&#xff0c;并且文件不存在 2. fclose 关闭文件 3. fgetc 读取一…

如何检查CMS建站系统的插件是否安全?

检查好CMS建站系统的插件安全是确保网站安全的重要环节&#xff0c;对于常见的安全检查&#xff0c;大家可以利用以下几种有效的方法和工具&#xff0c;来帮你评估插件的安全性。 1. 检查插件来源和开发者信誉 选择可信来源&#xff1a;仅从官方插件库或可信的第三方开发者处…

使用Dependency Walker和Beyond Compare快速排查dll动态库损坏或被篡改的问题

目录 1、问题描述 2、用Dependency Walker工具打开qr.dll库&#xff0c;查看库与库的依赖关系以及接口调用情况&#xff0c;定位问题 3、使用Beyond Compare工具比较一下正常的msvcr100d.dll和问题msvcr100d.dll的差异 4、最后 C软件异常排查从入门到精通系列教程&#xff…

【CF】Day9——Codeforces Round 953 (Div. 2) BCD

B. New Bakery 题目&#xff1a; 思路&#xff1a; 被标签害了&#xff0c;用什么二分&#xff08; 很简单的思维题&#xff0c;首先如果a > b&#xff0c;那么全选a就行了&#xff0c;还搞啥活动 否则就选 b - a 天来搞活动&#xff0c;为什么&#xff1f; 首先如果我…

【大模型】Transformer、GPT1、GPT2、GPT3、BERT 的论文解析

前言 在自然语言处理&#xff08;NLP&#xff09;和深度学习的快速发展中&#xff0c;Transformer模型和 GPT系列模型扮演了至关重要的角色。本篇博客旨在对这些开创性的论文进行介绍&#xff0c;涵盖它们的提出时间、网络结构等关键信息&#xff0c;能够快速的理解这些模型的设…

OpenGL ES 入门指南:从基础到实战

引言&#xff1a;为什么需要 OpenGL ES&#xff1f; 在当今的嵌入式设备&#xff08;如智能手机、汽车仪表盘、智能家居中控屏&#xff09;中&#xff0c;流畅的图形渲染能力是用户体验的核心。OpenGL ES&#xff08;OpenGL for Embedded Systems&#xff09; 作为行业标准&am…

51单片机指令系统入门

目录 基本概念讲解 一、机器指令​ 二、汇编指令​ &#xff08;一&#xff09;汇编指令的一般格式 &#xff08;二&#xff09;按字节数分类的指令 三、高级指令 总结​ 基本概念讲解 指令是计算机&#xff08;或单片机&#xff09;中 CPU 能够识别并执行的基本操作命令…

AtCoder Beginner Contest 397(ABCDE)

目录 A - Thermometer 翻译&#xff1a; 思路&#xff1a; 实现&#xff1a; B - Ticket Gate Log 翻译&#xff1a; 思路&#xff1a; 实现&#xff1a; C - Variety Split Easy 翻译&#xff1a; 思路&#xff1a; 实现&#xff1a; D - Cubes 翻译&#xff1a…

Spring Cloud Gateway 生产级实践:高可用 API 网关架构与流量治理解析

API 网关的核心价值 在分布式微服务架构中&#xff0c;API 网关作为系统流量的唯一入口&#xff0c;承担着路由分发、安全防护、流量治理三大核心职责。Spring Cloud Gateway 基于响应式编程模型与 Netty 高性能网络框架&#xff0c;提供灵活的路由规则、动态过滤器链和深度集…

在Pycharm配置conda虚拟环境的Python解释器

〇、前言 今天在配置python解释器时遇到了这样的问题 经过一下午自行摸索、上网搜寻后&#xff0c;终于找到的解决的方案&#xff0c;遂将该方法简要的记录下来&#xff0c;以备后用&#xff0c;并希望能帮助到有同样问题或需求的朋友:) 我所使用的软件的版本如下&#xff0c;假…

集成学习(上):Bagging集成方法

一、什么是集成学习&#xff1f; 在机器学习的世界里&#xff0c;没有哪个模型是完美无缺的。就像古希腊神话中的"盲人摸象"&#xff0c;单个模型往往只能捕捉到数据特征的某个侧面。但当我们把多个模型的智慧集合起来&#xff0c;就能像拼图一样还原出完整的真相&a…

Springboot+Vue登录、注册功能(含验证码)(后端!)

我们首先写一个接口&#xff0c;叫login&#xff01;然后对传入一个user&#xff0c;因为我们前端肯定是要传过来一个user&#xff0c;然后我们后端返回一个user&#xff0c;因为我们要根据这个去校验&#xff01;我们还引入了一个hutool的一个东西&#xff0c;在pom文件里面引…