JDBC

JDBC

**JDBC规范定义接口,具体的实现由各大数据库厂商来实现。**JDBC 是 Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。数据库驱动由数据库厂商提供。

使用 JDBC 的好处:

  1. 程序员如果要开发访问数据库的程序,只需要会调用 JDBC 接口中的方法即可,不用关注类是如何实现的。

  2. 使用同一套 Java 代码,进行少量的修改就可以访问其他 JDBC 支持的数据库

使用 JDBC 开发使用到的包:

会使用到的包说明
java.sql所有与 JDBC 访问数据库相关的接口和类
javax.sql数据库扩展包,提供数据库额外的功能。如:连接池
数据库的驱动由各大数据库厂商提供,需要额外去下载,是对 JDBC 接口实现的类

JDBC 的核心 API

接口或类作用
DriverManager 1) 管理和注册数据库驱动
2) 得到数据库连接对象
Connection 接口一个连接对象,可用于创建 Statement 和 PreparedStatement 对象
Statement 接口一个 SQL 语句对象,用于将 SQL 语句发送给数据库服务器。
PreparedStatemen 接口一个 SQL 语句对象,是 Statement 的子接口
ResultSet 接口用于封装数据库查询的结果集,返回给客户端 Java 程序

加载和注册驱动

加载和注册驱动的方法描述
Class.forName(数据库驱动实现类)加载和注册数据库驱动,数据库驱动由 mysql 厂商"com.mysql.jdbc.Driver"

com.mysql.jdbc.Driver 源代码:

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!");
        }
    }
}

从 JDBC3 开始,目前已经普遍使用的版本。可以不用注册驱动而直接使用。Class.forName这句话可以省略。

DriverManager 类

DriverManager 作用:

  1. 管理和注册驱动

  2. 创建数据库的连接

DriverManager类中的静态方法:

  • **Connection getConnection (String url, String user, String password):**通过连接字符串,用户名,密码来得到数据库的连接对象
  • **Connection getConnection (String url, Properties info):**通过连接字符串,属性对象来得到连接对象
JDBC 连接数据库的四个参数说明
用户名登录的用户名
密码登录的密码
连接字符串 URL不同的数据库 URL 是不同的,mysql 的写法jdbc:mysql://localhost:3306/数据库[?参数名=参数值]
驱动类的字符串名com.mysql.jdbc.Driver

连接数据库的 URL 地址格式:协议名:子协议://服务器名或IP地址:端口号/数据库名?参数=参数值

前提:必须是本地服务器,端口号是 3306

jdbc:mysql:///数据库名

乱码的处理

jdbc:mysql://localhost:3306/数据库?characterEncoding=utf8

Connection 接口

Connection 作用:

Connection 接口,具体的实现类由数据库的厂商实现,代表一个连接对象。

Connection 接口中的方法:

Statement createStatement(): 创建一条 SQL 语句对象

Statement 接口

Statement 作用:

代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。

Statement 接口中的方法:

int executeUpdate(String sql): 用于发送 DML 语句,增删改的操作,insert、update、delete

参数:SQL 语句

返回值:返回对数据库影响的行数

ResultSet executeQuery(String sql): 用于发送 DQL 语句,执行查询的操作。select

参数:SQL 语句

返回值:查询的结果集

JDBC 访问数据库的步骤

  1. 注册和加载驱动(可以省略)

  2. 获取连接

  3. Connection 获取 Statement 对象

  4. 使用 Statement 对象执行 SQL 语句

  5. 返回结果集

  6. 释放资源

释放资源

  1. 需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接

  2. 释放原则:先开的后关,后开的先关。ResultSet  Statement  Connection

  3. 放在哪个代码块中:finally 块

ResultSet 接口:

作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。

ResultSet 接口中的方法:

boolean next()

  1. 游标向下移动 1 行

  2. 返回 boolean 类型,如果还有下一条记录,返回 true,否则返回 false

数据类型 getXxx()

  1. 通过字段名,参数是 String 类型。返回不同的类型

  2. 通过列号,参数是整数,从 1 开始。返回不同的类型

java.sql.Date、Time、Timestamp(时间戳),三个共同父类是:java.util.Date

数据库工具类 JdbcUtils

public class JdbcUtil {
    private static final String USER = "root";
    private static final String PWD = "root";
    private static final String URL = "jdbc:mysql://localhost:3306/db3";
    private static final String DRIVER= "com.mysql.jdbc.Driver";
    static {
        try {
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static Connection getConn() throws SQLException {
        return DriverManager.getConnection(URL,USER,PWD);
    }

    public static void closeAll(ResultSet resultSet, Statement statement, Connection connection){
        if (resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement!=null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection!=null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}
public class Demo {
    public static void main(String[] args) throws SQLException {
        Connection conn = JdbcUtil.getConn();
        Statement statement = conn.createStatement();
        ResultSet resultSet = statement.executeQuery("select * from student2");
        while(resultSet.next()){
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            int anInt = resultSet.getInt(3);
            String string = resultSet.getString(4);

            Student student = new Student();
            student.setId(id);
            student.setName(name);
            student.setAge(anInt);
            student.setSex(string);

            System.out.println(student);
        }
        JdbcUtil.closeAll(resultSet,statement,conn);

    }
}

案例:用户登陆

public class LoginDemo {
    public static void main(String[] args) throws SQLException {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String name = sc.nextLine();
        System.out.println("请输入密码:");
        String password = sc.nextLine();
        login(name, password);
    }

    public static void login(String name, String password) throws SQLException {
        Connection conn = JdbcUtil.getConn();
        Statement statement = conn.createStatement();
        String s = "select * from user where name='" + name + "' and password='" + password + "'";
        System.out.println(s);
        ResultSet resultSet = statement.executeQuery(s);
        if(resultSet.next()){
            System.out.println("登录成功");
        }else {
            System.out.println("登录失败");
        }
        JdbcUtil.closeAll(resultSet,statement,conn);
    }
}

SQL 注入问题

当select * from user where name=‘newboy’ and password=‘a’ or ‘1’='1’时,

‘1’=‘1’ 真

相当于

select * from user where true; 查询了所有记录

我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了原有 SQL 真正的意义,以上问题称为 SQL 注入。要解决 SQL 注入就不能让用户输入的密码和我们的 SQL 语句进行简单的字符串拼接。

PreparedStatement 接口

PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句

  1. 因为有预先编译的功能,提高 SQL 的执行效率。

  2. 可以有效的防止 SQL 注入的问题,安全性更高。

Connection 创建 PreparedStatement 对象:

Connection 接口中的方法描述
PreparedStatement prepareStatement(String sql)指定预编译的 SQL 语句,SQL 语句中使用占位符?创建一个语句对象

PreparedStatement 接口中的方法:

PreparedStatement 接口中的方法描述
int executeUpdate()执行 DML,增删改的操作,返回影响的行数。
ResultSet executeQuery()执行 DQL,查询的操作,返回结果集

PreparedSatement 的好处

  1. prepareStatement()会先将 SQL 语句发送给数据库预编译。PreparedStatement 会引用着预编译后的结果。可以多次传入不同的参数给 PreparedStatement 对象并执行。减少 SQL 编译次数,提高效率。

  2. 安全性更高,没有 SQL 注入的隐患。

  3. 提高了程序的可读性

使用 PreparedStatement 的步骤:

  1. 编写 SQL 语句,未知内容使用?占位:“SELECT * FROM user WHERE name=? AND password=?”;

  2. 获得 PreparedStatement 对象

  3. 设置实际参数:setXxx(占位符的位置, 真实的值)

  4. 执行参数化 SQL 语句

  5. 关闭资源

PreparedStatement 中设置参数的方法描述
void setDouble(int parameterIndex, double x)将指定参数设置为给定 Java double 值。
void setFloat(int parameterIndex, float x)将指定参数设置为给定 Java REAL 值。
void setInt(int parameterIndex, int x)将指定参数设置为给定 Java int 值。
void setLong(int parameterIndex, long x)将指定参数设置为给定 Java long 值。
void setObject(int parameterIndex, Object x)使用给定对象设置指定参数的值。
void setString(int parameterIndex, String x)将指定参数设置为给定 Java String 值。
public class TestJdbc1 {
    @Test
    public void testJdbc() throws ClassNotFoundException, SQLException {
        //1.注册驱动
//        DriverManager.registerDriver(new Driver());
        Class.forName("com.mysql.jdbc.Driver" );

        //2.获取连接对象
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root");
        System.out.println(connection);//com.mysql.jdbc.JDBC4Connection@1f89ab83

        //3.获取语句执行者
        PreparedStatement preparedStatement = connection.prepareStatement("insert into student2(name,age,sex) values(?,?,?)");
        preparedStatement.setString(1,"王五");
        preparedStatement.setInt(2,20);
        preparedStatement.setString(3,"女");
        int b= preparedStatement.executeUpdate();

        System.out.println(b);
    }
}

JDBC 事务的处理

Connection 接口中与事务有关的方法说明
void setAutoCommit(boolean autoCommit)参数是 true 或 false
如果设置为 false,表示关闭自动提交,相当于开启事务
void commit()提交事务
void rollback()回滚事务
public class Transaction {
    public static void main(String[] args) throws SQLException {
        Connection conn = JdbcUtil.getConn();
        PreparedStatement preparedStatement1 = null;
        PreparedStatement preparedStatement = null;
        try{
            conn.setAutoCommit(false);
            preparedStatement = conn.prepareStatement("update student2 set age = age - ? where id=?");
            preparedStatement.setInt(1,10);
            preparedStatement.setInt(2,2);
            preparedStatement.executeUpdate();

            System.out.println(100/0);

            preparedStatement1 = conn.prepareStatement("update student2 set age = age + ? where id=?");
            preparedStatement1.setInt(1,10);
            preparedStatement1.setInt(2,3);
            preparedStatement1.executeUpdate();
            conn.commit();
            System.out.println("成功");
        }catch (Exception e){
            e.printStackTrace();
            try {
                //事务的回滚
                conn.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            System.out.println("转账失败");
        }finally {
            JdbcUtil.closeAll(null,preparedStatement,conn);
            JdbcUtil.closeAll(null,preparedStatement1,null);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值