zlprime zlprime
  • 首页
  • 朝花夕拾
    • 摄影
    • 生活
    • 随笔
  • 编程学习
    • Java
    • Vue
    • WordPress
  • 其它
    • 游记地图
    • 闲言碎语
    • 友情链接
    • 留言板
首页 › 编程学习 › JDBC的使用总结

JDBC的使用总结

Stone
6月前编程学习
651 0 0

JDBC是用Java语言操作关系型数据库的一套API,全称(Java DataBase Connectivity)Java数据库连。JDBC本质:

  • Java官方定义的一套操作所有关系型数据库的接口
  • 各个数据库厂商根据接口去做各自的实现,提供数据库驱动的jar包
  • 开发者使用接口(JDBC)提供的方法编程,真正执行的代码是驱动jar包中提供的实现类。
  • 这样虽然数据库不同,但由于接口相同,实现的方法相同。就能使用同一套代码操作不同的数据库。只要替换厂商提供的jar包即可,业务代码不用变化

JDBC的基础操作步骤:

 public void testJdbc() throws Exception {
        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        String driverUrl = "jdbc:mysql://localhost:3306/test";
        String userName = "root";
        String passWord = "zl.950922";

        //2.获取连接
        Connection conn = DriverManager.getConnection(driverUrl, userName, passWord);

        //3.定义SQL语句
        String sql = "select * from bs_user";

        //4.获取执行SQL的对象,statement
        Statement statement = conn.createStatement();

        //5.执行SQL
        boolean execute = statement.execute(sql);
        System.out.println(execute);

        //6.释放资源
        statement.close();
        conn.close();
    }

DriverManager(驱动管理类)

它是一个数据库的驱动管理类,定义了一些静态方法。主要用于注册数据库驱动和获取数据库连接:

  • 注册驱动 (DriverManager.registerDriver)
Class.forName("com.mysql.cj.jdbc.Driver");

在之前的示例代码中,我们使用Class.forName将指定名称的jar包加载入内存。好像并没有使用到DriverManager的registerDriver方法。但是,我们查看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!");
        }
    }
}

MySQL官方在Driver类中写了一个静态代码块。静态代码块中使用registerDriver进行了数据库驱动的注册。而静态代码块是随着类的加载自动执行的。所以,我们在使用Class.forName将类加载进内存的时候,已经自动使用DriverManager对驱动进行了注册

  • 获取数据库连接(DriverManager.getConnection)
Connection conn = DriverManager.getConnection(driverUrl, userName, passWord);

userName和passWord是连接数据库的用户名和密码,driverUrl是连接数据库的地址,主要用来定义数据库的链接路径、名称、参数等。

//jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2&参数键值对3 。。。。
String driverUrl = "jdbc:mysql://localhost:3306/test";  //表示连接本机3306端口的名为test的数据库
//如果是在本机的3306端口,可以简写为 String driverUrl = "jdbc:mysql:///test"

Connection(数据库连接对象)

这个类主要用于获取获取执行SQL语句的对象和管理事务

获取执行SQL语句的对象

1.普通执行SQL语句的对象 :Statement Connection.createStatement()

2.预编译SQL的执行SQL语句的对象:PrepareStatement Connection.prepareStatement(sql)

JDBC事务管理:Connection接口中定义了3个对应的方法用于管理事务

1.开启事务:setAutoCommit(boolean autoCommit) :true为自动提交事务,false为手动提交事务,即开启事务

2.提交事务:commit()

3.回滚事务:rollback()

    @Test
    public void testAutoCommit() throws Exception {
        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        String driverUrl = "jdbc:mysql://localhost:3306/test";
        String userName = "root";
        String passWord = "zl.950922";

        //2.获取连接
        Connection conn = DriverManager.getConnection(driverUrl, userName, passWord);

        //3.定义SQL语句
        String sql1 = "update account set money = 6000 where id =1";
        String sql2 = "update account set money = 6000 where id =2";

        //4.获取执行SQL的对象,statement
        Statement statement = conn.createStatement();
        //开启事务,不自动提交就是手动提交,即开启事务
        conn.setAutoCommit(false);

        try {
            //5.1执行SQL1
            int count1 = statement.executeUpdate(sql1);
            System.out.println(count1);
            int i = 1/0;
            //5.2 执行SQL2
            int count2 = statement.executeUpdate(sql2);
            System.out.println(count2);
        } catch (SQLException e) {
            //回滚事务,出现异常将刚才执行的sql语句进行回滚
            conn.rollback();
        }
        //提交事务
        conn.commit();

        //6.释放资源
        statement.close();
        conn.close();
    }

Statement

此类的作用是用来执行SQL语句,根据不同的SQL类型提供了多个执行SQL语句的方法

1.int executeUpdate(sql):执行DDL和DML语句,DML返回执行收影响的行数,DDL即使执行成功返回值也可能为0

//DML语句(数据表中数据的增删改)
String sql = "update account set money = 10000 where id = 1";

//获取执行SQL的对象,statement
Statement statement = conn.createStatement();

//执行SQL
int i = statement.executeUpdate(sql);
System.out.println(i);  //数据库中有一行数据被影响,则返回的结果为1

2.ResultSet executeQuery(sql):执行DQL语句,返回的是ResultSet结果集对象

  //执行SQL,获取Result结果集
  ResultSet resultSet = statement.executeQuery(sql);
  /**
  	* boolean next():将游标从当前位置向前移动一行,并判断当前行是否为有效行
  */
  while (resultSet.next()){
  	/**
  		* xxx  getXxx(参数):获取数据
    	* 参数:
    	*    1.int 列的编号,从1开始
    	*    2.String 列的名称
    */
    	//参数为字符串,即列的名称
    	System.out.println(resultSet.getInt("id"));
    	//参数为整型,即数据表中列的编号,从1开始
    	System.out.println(resultSet.getString(2));
    }

PreparedStatement

预编译SQL语句并执行,可以起到预防SQL注入的问题。

在之前使用Statement执行SQL语句时,如果SQL语句中有参数,我们是通过直接字符串的拼接来设置参数的:

String name ="zlprime";
String pwd = "zlprime";
String sql = "select * from account where name ='"+name +"'and pwd='"+pwd+"'";
//拼接出来的结果就是 select * from account where name ='zlprime' and pwd ='zlprime'
//这时是正常的,如果 恶意用户输入的是 pwd = "' or '1' = '1'"
//那么拼出来的结果就是 select * from account where name ='zlprime' and pwd ='' or '1' = '1'
//这样无论name和pwd是否正确,后面的1 = 1都是恒等式。那么这条sql语句被执行后,肯定能获取到数据。即使name和pwd不正确
//这就是SQL注入

而PreparedStatement就解决了这个问题,在它的底层对敏感字符进行了转义。如果用户输入的是 ‘1’ 经过PreparedStatement转义变为了 \’1\’ ,敏感字符被转译成了SQL中的字符,而不是再作为SQL语句的关键字被对待。这就解决了SQL注入的问题。

PreparedStatement基本使用

  • 获取PreparedStatement对象
 //SQL语句中的参数值使用 ? 占位符代替
 String sql = "select * from account where id = ? and money = ?";
 //通过Connection获取PreparedStatement对象,此时将SQL语句作为参数进行传入
 PreparedStatement preparedStatement = conn.prepareStatement(sql);
  • 设置参数值
 //设置参数值
 /**
 * setXxx(参数1,参数2):用于给 ? 占位符复制
 * 参数1:占位符的位置,即 ? 的位置
 * 参数2:占位符的值
 */
 preparedStatement.setInt(1,1);
 preparedStatement.setString(2,"3000");

整体下来的流程就是,先获取PreparedStatement对象,在获取该对象时,传入用 ? 占位符进行占位的SQL语句。然后再调用PreparedStatement对象的setXxx方法,为占位符进行赋值。接着再跟之前一样,执行它的executeXxx方法即可。

 //SQL语句中的参数值使用 ? 占位符代替
 String sql = "select * from account where id = ? and money = ?";
 //通过Connection获取PreparedStatement对象,此时将SQL语句作为参数进行传入
 PreparedStatement preparedStatement = conn.prepareStatement(sql);
 //设置参数值
 /**
 * setXxx(参数1,参数2):用于给 ? 占位符复制
 * 参数1:占位符的位置,即 ? 的位置
 * 参数2:占位符的值
 */
 preparedStatement.setInt(1,1);
 preparedStatement.setString(2,"3000");     
 //6.执行SQL语句
 ResultSet resultSet = preparedStatement.executeQuery();

PreparedStatement还有一个好处是预编译SQL,使得SQL语句的执行效率更高。通常情况下,一条SQL语句可能会重复执行多次。在这多次的执行过程中,SQL语句的结构是相同的,只是里面的参数值不同。如果没有预编译,每次执行这条SQL语句都要进行校验、解析等操作,比较耗时。因此MySQL提供了预编译功能,即,将需要替换的参数值使用?占位符进行站位,参数提取出来,把SQL语句进行模板化。这样再执行相同的SQL语句时,就不需要再重复解析校验了,只需要把参数带入再执行即可。

PreparedStatement的执行过程:

  1. 在mysql的driverUrl中加入参数 useServerPrepStmts=true,开启预编译功能
  2. 设置cachePrepStmts=true开启编译预缓存功能,即使是不同的PreparedStatement对象,如果执行相同的SQL语句,也不会编译两次。只要是同一个Connection,就能实现一次编译随处运行。
  3. 在获取PreparedStatement对象时,将SQL语句传给mysql服务器进行检查、校验
  4. 通过PreparedStatement的setXXX方法为占位符赋值,mysql服务器接收到语句时,直接执行不再检查校验。
java
0
本文系作者 @Stone 原创发布在 zlprime。未经许可,禁止转载。
Centos8中安装RabbitMQ
上一篇
摘草莓2
下一篇
评论 (0)
再想想
聚合文章
03Java中的变量
2周前
01从BeanFactory入门Spring框架
2周前
Jenkins修改插件的下载源
3周前
02Java中的数据类型
3周前
相关文章
03Java中的变量
01从BeanFactory入门Spring框架
Jenkins修改插件的下载源
02Java中的数据类型
简介

海边微风起,等风也等你

留言板
留言板
小伙伴们
2Broear Libra の 向往 云帆沧海 若志随笔 豆豆 Chuanbo 诗意笔记
Copyright © 2017-2023 zlprime. 皖ICP备17019582号
  • 首页
  • 朝花夕拾
    • 摄影
    • 生活
    • 随笔
  • 编程学习
    • Java
    • Vue
    • WordPress
  • 其它
    • 游记地图
    • 闲言碎语
    • 友情链接
    • 留言板
热门搜索
  • java
  • spring
Stone
75 文章
145 评论
84 喜欢
  • 0
  • 0
  • Top