博主简介

registerDriver方法是用于注册驱动的,但是我们之前做的入门案例并不是这样写的。而是如下实现

Class.forName("com.mysql.jdbc.Driver");

我们查询MySQL提供的Driver类,看它是如何实现的,源码如下:

在该类中的静态代码块中已经执行了 DriverManager 对象的registerDriver() 方法进行驱动的注册了,那么我们只需要加载 Driver 类,该静态代码块就会执行。而Class.forName("com.mysql.jdbc.Driver"); 就可以加载Driver 类。

提示:MySQL 5之后的驱动包,可以省略注册驱动的步骤,自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类


  • 获取数据库连接

参数说明:

  • user :用户名
  • password:密码
  • url : 连接路径

语法:

jdbc:mysql://ip地址(域名):端口号/数据库名称" /> 

参与autoCommit 表示是否自动提交事务,true表示自动提交事务,false表示手动提交事务。而开启事务需要将该参数设为为false。

  • 提交事务

  • 回滚事务


案例测试事务管理

  • 编写代码
package com.bby;import java.sql.Connection;import java.sql.DriverManager;import java.sql.Statement;/** * @author BoBooY * @date 2022/10/29 21:47 */public class JdbcTransaction {    public static void main(String[] args) throws Exception {        String url = "jdbc:mysql:///jdbc" />

  • 数据库更新前

  • 数据库更新后

这里程序出现异常,进行了事务的回滚,所以数据都没有被更新

  • 将代码更改正确
String sql2 = "update acount set money = 1002 wher id = 2";
  • 执行程序测试

3.3、Statement

3.3.1、概述

Statement对象的作用就是用来执行SQL语句。而针对不同类型的SQL语句使用的方法也不一样。

  • 执行DDL、DML语句

  • 执行DQL语句

3.3.2、代码演示

此处只展示核心代码,具体代码可以参考上面的代码案例

  • DML语句
// 定义sqlString sql = "update account set money = 3000 where id = 1";// 获取执行sql的对象 StatementStatement stmt = conn.createStatement();// 执行sqlint count = stmt.executeUpdate(sql);  //执行完DML语句,受影响的行数 
  • 执行DDL语句
// 定义sqlString sql = "drop database db2";// 获取执行sql的对象 StatementStatement stmt = conn.createStatement();// 执行sqlint count = stmt.executeUpdate(sql); //执行完DDL语句,可能是0

3.4、ResultSet

3.4.1、概述

ResultSet(结果集对象)作用:封装了SQL查询语句的结果

执行了DQL语句后就会返回该对象,对应执行DQL语句的方法如下:

ResultSet executeQuery(sql):执行DQL 语句,返回 ResultSet 对象

那么我们就需要从 ResultSet 对象中获取我们想要的数据。ResultSet 对象提供了操作查询结果数据的方法,如下:

如下图为执行SQL语句后的结果

一开始光标指定于第一行前,如图所示红色箭头指向于表头行。当我们调用了 next() 方法后,光标就下移到第一行数据,并且方法返回true,此时就可以通过 getInt(“id”) 获取当前行id字段的值,也可以通过 getString(“name”) 获取当前行name字段的值。如果想获取下一行的数据,继续调用 next() 方法,以此类推。

3.4.2、代码演示

  • 编写JdbcResultSet
package com.bby;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.Statement;/** * @author BoBooY * @date 2022/10/30 14:25 */public class JdbcResultSet {    public static void main(String[] args) throws Exception {        Class.forName("com.mysql.jdbc.Driver");        String url = "jdbc:mysql://localhost:3306/jdbc" />

3.5、PreparedStatement

3.5.1、SQL注入

SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

  • 代码模拟SQL注入问题
package com.bby;import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.Statement;/** * @author BoBooY * @date 2022/10/30 14:41 */public class JdbcSqlInjection {    public static void main(String[] args) throws Exception {        Class.forName("com.mysql.jdbc.Driver");        String url = "jdbc:mysql://localhost:3306/jdbc?useSSL=false";        String username = "root";        String password = "1234";        Connection connection = DriverManager.getConnection(url, username, password);        // 接收用户输入 用户名和密码        String name = "abcdefg";        String pwd = "' or '1' = '1";        String sql = "select * from users where name = '" + name + "' and password = '" + pwd + "'";        Statement statement = connection.createStatement();        ResultSet resultSet = statement.executeQuery(sql);        // 判断登录是否成功        if (resultSet.next()) {            System.out.println("登录成功~");        } else {            System.out.println("登录失败~");        }        resultSet.close();        statement.close();        connection.close();    }}

上面代码是将用户名和密码拼接到sql语句中,拼接后的sql语句如下:

select * from users where name = 'abcdefg' and password = '' or '1' = '1'

从上面语句可以看出条件name = 'abcdefg' and password = ''不管是否满足,而 or 后面的 '1' = '1' 是始终满足的,最终条件是成立的,就可以正常的进行登陆了。

  • 所以不管登录的密码是否正确都可以登录成功,控制台输出如下

3.5.2、PreparedStatement 概述

PreparedStatement作用:预编译SQL语句并执行,预防SQL注入问题

  • 获取 PreparedStatement 对象
// SQL语句中的参数值,使用?占位符替代String sql = "select * from users where name = " />

执行上面语句就可以发现不会出现SQL注入漏洞问题了。那么PreparedStatement又是如何解决的呢?它是将特殊字符进行了转
义,转义的SQL如下:

select * from `users` where name = 'abcdefg' and password = '\'or \'1\' = \'1'

3.5.4、PreparedStatement原理

PreparedStatement 好处:1.预编译SQL,性能更高。2.防止SQL注入:将敏感字符进行转义

Java代码操作数据库流程如图所示:

  • 将sql语句发送到MySQL服务器端

  • MySQL服务端会对sql语句进行如下操作

    • 检查SQL语句
      检查SQL语句的语法是否正确。
    • 编译SQL语句。将SQL语句编译成可执行的函数。
      检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
    • 执行SQL语句
  • MySQL服务端将结果返回

4、数据库连接池

4.1、数据库连接池简介

  • 数据库连接池是个容器,负责分配、管理数据库连接(Connection)
  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;
  • 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏
  • 好处:资源重用、提升系统响应速度、避免数据库连接遗漏

之前我们代码中使用连接使没有使用都创建一个Connection对象,使用完毕就会将其销毁。这样重复创建销毁的过程是特别耗费计算机的性能的及消耗时间的。而数据库使用了数据库连接池后,就能达到Connection对象的复用,如下图:

连接池是在一开始就创建好了一些连接(Connection)对象存储起来。用户需要连接数据库时,不需要自己创建连接,而只需要从连
接池中获取一个连接进行使用,使用完毕后再将连接对象归还给连接池;这样就可以起到资源重用,也节省了频繁创建连接销毁连接
所花费的时间,从而提升了系统响应的速度。

4.2、数据库连接池实现

  • 标准接口:DataSource

官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。该接口提供了获取连接的功能:

Connection getConnection()

那么以后就不需要通过 DriverManager 对象获取 Connection对象,而是通过连接池(DataSource)获取 Connection 对象。

  • 常见的数据库连接池:DBCP 、C3P0 、Druid

我们现在使用更多的是Druid,它的性能比其他两个会好一些

  • Druid(德鲁伊)

Druid连接池是阿里巴巴开源的数据库连接池项目,功能强大,性能优秀,是Java语言最好的数据库连接池之一

4.3、Driud 的使用

  • 导入jar包 druid-1.1.12.jar

将druid的jar包放到项目下的lib下并添加为库文件

  • 编写配置文件 druid.properties
driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql:///jdbcuseSSL=false&useServerPrepStmts=trueusername=rootpassword=1234# 初始化连接数量initialSize=5# 最大连接数maxActive=10# 最大等待时间maxWait=3000
  • 编写Java代码(JdbcDruid)
package com.bby;import com.alibaba.druid.pool.DruidDataSourceFactory;import javax.sql.DataSource;import java.io.FileInputStream;import java.sql.Connection;import java.util.Properties;/** * @author BoBooY * @date 2022/10/30 19:12 */public class JdbcDruid {    public static void main(String[] args) throws Exception {        // 加载配置文件        Properties prop = new Properties();        prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));        // 获取连接池对象        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);        // 获取数据库连接 Connection        Connection connection = dataSource.getConnection();        System.out.println(connection); //获取到了连接后就可以继续做其他操作了    }}
  • 运行查看控制台结果

尾言:创作不易,如果本文的内容对您有帮助,还望客官可以三连支持一下博主,(点赞)+✏️(评论)+⭐️(收藏)是我创作的巨大动力!