Java学习笔记-JDBC

这篇博客详细介绍了Java中使用JDBC进行数据库操作,包括JDBC的简介、体系结构、核心组件、CRUD操作、连接步骤、SQL执行、PreparedStatement与Statement的比较、ResultSet的使用、以及数据库事务的管理。还探讨了Java如何处理两表关系,如一对多、多对一、一对一和多对多关系,并给出了实例代码。最后,提到了JDBC批处理和反射处理结果集的方法,以及连接池的使用,如DBCP、C3P0和Druid等。
摘要由CSDN通过智能技术生成

JDBC

简介

JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序
​
Java具有坚固、安全、易于使用、易于理解和可从网络上自动下载等特性,是编写数据库应用程序的杰出语言。所需要的知识Java应用程序与各种不同数据库之间进行对话的方法。
​
JDBC可以在各种平台上使用Java,如Windows,Mac OS和各种版本的UNIX
​
JDBC库包括通常与数据库使用相关的下面提到的每个任务的API
- 连接数据库
- 创建SQL或MySQL语句
- 在数据库中执行SQL或MySQL查询
- 修改和查看生成的记录

JDBC体系结构

JDBC API支持用于数据库访问的两层和三层处理模型,但通常,JDBC体系结构由两层组成:
    -JDBC API:这提供了应用程序到JDBC管理器连接
    -JDBC驱动程序API:这支持JDBC管理器到驱动程序连接
    JDBC API使用驱动程序管理器和特定于数据库的驱动程序来提供与异构数据库的透明连接

 

JDBC核心组件

DriverManager:此类管理数据库驱动程序列表。使用通信子协议将来自Java应用程序的连接请求与适当的数据库驱动程序匹配
​
Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互。而是使用DriverManager对象来管理这种类型的对象
​
Connection:该界面具有用于联系数据库的所有方法。连接对象表示通信上下文,即,与数据库的所有通信仅通过连接对象
​
Statement:使用从此接口创建的对象将SQL语句提交到了数据库。除了执行存储过程之外,一些派生接口还接收参数
​
ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为一个迭代器,允许我们移动其数据
​
SQLException:此类处理数据库应用程序中发生的任何错误

CRUD语法介绍

SQL是一种标准化的语言,它允许你在数据库上执行操作,如创建项目,查询内容,更新内容,并删除条目等操作
Create, Read, Update, and Delete 通常称为CRUD操作。
​
CREATE DATABASE语句用于创建新的数据库:
 CREATE DATABASE DATABASE_NAME;
 
 DROP DATABASE语句用于删除现有数据库:
 DROP DATABASE DATABASE_NAME;
 
 CREATE TABLE语句用于创建新表。语法是:
 CREATE TABLE Employees ( 
     id INT NOT NULL, 
     age INT NOT NULL, 
     first VARCHAR(255), 
     last VARCHAR(255), 
     PRIMARY KEY ( id ) 
 );
 
 DROP TABLE语句用于删除现有表。
 DROP TABLE table_name;
 
 INSERT的语法类似于以下内容,其中column1,column2等表示要显示在相应列中的新数据
 INSERT INTO table_name VALUES (column1, column2, ...);
 
 SELECT语句用于从数据库中检索数据。SELECT的语法是:
 SELECT column_name, column_name, ... FROM table_name WHERE conditions;
 WHERE子句可以使用比较运算符,例如=,!=,<,>,<=和> =,以及BETWEEN和LIKE运算符。
 
 UPDATE语句用于更新数据:
 UPDATE table_name 
 SET column_name = value, column_name = value, ... 
 WHERE conditions;
 WHERE子句可以使用比较运算符,例如=,!=,<,>,<=和> =,以及BETWEEN和LIKE运算符。
 
 DELETE语句用于从表中删除数据:
 DELETE FROM table_name WHERE conditions;
 WHERE子句可以使用比较运算符,例如=,!=,<,>,<=和> =,以及BETWEEN和LIKE运算符。
 
 

使用步骤

构建JDBC应用程序涉及以下六个步骤:
1.添加依赖
2.注册JDBC驱动程序:要求初始驱动程序,以便可以打开与数据库的通信通道
3.打开链接:需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表示与数据库的物理链接
4.执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库
5.从结果集中提取数据:需要使用相应的ResultSet.getxxx()方法从结果集中检索数据
6.释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾回收

JDBC连接步骤

JDBC连接步骤

建立JDBC连接所涉及的编程相当简单。这是简单的四个步骤
    1.引入依赖
    2.注册JDBC驱动程序:此步骤将使JVm将所需的驱动程序实现加载到内存中,以便它可以满足您的JDBC请求
    3.数据库URL配置:这是为了创建一个格式正确的地址,指向要连接到的数据库
    4.创建连接对象:最后,调用DriverManager对象的getConnection()方法来建立实际的数据库连接

Class.forName()

Class.forName():注册驱动程序最常见的方法是使用Java的Class.froName()方法,将驱动程序的类文件动态加载到内存中,并将其自动注册
try {
    Class.forName("com.mysql.cj.jdbc.Driver"); 
}catch(ClassNotFoundException ex) { 
    System.out.println("Error: unable to load driver class!");
    System.exit(1); 
}

DriverManager.registerDriver()

DriverManager.registerDriver():
    第二种方法就是使用静态DriverManger.registerDriver()方法。
    try {
        Driver myDriver = new com.mysql.cj.jdbc.Driver(); 
        DriverManager.registerDriver( myDriver ); 
    }catch(ClassNotFoundException ex) { 
        System.out.println("Error: unable to load driver class!"); System.exit(1); 
    }

数据库URL配置

加载驱动程序后,可以使用DriverManager.getConnection()方法建立连接。为了方便参考,让我列出三个重载的DriverManager.getConnection()方法
- getConnection(String url) 
- getConnection(String url,Properties prop) 
- getConnection(String url,String user,String password)
RDBMS JDBC驱动程序名称 网址格式
MYSQL8 com.mysql.cj.jdbc.Driver jdbc:mysql://hostname:3306/databaseName?serverTimezone=UTC
MYSQL com.mysql.jdbc.Driver jdbc:mysql://hostname:3306/databaseName
ORACLE oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:@hostname:port Number:databaseName
DB2 COM.ibm.db2.jdbc.net.DB2Driver jdbc:db2:hostname:port Number / databaseName
SYBASE com.sybase.jdbc.SybDriver jdbc:sybase:Tds:hostname:port Number / databaseName

创建数据库连接对象

String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC"; 
String USER = "username"; 
String PASS = "password";
Connection conn = DriverManager.getConnection(URL, USER, PASS);

完整的连接地址:
版本1:
    jdbc:mysql://localhost:3306/数据库名? useSSL=false&useUnicode=true&characterEncoding=UTF-8
版本2:
    jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC

使用数据库URL和属性对象

DriverManager.getConnection()方法的第三种形式需要一个数据库URL和一个Properties对象
DriverManager.getConnection(String url, Properties info);

import java.util.*; 
String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC"; 
Properties info = new Properties( ); 
info.put( "user", "username" ); 
info.put( "password", "password" ); 
Connection conn = DriverManager.getConnection(URL, info);

关闭数据库连接

为确保连接关闭,可以在代码中提供一个finally块,finally块总是执行,不管是否发生异常。要关闭上面打开的连接,应该调用close()方法
conn.close();

JDBC执行SQL语句

一旦获得了连接,我们可以与数据库进行交互。JDBC Statement和PreparedStatement接口定义了能够发送SQL命令并从数据库接收数据的方法和属性

Statement

创建语句对象
在使用Statement对象执行SQL语句之前,需要使用Connection对象的createStatement()方法创建一个
示例:
    Statement stmt = null; 
    try {
        stmt = conn.createStatement(); 
        . . . 
    }catch (SQLException e) {
        . . . 
    }finally { 
        . . . 
    }
创建Statement对象后,可以使用它来执行一个SQL语句,其中三个执行方法之一
    
- boolean execute(String SQL):如果可以检索到ResultSet对象,则返回一个布尔值true;否则返回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时
    
- int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响多个行的SQL语句,例如INSERT,UPDATE或DELETE语句
    
- ResultSet executeQuery(String SQL):返回一个ResultSet对象。当希望获得结果集时,使用此方法,就像使用SELECT语句一样
    
关闭Statement对象
    就像我们关闭一个Connection对象以保存数据库资源一样,由于同样的原因,还应该关闭Statement对象。
    一个简单的调用close()方法将执行该作业,如果先关闭Connection对象,它也会关闭Statement对象,但是,应始终显示关闭Statement对象,以确保正确清理
    Statement stmt = null; 
    try {stmt = conn.createStatement(); 
         . . . 
    }catch (SQLException e) { 
        . . . 
    }finally { 
        stmt.close(); 
    }

SQL注入

就是通过吧SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。棘突来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句,比如先前的很多影视网站泄漏VIP会员密码大多就是通过Web表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击
​
String username ="admin"; 
String password=" 'abc' or 1=1 "; 
String sql="select * from users where username= '"+username+"' and password= "+password;

PreparedStatement(预状态通道)

该PreparedStatement的接口扩展了Statement接口,提供了一个通用的Statement对象,有两个优点附加功能
此语句可以动态地提供参数
PreparedStatement pstmt = null; 
try {
    String SQL = "Update Employees SET age = ? WHERE id = ?"; 
    pstmt = conn.prepareStatement(SQL); 
    . . }
catch (SQLException e) {
    . . . }
finally { 
    . . . 
}

JDBC中的所有参数都由? 来做占位符,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。所述的setxxx()方法将值绑定到所述参数,其中xxx代表要绑定到输入参数化的值的Java数据类型。如果忘记提供值,将收到一个SQLException

每个参数标记由其顺序位置引用。第一个标记表示位置1,下一个位置2等等..。该方法与Java数组从0开始的索引不同。

关闭PreparedStatement对象

就像关闭Statement对象一样,由于同样的原因,还应该关闭PreparedStatement对象
一个简单的调用close()方法将执行该作业。如果关闭Connection对象,它也会关闭PreparedStatement对象。但是,应始终显式关闭PreparedStatement对象,以确保正确清理
PreparedStatement pstmt = null; 
try {
    String SQL = "Update Employees SET age = ? WHERE id = ?"; 
    pstmt = conn.preparedStatement(SQL); 
    . . . }
catch (SQLException e) { 
    . . . }
finally { 
    pstmt.close(); 
}

对比Statement和PreparedStatement

1.Statement属于状态通道,PreparedStatement属于与状态通道
2.预状态通道会先编译sql语句,再去执行,比statement执行效率高
3.预状态通道支持占位符? ,给占位符赋值的时候,位置从1开始
4.预状态通道可以防止sql注入,原因:预状态通道在处理值的时候以字符串的方式处理

ResultSet

select语句是从数据库中选择行并在结果集中查看行的标准方法。该java.sql.ResultSet的接口表示结果集数据库查询

ResultSet对象维护指向结果集中当前行的游标。术语"结果集"是指包含在ResultSet对象中的行和列数据。

如果没有指定任何ResultSet类型,将自动获得一个TYPE_FORWARD_ONLY。
类型 描述
ResultSet.TYPE_SCROLL_INSENSITIVE 光标可以向前和向后滚动,结果集对创建结果集后发生的数据的其他改变不敏感
ResultSet。TYPE_SCROLL_SENSITIVE 光标可以向前和向后滚动,结果集对创建结果集之后发生的其他数据库所做的更改敏感
ResultSet.TYPE_FORWARD_ONLY 光标只能在结果集中向前移动
try {
    Statement stmt = conn.createStatement(
        ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_READ_ONLY); 
}
catch(Exception ex) { 
    .... }
finally { 
    .... 
}

JAVA操作两表关系

四种:双向一对一,一对多,多对一,多对多
多表关系处理数据
1.数据库通过外键建立两表关系
2.实体类通过属性的方式建立两表关系
    实体类要求:类名=表名,列名=属性名

一对多(老师-->学生)

  1. 创建数据库表

    • CREATE TABLE `student` ( 
          `stuid` int(11) NOT NULL AUTO_INCREMENT, 
          `stuname` varchar(255) DEFAULT NULL, 
          `teacherid` int(11) DEFAULT NULL, 
          PRIMARY KEY (`stuid`) 
      ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8; 
      INSERT INTO `student` VALUES ('1', 'aaa', '3');
      INSERT INTO `student` VALUES ('2', 'bb', '1');
      INSERT INTO `student` VALUES ('3', 'cc', '3'); 
      INSERT INTO `student` VALUES ('4', 'dd', '1'); 
      INSERT INTO `student` VALUES ('5', 'ee', '1'); 
      INSERT INTO `student` VALUES ('6', 'ff', '2'); 
      DROP TABLE IF EXISTS `teacher`; 
      ​
      CREATE TABLE `teacher` ( 
          `tid` int(11) NOT NULL AUTO_INCREMENT, 
          `tname` varchar(255) DEFAULT NULL, 
          PRIMARY KEY (`tid`) 
      ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; 
      INSERT INTO `teacher` VALUES ('1', '张三老师'); 
      INSERT INTO `teacher` VALUES ('2', '李四老师'); 
      INSERT INTO `teacher` VALUES ('3', '王五');
  2. 创建实体类

    • public class Teacher {
          private int tid;
          private String tname;
          private List<Student> list=new ArrayList<Student>();
          public List<Student> getList() {
              return  list;
          }
          public void setList(List<Student> list) {
              this.list = list;
          }
          public int getTid() {
              return tid;
          }
          public void setTid(int tid) {
              this.tid = tid;
          }
          public String getTname() {
              return tname;
          }
          public void setTname(String tname) {
              this.tname = tname;
          }
      }
      ​
      public class Student {
          private int stuid;
          private String stuname;
          //外键列一般不生成属性
          // private int teacherid;
          public int getStuid() {
              return stuid;
          }
          public void setStuid(int stuid) {
              this.stuid = stuid;
          }
          public String getStuname() {
              return stuname;
          }
          public void setStuname(String stuname) {
              this.stuname = stuname;
          }
      }
  3. 定义dao接口

    • public interface TeacherDao {
          //定义操作方法
          //1.定义一个根据老师id查询老师信息(学生的信息)
          public Teacher
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值