JDBC技术文章

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: JDBC技术文章

JDBC


数据库的访问过程

1.建立连接

协议、ip、端口号、用户名、密码

2.客户端向MySQL服务器发送请求

即SQL语句

3.服务器接收到请求,执行语句,得到一个结果

4.服务器将结果返回给客户端

5.客户端接收到结果后将结果展示出来

6.执行完毕后断开连接

JDBC的定义

JDBC:Java Database Connection

Java数据库连接。Java语言需要访问多个数据库,但流程是一样的,于是就制定了一套统一的接口方便开发者使用,具体的驱动程序由各个数据库的厂商来提供

JDBC所有的接口都在 java.sql 以及 javax.sql 这两个包下面。

JDBC程序的创建

1.新建项目

2.导入驱动程序包

  • 把驱动程序包下载下来https://mvnrepository.com/
    jar包是java虚拟机可以识别的压缩格式,里面放的class文件
  • 把文件放到项目的根目录下
  • 右键添加为library
  • 编写程序
public static void main(String[] args) throws SQLException{
    //1.注册驱动
    DriverManager.registerDriver(new Driver());
    
    //2.获取连接 返回的是Connection接口的实现类
    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/36th_rev?useSSL=false","root","123456");
    //3.获取statement对象 这个对象是用来包装SQL语句为网络请求
    Statement statement = connection.createStatement();
    //4.通过statement对象发送SQL语句
    int affectedRows = statement.executeUpdate("");
    //5.解析结果集
    //6.关闭资源
    statement.close();
    connection.close();
}
public static void main(String[] args) throw SQLException{
    //1.注册驱动
    DriverManager.registerDriver(new Driver());
    //2.获取连接 返回的是Connection接口的实现类
    Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/36th_rev>useSSL=false","root","123456");
    //3.获取statement对象
    Statement statement = connection.createStatement();
    //4.通过statement对象发送语句
    ResultSet rs = statement.executeQuery("select * from student");
    //5.解析结果集
    while(resultSet.next()){
        int id = rs.getInt("id");
        String name = rs.getString("name");
        String aClass = rs.getString("class");
        int score = rs.getInt("score");
    }
    //6.关闭资源
    rs.close();
    statement.close();
    connection.close();
    
}

API

DriverManager

用于注册驱动和获取连接

注册驱动:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());

获取连接:

Connection connection = DriverManager.getConnection(String url,String username,String password)

这里获取到的连接对象是

com.mysql.jdbc.JDBC4Connection这个类的对象,对象是根据我们上面注册的驱动来变化的,所以在设计工具类的时候就可以使用配置文件

Connection

这个是JDBC中提供的一个接口,这个接口的实现类代表一个数据库连接。在MySQL的操作中,实现类是com.mysql.jdbc.JDBC4Connection,通常我们使用连接来获取statement对象,用于控制事务

获取statement对象,返回的是StatementImpl,是Statement接口的实现类

Statement statement = connection.createStatement();

Statement

这个是一个JDBC中提供的一个接口,这个接口的实现类的具体作用是帮助我们把SQL语句包装成网络请求,发送给MySQL服务器

执行SQL语句

// 执行增删改的API,返回的是影响的行数
int affectedRows  = statement.executeUpdate(String sql);
    
// 执行查询的API,返回的是查询语句执行完之后的结果集
ResultSet rs = statement.executeQuery(String sql);

ResultSet

表示结果集,使用API来解析结果集

有一个类似于迭代器的游标,初始的时候指向第一个数的前一个位置,然后向下迭代,返回值是boolean类型,与迭代器不同,无法使用for each

// 向后移动游标,如果ret是true,说明移动了,如果ret是false,表示这个游标已经移到了结果集的尾部,这个游标默认指向第一行之前
Boolean ret  = resultSet.next();

// 移动到末尾
resultSet.afterLast();

// 往前移动
Boolean ret = resultSet.previous();

// 移动到第一行之前
resultSet.beforeFirst();

// 获取值 传入结果集的列名,根据字段的类型来选择对应的API,如果有别名,要使用别名
resultSet.getInt(String columnName);
resultSet.getString(String columnName);
resultSet.getDate(String columnName);
//循环调用
while(resultSet.next){
    resultSet.getInt(String columnName);
  resultSet.getString(String columnName);
  resultSet.getDate(String columnName);
}

释放资源

finally{
 //注意先后顺序,应该是resultSet、statement、connection
    try{
        resultSet.close();
    }finally{
        try{
            statement.close();
        }finally{
            connection.close();
        }
    }
}

好处:

  • 确保connection.close()能够被执行
  • 严格保证关闭的执行顺序

指令重排:volatile

java在执行程序的时候如果代码的顺序并不影响执行的结果的话,那么有可能导致执行的顺序错乱

int i = 0;
int b = 1;
i++;
b++;

JDBC的优化

使用工具类来简化JDBC的使用

package day4.utils;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils { //JDBC工具类,用于封装方法
    static Connection connection;
    static String url;
    static String username;
    static String password;
    static String driverClassName;

    static {
        //静态代码块加载配置文件
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("jdbc.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        url = properties.getProperty("url");
        username = properties.getProperty("username");
        password = properties.getProperty("password");
        driverClassName = properties.getProperty("driverClassName");
        try {
            Class.forName(driverClassName); //注册驱动
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            connection = DriverManager.getConnection(url, username, password); //获取连接
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() { //外部调用的获取连接的方法
        return connection;
    }

    //关闭资源
    public static void closeResource(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

        } finally {
            try {
                if (statement != null) {
                    try {
                        statement.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            } finally {
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
package day4.utils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class MyUtils { //用于增删改查的类
    static Statement statement = null;
    static Connection connection = JDBCUtils.getConnection();
    public static void createData(String createSql){ //创建数据的方法
        try {
            statement = connection.createStatement();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            statement.executeUpdate(createSql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    public static ResultSet selectData(String sql){ //用于查找数据,返回一个结果集
        ResultSet rs = null;
        try {
            statement = connection.createStatement();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            rs = statement.executeQuery(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return rs;
    }
    public static void closeResource(){ //用于关闭资源
        JDBCUtils.closeResource(null,statement,connection);
    }

    public static void closeResource(ResultSet resultSet){ //用于关闭资源的方法重载,提供给带有resultSet的使用
        JDBCUtils.closeResource(resultSet,statement,connection);
    }

}

数据库的注入问题

在用户登录的过程中,如果输入的SQL语句带有关键字的话,那么就有可能造成安全问题

login("","xxx' or '1=1");

如上,sql会判定or为关键字,那么1=1永远返回的是true,这样就会造成安全问题

解决办法:

  • 不让用户自己输入(登录的案例不太适用)
  • 审查用户的登录的时候传递过来的用户名和密码中是否有关键字
  • 适用SQL语句预编译的方式来做,可以解决数据库的注入问题,PrepareStatement就可以解决数据库的注入问题

PrepareStatement

statement的一个子接口,可以帮助我们防止注入的问题

//获取prepareStatement对象,需要传入一个SQL语句的模板,使用?来占位
//执行这一步的时候会把SQL语句发送到服务器,然后服务器进行预编译,并返回一个对象
PreparedStatement preparedStatement = connection.prepareStatement("select * from user where name = ? and password = ?")
//设置参数,下标对应的是?,从1开始
preparedStatement.setString(1,username);    
preparedStatement.setString(2,password);
//执行SQL语句,到这一步时需要再次与服务器进行通信,客户端将参数传给服务器后,服务器执行指令,返回一个结果集
ResultSet resultSet = preparedStatement.executeQuery();

批处理

批量执行SQL语句

循环

//循环来处理
public static void batchForeach() throws SQLException{
    //获取statement对象
    Statement statement = connection.createStatement;
    for(int i = 0;i<1000;i++){
        statement.executeUpdate("insert into user values(null,'带土','神威','莫毅几多')")
    }
    //关闭资源
    JDBCUtils.closeResource(null,statement,null)//正常来说连接都要关闭,但这里的代码是因为要使用3个不同的批处理对比,但共用同一个连接,如果断开的话会报错,因此等待执行完毕一起关闭
}

statement

public static void batchByStatement() throws SQLException{
    //获取连接
    Connection connection = JDBCUtils.getConnection();
    //获取Statement对象
    Statement statement = connection.createStatement();
    //添加到批处理
    for(int i = 0;i<100;i++){
        statement.addBatch("insert into user values(null,'naruto','螺旋丸','哒嘚吧哟')")
    }
    //执行批处理
    statement.executeBatch();
    //关闭资源
    JDBCUtils.closeResource(null,statement,null);
}

PrepareStatement

需要在url后面添加参数rewriteBatchedStatements=true才能使其生效

public static void batchBypreparedStatement() throws SQLException{
    //获取连接
    Connection connection = JDBCUtils.getConnection();
    //获取对象
    PreparedStatement preparedStatement = connection.prepareStatement("insert into user values(null,?,?,?)");
    for(int i = 0;i<100;i++){
        preparedStatement.setString(1,'sasigi');
        preparedStatement.setString(2,'千鸟');
        preparedStatement.setString(3,'naruto');
        //添加到批处理
        preparedStatement.addBatch();
    }
    //执行批处理
    preparedStatement.executeBatch();
    //关闭资源
    JDBCUtils.closeResource(null,preparedStatement,null);
       
}

服务器只需要预编译一次,然后每次我们输入不同的参数,服务器执行,这样效率大大的提高了

通信1000次的对比

通信次数 编译次数 执行时间
for循环 1000 1000 1213 ms
statement 1 1000 876 ms
prePrepareStatement 2 1 35 ms

prePrepareStatement的速度显然最快,但statement不限定SQL语句的格式,在使用的时候要根据实际情况来进行考虑

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
8月前
|
SQL 前端开发 Java
大数据平台底层技术-JAVA篇-如何动态加载不同版本的 HIVE JDBC 驱动 - 一文读懂JAVA的类加载机制 1
大数据平台底层技术-JAVA篇-如何动态加载不同版本的 HIVE JDBC 驱动 - 一文读懂JAVA的类加载机制
|
28天前
|
Java 关系型数据库 MySQL
【JDBC编程】基于MySql的Java应用程序中访问数据库与交互数据的技术
【JDBC编程】基于MySql的Java应用程序中访问数据库与交互数据的技术
|
28天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
8月前
|
SQL Java 大数据
大数据平台底层技术-JAVA篇-如何动态加载不同版本的 HIVE JDBC 驱动 - 一文读懂JAVA的类加载机制 2
大数据平台底层技术-JAVA篇-如何动态加载不同版本的 HIVE JDBC 驱动 - 一文读懂JAVA的类加载机制
|
28天前
|
SQL druid Java
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)
36 0
|
28天前
|
SQL Java 关系型数据库
数据库-----JDBC技术
数据库-----JDBC技术
231 0
|
10月前
|
SQL druid Java
JAVA进阶 JDBC技术学习笔记(四)
JAVA进阶 JDBC技术学习笔记(四)
|
28天前
|
SQL Java 数据库连接
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)(下)
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)
466 1
|
28天前
|
SQL Java 数据库连接
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)(中)
JDBC技术【分页查询、数据库连接池、应用程序分层、封装通用的BaseDao】(四)-全面详解(学习总结---从入门到深化)
33 0
|
28天前
|
SQL Java 关系型数据库
JDBC技术【SQL注入、JDBC批量添加数据、JDBC事务处理、其他查询方式】(三)-全面详解(学习总结---从入门到深化)
JDBC技术【SQL注入、JDBC批量添加数据、JDBC事务处理、其他查询方式】(三)-全面详解(学习总结---从入门到深化)
41 0