草庐IT

JDBC

苏无及 2023-03-28 原文

JDBC

一、JDBC概述

什么是JDBC?

JDBC 是使用 Java 语言操作关系型数据库的一套 API。这套 API 是交由不同的数据库厂商实现的。我们利用 JDBC 编写操作数据库的代码,真正执行的是各个数据库的实现类驱动)。

全称:(Java DataBase Connectivity)Java 数据库连接。

JDBC的好处

  • 面向接口编程,屏蔽实现上的差异。
  • 一套 Java 代码操作不同数据库。、

二、使用JDBC

环境配置

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.29</version>
</dependency>

编码

步骤

  1. 引入驱动并注册
  2. 获取连接
  3. 定义SQL
  4. 获取执行SQL对象
  5. 执行SQL
  6. 处理返回结果
  7. 释放资源

代码实现

public static void demo(){
    Connection conn = null;
    Statement state = null;
    try {
        // 1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        // 2.获取连接
        conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
        // 3.定义SQL
        String sql = "select * from user";
        // 4.获取Statement对象
        state = conn.createStatement();
        // 5.执行SQL
        ResultSet resultSet = state.executeQuery(sql);
        // 6.处理返回结果
        System.out.println(resultSet);
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    } finally {
        // 7.关闭资源
        if (state != null) {
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

注意

  • 最晚获得的资源最先关闭。

  • Mysql8 之前的驱动类全类名为 com.mysql.jdbc.DriverMysql8之后则为 com.mysql.cj.jdbc.Driver

三、JDBC API

DriverManager

作用

  • 注册驱动
  • 获取数据库连接

这两个作用对应着两个方法:

方法 作用
getConnection(String url, String user, String password) 通过给定的URL与数据库建立连接,并返回连接对象
registerDriver(Driver driver) 注册给定的驱动 Driver

Mysql 驱动底层通过静态代码块调用了DriverManagerregisterDriver方法,所以我们不必去显式的进行驱动的注册,它已经帮我们注册好了。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

注意

如果导入 MySQL5 之后的驱动 jar包,可以不用写 Class.forName("com.mysql.cj.jdbc.Driver");,Driver 会自动读取 java.sql.Driver文件中的驱动类全限定名,进行驱动的注册。

Connection

作用

  • 获取执行SQl的对象
  • 管理事务

执行SQL的对象

  • Statement

    普通的执行对象,将获得的字段拼接在SQl语句上,然后在执行编译,有SQl注入攻击的风险。

  • PerparedStatement

    对SQL进行预编译的执行对象,先对SQl语句进行编译,再用字段将替换掉。

  • CallableStatement

    执行存储过程的对象。

事务管理

方法 说明
setAutoCommit(boolean) 开启事务。true:自动提交事务,false:开启手动提交事务
commit() 提交事务
rollback() 回滚事务
try {
    // 开启事务
    conn.setAutoCommit(false);
    // 执行操作一
    int i = state.executeUpdate(sql1);
    System.out.println(i);
    // 制造异常
    int j = 1/0;
    // 执行操作二
    int i1 = state.executeUpdate(sql2);
    System.out.println(i1);
    // 提交事务
    conn.commit();
} catch (Exception e) {
    // 事务回滚
    conn.rollback();
    e.printStackTrace();
}

Statement

作用

执行 sql 语句。

方法

方法 说明
int executeUpdate(String sql) 执行给定的SQL语句,这可能是 INSERTUPDATE ,或 DELETE语句,或者不返回任何内容,如SQL DDL语句的SQL语句。并返回受影响的行数。
ResultSet executeQuery(String sql) 执行给定的SQL语句,该语句返回单个 ResultSet对象。

ResultSet

作用

封装了查询语句的执行结果,Statement 或者 PreparedStatement 通过执行 executeQuery 方法返回 ResultSet 对象。

方法

方法 说明
getXxx() 获取每行中各个数据,可以传入 列号(从1开始) 或者 列名
next() 向下移动指针,判断该行是否有数据。

// 6.处理返回结果
while (resultSet.next()) {
    String name = resultSet.getString("name");
    System.out.println(name);
    String password = resultSet.getString(3);
    System.out.println(password);
}

PerparedStatement

作用

执行 sql 语句,但是它会对 SQl 语句进行预编译,可以防止 SQl 注入攻击。并且 PreparedStatement 继承自 Statement

SQl注入

在编译之前利用 SQl 语句的拼接,输入特殊字符串修改定义好的 SQL 语句,改变 SQL 语句的语义。

一个简单的 SQL 注入演示:

(比如是有一个用户登录的场景,在 DAO 层中进行数据库操作)

String sql = "select * from user where username='"+admin+"' and password='"+'or'1'='1+"'";

用户密码一看就不正经,但是可以看一下拼接好的 SQL 语句是怎样的:

select * from user where username='admin' and password=''or'1'='1'

password 变成了空字符串,在 SQL 语句的尾部 拼接了 or '1'='1' 。username 和 password 查询为false,但是接着又 or 一个恒等式,整体结果就变成了 true,将会查询出所有结果。

预编译

PreparedStatement 的使用步骤:

// 3.定义SQL
String sql = "select * from user where name=? and password=?";
// 4.获取PreparedStatement对象
PreparedStatement statement = conn.prepareStatement(sql);
// 4.5替换占位符
statement.setString(1,"黑夫");
statement.setString(2,"123");
// 5.执行SQL
ResultSet resultSet = statement.executeQuery();

在定义 SQL 语句时,SQL 中未知字段使用 进行占位。

可以看到在获取 PreparedStatement 对象的同时,就需要将 SQL 传入,这时会将 SQL 语句发送给 mysql 服务器,进行检查语法、编译等。

为什么能达到防止 SQL 注入的效果?

SQL 语句在执行之前已经进行了编译,它的结构已经被固定下来,当运行时动态地把参数传给 PreprareStatement 时,即使参数里有敏感字符如 or '1=1'数据库会将它作为一个参数一个字段的属性值来处理而不会作为一个 SQL 指令。而且 PreparedStatement 在用具体字段替换占位符时,会对特殊字符进行转义,比如单引号 ' 会转义为 \'。如此,可以有效的防止 SQL 注入。

可以在 url 后面加上命令开启预编译:useServerPrepStmts=true。不写这句,仍会对特殊字符进行转义。

jdbc:mysql://localhost:3306/test?useSSL=false&useServerPrepStmts=true

useSSL=false 表示不进行安全连接。

预编译的好处

  • 防止 SQL 注入

  • 一次编译、多次运行,省去了解析优化等过程

    在执行 SQL 时,很多 SQL 语句都是结构相同的,只是个别字段不同,如果对每一条 SQL 进行编译,那么运行速度将大大降低。预编译时会将编译过后的SQL语句进行缓存,当有结构相同的 SQL 语句需要执行时,只需用属性值替换掉占位符即可,不需要重新词法语义解析语句优化制定执行计划编译等,从而提高效率。

关于更多 PreparedStatement 的了解,看这篇博文:

预编译语句(Prepared Statements)介绍,以MySQL为例

四、数据库连接池

简介

数据库连接池是负责分配、管理和释放数据库连接的容器,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。

对于多用户的应用,如果为每一个用户都创建一个数据库连接,毫无疑问是对资源的浪费,同时也浪费时间。我们应当在系统加载的时候就将数据库资源创建好,不推荐运行时再去开启资源。做到对资源的统一管理,从而避免资源浪费,提升响应速度。

使用

SUN 公司提供了数据库连接池的标准接口 DataSource 由第三方组织进行实现。

推荐使用 Druid 数据库连接池技术。

环境搭建

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.11</version>
</dependency>

在resources目录下新建 druid.properties 配置文件

driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/test
username = root
password = root
# 初始化连接数
initialSize = 5
# 最大连接数
maxActive = 10
# 最大等待时间
maxWait = 3000

maxWait 表示如果连接池中没有空闲连接的最大等待时间,超过时间则会抛出异常。

更多配置参考:Configuration reference

获取连接

// 1.加载配置文件
Properties properties = new Properties();
properties.load(ClassLoader.getSystemResourceAsStream("druid.properties"));
// 2.获取连接
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
conn = dataSource.getConnection();

有关JDBC的更多相关文章

  1. 【JAVAEE】JAVA数据库连接(JDBC) - 2

    1.什么是JDBC?Java数据库连接,(JavaDatabaseConnectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是SunMicrosystems的商标。我们通常说的JDBC是面向关系型数据库的。简而言之,JDBC就是JDK提供的关于数据库操作的一套接口规范,不同数据库厂商来负责实现这个接口,完成指定的操作。用程序和数据建立连接,分为三步骤:1.连接数据库2.执行SQL语句3.把查询到的结果集转换成JAVA对象2.对于MySQL的JDBC编程的前期准备工作知识拓展:JAR文件(Java归

  2. MySQL的JDBC 编程 - 2

    目录1.数据库编程:JDBC2.JDBC工作原理3.JDBC使用3.1驱动包的下载与导入3.2JDBC使用步骤(插入)4.JDBC修改删除查询1.将数据库驱动包,添加到项目依赖中创建目录,拷贝jar包,然后addaslibrary2.创建数据源DataSourse:数据源,描述了数据库服务器在哪里3.和数据库建立连接使用JDBC里的Connection将代码和数据库服务器进行连接一个程序中,通常有一个数据源对象,可以有多个Connection对象4.构造sql语句PreparedStatement:表示一个预处理过的SQL语句对象5.执行sql语句(1)executeUpdate对应插入到删除

  3. oracle - Golang用的是JDBC还是ODBC或者什么连接类型 - 2

    goversiongo1.8.1windows/amd64我正在导入"github.com/mattn/go-oci8""database/sql"用于连接到我的oracle数据库。在这里,当我在连接字符串中提供数据库用户名、密码、端口和表名时funcopenAndConnectToDb(sbconfigConnectorConfig)*sql.DB{logger:=sbgoclient.Loglogger.Println("Openthedatabase")//oraprop:=LoadConfig("oraproperties.yml")fmt.Println("Loadconfi

  4. xml - 将 JDBC url 从 Maven 传递到 hibernate.cfg.xml - 2

    我有一个hibernate.cfg.xml,其中配置了JDBCUrl:jdbc:mysql://${server.hostname}:3306/dsm?zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=true&autoReconnect=true这些&是必需的(而不仅仅是&)以避免异常:对实体“jdbcCompliantTruncation”的引用必须以“;”结尾分隔符。为了能够通过Maven选择不同的目标数据库,我想将其更改为:${jdbc.url}其中${jdbc.url}是Maven中定义的属性

  5. java - Spring 3 applicationContext-security-JDBC.xml 有 bean :bean not bean? - 2

    有人可以告诉我在我的ApplicationContext中我必须使用beans:bean而不是bean的什么以及如何修复它。 最佳答案 说明。基本上,您在这里处理的是XML命名空间。Spring配置允许您使用来自不同命名空间的配置元素作为一种扩展基本beans命名空间配置的方式,具有方便的特定于域的配置,如上述案例中的安全配置。如果您的配置文件集中在这些扩展命名空间之一——再次,让我们以安全性为例——如果您将默认命名空间声明为扩展命名空间而不是标准beans命名空间。就是这样xmlns="http://www.springframe

  6. java - 从 JDBC 结果集中获取 XML 的最佳方式 - 2

    我正在寻找从JDBC结果集中获取XML文档的最佳方法。XML的结构不是很重要,但它应该相当快。为了清楚起见,我想要结果集中的数据和足够的元数据来识别数据(本质上是字段名称)。我目前正在使用MySQL、DB2、SQLServer,但解决方案需要与数据库无关(对于SQLServer中的XML不是一个可行的选择)。 最佳答案 通过使用WebRowSet,一次可以将整个ResultSet转换成XML。WebRowSet生成的XML非常清晰和简单,我不确定速度,因为它还取决于驱动程序实现。这里有一篇关于WebRowSetusingOracle

  7. java - Log4j2 - 如何将 XML 配置转换为 JDBC appender 的 .properties 格式 - 2

    如何将此log4j2.xml配置片段转换为log4j2.properties格式?我不能在我的maven+netbeans项目中使用XML格式,因为我根本无法让log4j2解析和响应log4j2.xml文件-无论我将它放在项目中的什么位置,它都会被log4j2忽略。但是main/resource中的log4j2.properties被解析并响应,所以我-必须-使用.properties...:我通过官方ApacheMavenlog4j工件使用log4j22.10.0。什么是-correct-log4j2.properties配置才能100%等同于上述配置?我几乎连续两天都在让JDBCa

  8. Java:Oracle XMLType + JDBC - 2

    如何将oracleXMLElement获取到JDBC?java.sql.Statementst=connection.createStatement();//worksoracle.jdbc.OracleResultSetrs=st.execute("SELECTXMLElement("name")FROMdual");rs.getString(1);//returnsnull,why?oracle.sql.OPAQUE=(OPAQUE)rs.getObject(1);//thisworks,butwtfisOPAQUE?基本上,我想读取像这样的字符串或任何XML格式的输出。但是我总是

  9. xml - 最好的 JDBC 数据源 bean 类 - 2

    我看到有些人使用org.apache.commons.dbcp.BasicDataSource而其他配置有com.mchange.v2.c3p0.ComboPooledDataSource。Spring有自己的:org.springframework.jdbc.datasource.DriverManagerDataSource可能还有更多。但哪个最好?我有一个需要连接池的JPA/Hibernate三层应用程序,但看起来它们都支持这个.... 最佳答案 Springhasitsown:org.springframework.jdbc

  10. sql-server - Windows 2003 中 JDBC 连接可用的套接字数 - 2

    我的团队使用带有JTDS驱动程序的纯JDBC(无连接池),用Java构建了一个连接到Windows2003Server中的SQLServer2005的Windows服务。一段时间后,打开数据库连接的方法开始使用以下堆栈跟踪引发异常:java.net.BindException:Addressalreadyinuse:connectatjava.net.PlainSocketImpl.socketConnect(NativeMethod)atjava.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)atjava.net.Pla

随机推荐