百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

JDBC和连接池

wxin55 2024-11-20 22:42 7 浏览 0 评论

JDBC是什么?

Java DataBase Connectivity(Java语言连接数据库)

JDBC的本质是什么?

  1. JDBC是Sun公司提供的一套专门用于Java语言和数据库进行链接的API(Application Programma Interface应用程序编程接口)
  2. java.sql.*;(这个软件包下有很多接口)
  3. 接口都有调用者和实现者。面向接口调用、面向接口写实现类,这都属于面向接口编程。

为什么使用JDBC?

Sun公司为了避免Java程序员,每一种数据库软件都学习一套全新的方法,通过JDBC接口将方法名定义好, 让各个数据库厂商根据此接口中的方法名写各自的实现类(就是一个jar文件, 称为数据库的驱动) ,这样Java程序员只需要掌握JDBC接口中方法的调用,即可访问任何数据库软件.


JDBC用途

  1. 与数据库建立连接
  2. 发送 SQL 语句
  3. 处理结果

JDBC接口的本质


为什么要面向接口编程?

//解耦合:降低程序的耦合度,提高程序的扩展力。
//多态机制就是非常典型的:面向抽象编程。(不要面向具体编程)
//		建议:
    Animal a = new Cat();
    Animal a = new Dog();
    // 方法
    public void feed(Animal a){ // 面向父类型编程。
    }
//不建议:
    Dog d = new Dog();
    Cat c = new Cat();

JDBC编程六步

  • 第一步:注册驱动(作用:告诉Java,即将连接的是哪个品牌的数据库)IDEA忽略
  • 第二步:获取连接(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完之后一定要关闭通道。)
  • 第三步:获取数据库操作对象(专门执行sql语句的对象)
  • 第四步:执行SQL语句(DQL DML…)
  • 第五步:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集。)
  • 第六步:释放资源(使用完资源之后一定要关闭资源。Java和数据库属于进程之间的通信,开启之后一定要关闭。)
try {
  // 1、注册驱动
  Class.forName(driver);
  // 2、获取连接
  conn = DriverManager.getConnection(url,user,password);
  // 3、获取数据库操作对象
  stmt = conn.createStatement();
  // 4、执行sql语句
  String sql = "update dept set dname = '销售部',loc = '天津' where deptno = 20";
  int connt = stmt.executeUpdate(sql); 
  System.out.println(count == 1? "修改成功":"修改失败");
  // 5、获取查询结果集
} catch(Exception e){
  e.printStackTrace();
} finally {
  // 6、释放资源
  if(conn != null) {
    try {
      conn.close();
    } catch(SQLException e){
      e.printStackTrace();
    }
  }
  if(stmt != null) {
    try {
      stmt.close();
    } catch(SQLException e){
      e.printStackTrace();
    }
	}
}

IDEA 使用JDBC操作数据库

  • 1).pom.xml文件安装数据库依赖
<!-- 连接MySQL数据库的依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.15</version>
</dependency>
  • 2).JDBC代码
  1. execute("sql"); 此方法可以执行任意SQL语句, 但建议执行DDL(数据库相关和表相关的SQL语句)
  2. int row = executeUpdate("sql"); 此方法用来执行增删改相关的SQL语句, 返回值表示生效的行数
  3. ResultSet rs = executeQuery("sql"); 此方法用来执行查询相关的SQL语句,返回值ResultSet叫做结果集对象,查询到的数据都装在此对象中
try{
  //1.获取链接
  Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/emp?
         charsetEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false","root","root");
   //2.获取数据库操作对象
  Statement s = coon.createStatement();
  //3执行sql
   s.executeUpdate("insert into hero (name,money) values ('"+name+"',"+money+")");
  //4.关闭资源
 conn.close();
 } catch (SQLException throwables) {
   throwables.printStackTrace();
 }

ResultSet里的数据一行一行排列,每行有多个字段,且有一个记录指针,指针所指的数据行叫做当前数据行,我们只能来操作当前的数据行。我们如果想要取得某一条记录,就要使用ResultSet的next()方法 ,如果我们想要得到ResultSet里的所有记录,就应该使用while循环。

JDBC中使用事务

(1)在JDBC中,事务操作缺省是自动提交。

  1. 一条对数据库的DML(insert、update、delete)代表一项事务操作
  2. 操作成功后,系统将自动调用commit()提交,否则自动调用rollback()回滚

(2)在JDBC中,事务操作方法都位于接口java.sql.Connection中

  1. 可以通过调用setAutoCommit(false)来禁止自动提交。
  2. 之后就可以把多个数据库操作的表达式作为一个事务,在操作完成后调用commit()来进行整体提交,
  3. 倘若其中一个表达式操作失败,都不会执行到commit(),并且将产生响应的异常;此时就可以在异常捕获时调用rollback()进行回滚,回复至数据初始状态

(3)事务开始的边界则不是那么明显了,它会开始于组成当前事务的所有statement中的第一个被执行的时候。

(4)事务结束的边界是commit或者rollback方法的调用

Connection connect = null;
String sql = "update ACCOUNT set balance=balance-100 where id=2";
String sql2 = "update ACCOUNT set balance=balance+100 where id=1";
PreparedStatement preparedStatement = null;
try {
  //1.得到连接
  connect = JDBCUtils.connect();
  connect.setAutoCommit(false);   //关闭自动提交
  //2.执行语句
  preparedStatement = connect.prepareStatement(sql);
  preparedStatement.executeUpdate();
  
  preparedStatement = connect.prepareStatement(sql2);
  preparedStatement.executeUpdate();

  //这里提交事务
  connect.commit();
  
} catch (Exception e) {
  //这里可以进行回滚,即撤销执行的sql语句
  //默认回滚到事务开始状态
  System.out.println("执行发生异常,撤销执行的sql");
  try {
    connect.rollback();
  } catch (SQLException throwables) {
    throwables.printStackTrace();
  }
  e.printStackTrace();
}finally {
  //调用工具类关闭资源
  JDBCUtils.close(null,preparedStatement,connect);
}

数据库连接池DBCP DataBaseConnectionPool数据库连接池)

作用: 将连接重用,从而提高执行效率

为什么采用连接池?

数据库连接的建立及关闭是耗费系统资源的操作,在大型应用中对系统的性能影响尤为明显。为了能重复利用数据库连接对象,缩短请求的响应时间和提高服务器的性能,支持更多的客户,应采用连接池技术。

如何使用?

  • 1)pom.xml配置依赖(阿里的为例)
<!-- 数据库连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.21</version>
</dependency>
  • 2)代码
//创建链接对象
DruidDataSource ds = new DruidDataSource();
//设置链接信息
ds.setUrl("jdbc:mysql://localhost:3306/emp?charsetEncoding=utf8&serverTimezone=Asia/Shanghai");
ds.setUsername("root");
ds.setPassword("root");
//设置初始链接数
ds.setInitialSize(3);
//设置最大链接数
ds.setMaxActive(5);
//获取链接
Connection conn = ds.getConnection();

演示SQL注入现象

  1. 当前程序出现的问题
  2. 用户名:fdsa
  3. 密码:fdsa ’ or ‘1’='1
  4. 登录成功 这种现象被称为SQL注入(安全隐患),(黑客经常使用)
// fdsa ’ or ‘1’='1
String  sql = "select * from user where Name = '"+loginName+"' and Pwd = '"+loginPwd+"'";
 //以上正好完成了SQL语句的拼接,以下代码的含义是,发送SQL语句给DBMS,DBMS进行SQL编译
 //正好将用户提供的“非法信息”编译进去,导致原SQL语句的含义被扭曲了。   
resultSet = statement.executeQuery(sql);

用户输入的信息中含有SQL语句的关键字,并且这些关键字参与SQL语句的编译过程【参与编译了这是最关键的原因】

解决SQL注入问题(sql中存在变量则必须防止sql注入)

  1. 只要用户提供的信息不参与SQL语句的编译过程,问题就解决了
  2. 即使用户提供的信息中含有SQL语句的关键字,但是没有参与编译,不起作用
  3. 要想用户信息不参与SQL语句的编译,那么必须使用java.sql.preparedStatement
  4. PreparedStatement接口继承了java.sql.Statement
  5. PreparedStatement是属于预编译的数据库操作对象。
  6. PreparedStatement的原理 是,预先对SQL语句的框架进行编译,然后再给SQL语句传“值”。

【注】编译SQL语句的时间点从之前执行时,提前到了创建对象时, 好处是此时编译用户输入的内容还不在SQL语句里面,只是将原有SQL语句进行编译, 此时可以将原有SQL语句的逻辑部分锁死

//SQL语句的框子。其中一个?,表示一个占位符,一个?将来接收一个“值”,
//【注意】,占位符不能使用单引号括起来。
String  sql = "select * from user where Name = ? and Pwd = ?";
//程序执行到此处,会发送SQL语句的框子给DBMS,然后DBMS进行SQL语句的预先编译。
ps = connection.prepareStatement(sql);
//给占位符?传值(第1个问号下标是1,第2个问号下标是2,JDBC中所有下标从1开始)
ps.setString(1,loginName);
ps.setString(2,loginPwd);
//4.执行SQL
resultSet = ps.executeQuery();

Demo综合案例(登录)

//DB工具类
public class DBUtils {
    private static DruidDataSource ds;
    static {
        //创建连接池对象
        ds = new DruidDataSource();
        //设置数据库连接信息 url 用户名 密码
        ds.setUrl("jdbc:mysql://localhost:3306/emp?characterEncoding=utf8
                  &serverTimezone=Asia/Shanghai&useSSL=false");
        ds.setUsername("root");
        ds.setPassword("root");
        //设置初始连接数量
        ds.setInitialSize(3);
        //设置最大连接数量
        ds.setMaxActive(5);
    }
    public static Connection getConn() throws SQLException {
        //从连接池中获取连接   异常抛出
        Connection conn = ds.getConnection();
        System.out.println("连接对象:"+conn);
        return conn;
    }
}
//登录实现
public static void main(String[] args) {
  Scanner sc = new Scanner(System.in);
  System.out.println("请输入用户名:");
  String username = sc.nextLine();
  System.out.println("请输入密码");
  String password =sc.nextLine();
  //连接,使用工具类
  try(Connection coon = DBUtils.getConn()) {
    Statement s = coon.createStatement();
    //有sql注入风险
 //  ResultSet rs =s.executeQuery("select username,password from user where username ='"+username+"'");
   
    //使用PreparedStatement 防止sql注入
    String sql = "select username,password from user where username =?";
    PreparedStatement ps = coon.prepareStatement(sql);
    ps.setString(1,username);
    ResultSet rs = ps.executeQuery();
    //没有查到,代表账号不存在
    if(!rs.next()){
      System.out.println("用户名不存在!");
      return;
    }
    //判断密码是否正确
    if(password.equals(rs.getString("password"))){
      System.out.println("恭喜你,登录成功!");
      return;
    }
    System.out.println("密码错误,登录失败");
  } catch (SQLException throwables) {
    throwables.printStackTrace();
  }
}

JDBC API总结

  • 1、Connection接口

作用:代表数据库连接

  • 2、DriverManager类

作用:管理一组 JDBC 驱动程序的基本服务

应用程序不再需要使用 Class.forName() 显式地加载 JDBC 驱动程序。在调用 getConnection 方法时,DriverManager 会试着从初始化时加载的那些驱动程序以及使用与当前 applet 或应用程序相同的类加载器显式加载的那些驱动程序中查找合适的驱动程序

  • 3、Statement接口

作用:用于将 SQL 语句发送到数据库中,或理解为执行sql语句

  1. Statement:用于执行不带参数的简单SQL语句;
  2. PreparedStatement 从 Statement 继承:用于执行带或不带参数的预编译SQL语句;
  3. CallableStatement 从PreparedStatement 继承:用于执行数据库存储过程的调用。
  • 4、PreparedStatement接口

关系:public interface PreparedStatement extends Statement

  1. PreparedStatment安全性高,可以避免SQL注入
  2. PreparedStatment简单不繁琐,不用进行字符串拼接
  3. PreparedStatment性能高,用在执行多个相同数据库DML操作时

5、ResultSet接口

  1. ResultSet对象是executeQuery()方法的返回值,它被称为结果集,它代表符合SQL语句条件的所有行,并且它通过一套getXXX方法(这些get方法可以访问当前行中的不同列)提供了对这些行中数据的访问。
  2. ResultSet里的数据一行一行排列,每行有多个字段,且有一个记录指针,指针所指的数据行叫做当前数据行,我们只能来操作当前的数据行。我们如果想要取得某一条记录,就要使用ResultSet的next()方法 ,如果我们想要得到ResultSet里的所有记录,就应该使用while循环。
  3. ResultSet对象自动维护指向当前数据行的游标。每调用一次next()方法,游标向下移动一行。
  4. 初始状态下记录指针指向第一条记录的前面,通过next()方法指向第一条记录。循环完毕后指向最后一条记录的后面。

学习记录,如有侵权请联系删除。

相关推荐

ES6中 Promise的使用场景?(es6promise用法例子)

一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...

JavaScript 对 Promise 并发的处理方法

Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...

Promise的九大方法(promise的实例方法)

1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...

360前端一面~面试题解析(360前端开发面试题)

1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...

前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?

Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...

最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式

看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...

前端分享-Promise可以中途取消啦(promise可以取消吗)

传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...

手写 Promise(手写输入法 中文)

前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...

什么是 Promise.allSettled()!新手老手都要会?

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...

前端面试-关于Promise解析与高频面试题示范

Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...

宇宙厂:为什么前端离不开 Promise.withResolvers() ?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...

Promise 新增了一个超实用的 API!

在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...

一次搞懂 Promise 异步处理(promise 异步顺序执行)

PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...

Promise 核心机制详解(promise机制的实现原理)

一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...

javascript——Promise(js实现promise)

1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...

取消回复欢迎 发表评论: