JDBC基础

需求

​ 早期的数据库应⽤程序开发,因为没有通⽤的针对于数据库的编程接⼝,所以,开发⼈员需要学习相关数据库的API,才可以进⾏应⽤程序,这样增加了学习成本和开发周期。因此整个开发市场⼀直在呼吁有⼀套通⽤的编程接⼝

ODBC

​ 因为有市场需要,微软定义了⼀组⽤于数据库应⽤程序的编程接⼝ODBC(open database connectivity)。这⼀套⽅案⼤⼤缩短了程序的开发周期,可以让开发⼈员只需要调⽤同⼀套编程接⼝,⽆需考虑具体实现。

在这里插入图片描述

ODBC分为四个部分:

1. 应⽤程序:开发⼈员所写的代码,ODBC提供的调⽤接⼝
2. 驱动程序管理器:⽤于管理驱动程序的。
3. 驱动程序:对接⼝的实现部分,各个数据库⼚商来完成的。
4. 数据源:就是连接数据库的⼀些参数:url,username,password

JDBC

​ Sun公司参考了ODBC⽅案,制定了⼀组专⻔为java语⾔连接数据库的通⽤接⼝JDBC。⽅便了java开发⼈员,开发⼈员不需要考虑特定的数据库的DBMS。JDBC不直接依赖于DBMS,⽽是通过驱动程序将sql语句转发给DBMS,由DBMS进⾏解析并执⾏,处理结果返回。

**注意:**驱动程序:由数据库⼚商⾃⼰实现,程序员只需要拿来使⽤即可。

在这里插入图片描述

JDBC的⼯作原理

在这里插入图片描述

第⼀步:注册驱动程序
第⼆步: 请求连接
第三步: 获取执⾏sql语句的对象,发送给DBMS
第四步:返回结果集,程序员进⾏处理
第五步: 关闭连接操作

JDBC中常⽤的接⼝和类

概述

​ JDBC与数据库驱动的关系:
接⼝与实现的关系。
​ JDBC规范(掌握四个核⼼对象):
DriverManager:⽤于注册驱动
Connection: 表示与数据库创建的连接
Statement: 操作数据库sql语句的对象
ResultSet: 结果集或⼀张虚拟表

​ 开发⼀个JDBC程序的准备⼯作:
JDBC规范在哪⾥:
JDK中:
java.sql.;
javax.sql.
;
数据库⼚商提供的驱动:jar⽂件

*.ja
在这里插入图片描述

java.sql.DriverManager

a.注册驱动
DriverManager.registerDriver(new com.mysql.jdbc.Driver());不建议使⽤
原因有2个:

导致驱动被注册2次。
强烈依赖数据库的驱动jar
解决办法:

//5.0使用方式

Class.forName(“com.mysql.jdbc.Driver”);

//8.0版本使用方式

Class.forName(“com.mysql.cj.jdbc.Driver”);

b.与数据库建⽴连接

⽅法名字:
static Connection getConnection(String url, String user, String
password)

试图建⽴到给定数据库 URL 的连接。
url: 连接指定数据库的地址 jdbc:mysql://ip:port/dbname
user: 连接⽤户名
password:密码
getConnection("jdbc:mysql://localhost:3306/day06", "root","root");

对URL的解释:
URL:SUN公司与数据库⼚商之间的⼀种协议。
jdbc:mysql://localhost:3306/day06
//上面URL是5.0版本使用的方式,下面为8.0增加一个时间戳
jdbc:mysql://localhost:3306/oa_db?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=false

协议 ⼦协议 IP :端⼝号 数据库
mysql: jdbc:mysql://localhost:3306/day14 或者
jdbc:mysql:///day14(默认本机连接)
oracle: jdbc:oracle:thin:@localhost:1521:sid

示例:
Connection con =
DriverManager.getConnection("jdbc:mysql://localhost:3306/day14?user=root&password=root");

java.sql.Connection接⼝

接⼝的实现在数据库驱动中。所有与数据库交互都是基于连接对象的。

Statement createStatement();
作⽤:⽤于获取Statement对象

java.sql.Statement接⼝

作⽤:操作sql语句,并返回相应结果的对象(⼩货⻋)
接⼝的实现在数据库驱动中。⽤于执⾏静态 SQL 语句并返回它所⽣成结果的对象。
ResultSet executeQuery(String sql) 根据查询语句返回结果集。只能执⾏select语句。

int executeUpdate(String sql) 根据执⾏的DML(insert update delete)语句,返回受影响的⾏数。

boolean execute(String sql) 此⽅法可以执⾏任意sql语句。返回boolean值,表示是否返回ResultSet结果集。仅当执⾏select语句,且有返回结果时返回true, 其它语句都返回false;

这个execute⽅法不好,因为执⾏查询时返回true,其他操作返回false,⽆法知道是否删除或插⼊或修改成功.

execute(String sql):通常⽤于DDL
executeUpdate(String sql):通常⽤于DML
executeQuery(String sql):⽤于DQL

java.sql.ResultSet接⼝

表示结果集(客户端存表数据的对象)
a.封装结果集
常规
提供⼀个游标,默认游标指向结果集第⼀⾏之前。
调⽤⼀次next(),游标向下移动⼀⾏。
提供⼀些get⽅法。
封装数据的⽅法
Object getObject(int columnIndex); 根据序号取值,索引从1开始
Object getObject(String ColomnName); 根据列名取值。
将结果集中的数据封装到javaBean中
java的数据类型与数据库中的类型的关系
在这里插入图片描述

常⽤⽅法
boolean next() 将光标从当前位置向下移动⼀⾏
int getInt(int colIndex) 以int形式获取ResultSet结果集当前⾏指定列号值
int getInt(String colLabel) 以int形式获取ResultSet结果集当前⾏指定列名值
float getFloat(int colIndex) 以float形式获取ResultSet结果集当前⾏指定列号值
float getFloat(String colLabel) 以float形式获取ResultSet结果集当前⾏指定列名值
String getString(int colIndex) 以String 形式获取ResultSet结果集当前⾏指定列号值
String getString(String colLabel) 以String形式获取ResultSet结果集当前⾏指定列名值
Date getDate(int columnIndex);
Date getDate(String columnName);
void close() 关闭ResultSet 对象
b.可移动游标的⽅法
boolean next() 将光标从当前位置向前移⼀⾏。 boolean previous()将光标移动到此 ResultSet 对象的上⼀⾏。

boolean absolute(int row) 参数是当前⾏的索引,从1开始
根据⾏的索引定位移动的指定索引⾏。
void afterLast()
将光标移动到末尾,正好位于最后⼀⾏之后。
void beforeFirst()
将光标移动到开头,正好位于第⼀⾏之前。
示例

在这里插入图片描述

JDBC⼊⻔编程

准备⼯作

数据库准备

直接使⽤⽂档(数据库⾼级)中创建的雇员表emp

代码编写步骤

1. 创建项⽬,加载相应的静态资源,如图⽚、第三⽅jar包(.jar⽂件)等
	注意:要对架包进⾏buildPath操作----idea中需要选中jar包所在的⽬录--右键---add as libaray,在出现提示框后,直接点击确定.
	具体实现:将mysql-connector-java-5.0.8-bin.jar jdbc连接包导⼊⼯程
	步骤:
		1.1 在⼯程下新建⼀个⽂件夹(mybin)
		1.2 将mysql-connector-java-5.0.8-bin.jar导⼊mybin或者直接拷⻉粘贴
		1.3 选中mybin,右击选择add as libaray,出现提示框后,点击确定.
2. 注册驱动
3. 建⽴连接
4. 获取执⾏对象
5. 处理结果集
6. 关闭连接

jdbc基本实现

public class Demo1 {
    public static void main(String[] args) throws SQLException {
        //1.注册mysql的驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        //2.创建连接对象--connection对象
        Connection connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2","root","123456");
        //3.建⽴⼩⻋并绑定sql语句
        Statement statement = connection.createStatement();
        //绑定sql语句
        String sql = "select empno,ename,job from emp";
        ResultSet set = statement.executeQuery(sql);
        //4.将数据放⼊箱⼦,拉回客户端,并完成卸货.
        //原理:类似于迭代器,开始指针指向表头,调⽤next⽅法会使指针向下移动⼀,判断当前⾏是否有数据,如果有,返回true,没有返回false
        while (set.next()){
       		 //第⼀种:根据sql语句中字段的下标取值,默认从1开始
       		 //set⾥对应的是虚拟表的数据,所以我们这⾥的顺序跟虚拟表中字段的顺序⼀致
            // Object obj1 = set.getObject(1);
            //第⼆种:通过字段名字(key)取值
            // Object obj2 = set.getObject("empno");
            // System.out.println(obj1+" "+obj2);
            //完全通过字段名字(key)取值
            int empno = set.getInt("empno");
            String name = set.getString("ename");
            String job = set.getString("job");
            System.out.println("empno:"+empno+"
            ename:"+name+" job:"+job);
        }
        //5.关闭资源
        connection.close();
        statement.close();
        set.close();
    }
}

jdbc相关内容

​ 内容提示:
1.不再使⽤new,直接使⽤反射
new的缺点:导致驱动被注册2次;强烈依赖数据库的驱动jar
替代⽅案:使⽤反射实现
Class.forName(“com.mysql.jdbc.Driver”);
2.创建连接对象的⽅式有三种
3.4.前⾯实现的是查找(⽤executeQuery())
ResultSet set = statement.executeQuery(sql);
现在实现的是增删改(统⼀⽤executeUpdate()
int num = statement.executeUpdate(sql);
​ 代码实现

public class Demo2 {
    public static void main(String[] args) throws SQLException,ClassNotFoundException {
        //1.注册mysql的驱动
        //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        //注册使⽤反射--节省空间,开发⽅便
        Class.forName("com.mysql.jdbc.Driver");
        //2.创建连接对象--connection对象
        //第⼀种:三个参数
        //Connection connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2","root","123456");
        //第⼆种:两个参数
        // Properties properties = new Properties();
        // properties.setProperty("user","root");
        // properties.setProperty("password","123456");
        // Connection connection =
       DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2",properties);
        //第三种:⼀个参数
        Connection connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb2?
        user=root&password=123456");
        //3.建⽴⼩⻋并绑定sql语句
        Statement statement = connection.createStatement();
        //增删改---executeUpdate()
        //增加
        String sql = "insert into emp(empno,ename,job)
        values(100,'bing','演员')";
        int num = statement.executeUpdate(sql);
        if (num != 0){
        	System.out.println("插⼊成功");
        }
        //5.关闭资源--可选
        connection.close();
        statement.close();
        //set.close();
    }
}

jdbc的模型封装

内容提示
1.对于从数据库接收到数据,我们⼀般是需要保存到模型中,⼀个模型对应数据库中的
⼀张表.下⾯的代码实现了这个功能.
2.在编写项⽬时,我们需要创建很多特定功能的包,让⼯程的结构清晰,增加代码可读性,
易于编程实现.
在这里插入图片描述

注意:这⾥的servlet层,service层,dao层分别对应的是MVC开发模式中的三层,jdbc⾼级中会讲

DBUtil⼯具类的封装

说明:
1.编写代码时使⽤⾯向对象的思想,尽量将代码进⾏封装,这⾥将数据库的链接和关闭等共同的操作放⼊了DBUtils⼯具类中
2.对于共享的DBUtils⼯具类,不能每次发⽣⼀些变动(⽐如:更换数据库或者修改密码等操作),都去更改代码.所以我们⼜将变化的部分封装了配置⽂件DBConfig.properties.

配置⽂件DBConfig.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mydb2
user=root
pwd=123456

DBUtils代码

package com.qf.util;

import java.sql.*;
import java.util.ResourceBundle;


public class DBUtils {
    static String mydriver;
    static String myurl;
    static String myuser;
    static String mypwd;

    static {
        ResourceBundle bundle = ResourceBundle.getBundle("DBConfig");
        mydriver = bundle.getString("driver");
        myurl = bundle.getString("url");
        myuser = bundle.getString("user");
        mypwd = bundle.getString("pwd");

        try {
            Class.forName(mydriver);
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
    }
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(myurl,myuser,mypwd);
    }
    public static void closeAll(Connection connection, Statement statement, ResultSet set){
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (set != null){
            try {
                set.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

jdbc的批处理

概念

每⼀次的sql操作都会占⽤数据库的资源。如果将N条操作先存储到缓存区中,然后再⼀次性刷到数据库中,这就减少了与数据库的交互次数。因此可以提⾼效率。

Statement

addBatch(String sql):将sql语句添加到缓存中
executeBatch():将缓存中的sql⼀次性刷到数据库中

代码

@Test
public void testBatch(){
    Connection conn = null;
    Statement stat = null;
    try{
        conn = DBUtils.getConnection();
        stat = conn.createStatement();
        int num = 0;
        while(num<1003){
            String sql = "insert into testbatch values(null,'zs"+num+"','f')";
            stat.addBatch(sql);//将sql语句添加到缓存中,
            if(num%50==0){
            stat.executeBatch();//缓存中每有50条都刷新⼀次。
        }
     num++;
     }
     stat.executeBatch();//循环结束后,将缓存中剩余的不⾜50条的全都刷新出去
    }catch (Exception e){
    	e.printStackTrace();
    }finally {
   		DBUtils.closeAll(conn,stat,null);
    }
}

SQL注⼊问题

登陆案例演示

登陆案例需求分析

1.需求:输⼊⽤户名和密码后,实现跳转到主⻚⾯的功能
2.逻辑分析:
- 客户端: 接收⽤户名和密码,并将这些信息发送到服务端
- 服务端:接收到客户端传过来的⽤户名和密码后,进⾏数据库校验是否存在这样的数据,如果存在,就将⽤户名对应的这⼀条记录返回,并封装成⼀个User对象。返回给客户端。
- 客户端收到返回信息后,判断User对象是否存在,如果存在,就实现跳转.....
3.注意:因为没有学习真正的服务器知识,所以这⾥是通过⽅法调⽤模拟客户端与服务器端的通信

在这里插入图片描述

测试

1.先运⾏服务器端
2.运⾏客户端,输⼊测试数据
姓名:bingbing
密码:123456
结果:登录成功

SQL注⼊问题(安全隐患)

注意:
当输⼊
⽤户名:chen
密码:’ or 1='1时,报错.
原因

Statament对象发送的语句可以被改变结构,即如果之前在where中设置的是两个条件,那么可以通过⼀些参数 ⽐如 添加or 后⾯再跟其他条件。此时,where⼦句中是三个条件。这种情况就叫做SQL注⼊。有安全隐患问题。

PreparedStatement类

预编译类的简介

- PreparedStatementStatement的⼦类型
- 此类型可以确定SQL语句的结构,⽆法通过其它⽅式来增减条件。
- 此类型还通过占位符 "?"来提前占位,并确定语句的结构。
- 提供了相应的赋值⽅式:
    ps.setInt(int index,int value)
    ps.setString(int index,String value)
    ps.setDouble(int index,double value)
    ps.setDate(int index,Date value)
    index:表示sql语句中占位符?的索引。从1开始
    value:占位符所对应的要赋予的值
- 执⾏⽅法:
        ps.execute() ;------⽤于DDL和DML
        ps.executeUpdate();-----⽤于DML
        ps.executeQuery();-----⽤于DQL

编译类的简介

- PreparedStatementStatement的⼦类型
- 此类型可以确定SQL语句的结构,⽆法通过其它⽅式来增减条件。
- 此类型还通过占位符 "?"来提前占位,并确定语句的结构。
- 提供了相应的赋值⽅式:
    ps.setInt(int index,int value)
    ps.setString(int index,String value)
    ps.setDouble(int index,double value)
    ps.setDate(int index,Date value)
    index:表示sql语句中占位符?的索引。从1开始
    value:占位符所对应的要赋予的值
- 执⾏⽅法:
        ps.execute() ;------⽤于DDL和DML
        ps.executeUpdate();-----⽤于DML
        ps.executeQuery();-----⽤于DQL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值