JDBC


驱动包的注册

Class.forName("com.mysql.jdbc.Driver");

这句可以不写,因为在mysql5之后的驱动jar包可以省略注册驱动。

在驱动包META-INF/servicesjava.sql.Driver/文件里会自动加载驱动

实际注册驱动的是DriverManager,在com.mysql.jdbc.Driver包里可以找到下面的语句:

DriverManager.registerDriver(new Driver());
  • 连接数据库时,如果连接的是本地数据库并且端口为3306,则连接的URL可以简写为:jdbc:mysql:///<数据库名>

连接数据库的对象

  1. DriverManager:驱动管理对象

    • 注册驱动

    • 获取数据库连接DriverManager.getconnection()

  2. Connection:数据库连接对象

    1. 功能:

      • 获取执行sql 的对象
    2. 管理事务:

      • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务

      • 提交事务:commit()

      • 回滚事务:rollback()

  3. Statement:执行sql的对象

    • 执行sql

      1. boolean execute(String sql) :可以执行任意的sql (了解)

      2. int executeUpdate(String sql) :执行DML(增删改)语句、DDL(create,alter、drop)语句(不常用,一般设计数据库用专业软件)

        • 返回值为:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
      3. ResultSet executeQuery(String sql) :执行DQL(select)查询语句

  4. ResultSet:结果集对象,封装查询结果

    • boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是(最后一行没有数据),则返回false,如果不是则返回true

    • getXxx(参数):获取数据

      • Xxx:代表数据类型 如: int getInt() , String getString() //根据字段的类型

      • 参数有两种类型:

        1. int:代表列的编号,从1开始 如: getString(1) //表示获取第几个字段,从1开始,注意不带双引号

        2. String:代表列名称。 如: getDouble(“balance”) //表示获取哪个具体字段

      • 注意:

        • 使用步骤:

          1. 游标向下移动一行

          2. 判断是否有数据(不然会有异常)

          3. 获取数据

  5. PreparedStatement:执行sql的对象

    1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
      • 例子
        1. 输入用户名:随便,输入密码:a’ or ‘a’ = ‘a
        2. 整个SQL语句就变成:select * from user where username = 'fhdsjkf' and password = 'a' or 'a' = 'a'
          • username = 'fhdsjkf'肯定为false,password = 'a'也为false,但是后面有个or 'a' = 'a'
          • 'a' = 'a'是一个恒等式,一定是个true,那么整体就是false or true 结果就是true,然后就可以强行登陆,做一些坏事!
    2. 解决方案:使用PreparedStatement对象来解决
    3. 预编译的SQL:参数使用?作为占位符
    4. 具体使用步骤:
      1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
      2. 注册驱动
      3. 获取数据库连接对象 Connection
      4. 定义sql
        • 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
      5. 获取执行sql语句的对象 PreparedStatement ps=connection.prepareStatement(String sql) //这里要直接传个sql语句做参数,Statement对象没有
      6. 给?赋值:
        • 方法: setXxx(参数1,参数2) //Xxx为数据类型
          • 参数1:?的位置编号 从1开始
          • 参数2:?的值
      7. 执行sql,接受返回结果,不需要传递sql语句
      8. 处理结果
      9. 释放资源
    5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
      1. 可以防止SQL注入
      2. 效率更高

抽取JDBC工具类 : JDBCUtils

  • 注意!注意!注意!:
    jdbc.properties数据库配置文件一定要放在src根目录下,不然会报Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class xyz.sky03.JDBC.util.JDBCUtils这种错误。

具体实现:

package xyz.sky03.JDBC.util;

import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils {

    private static String url;  //只有静态的变量才能被静态代码块读取到,才能被静态方法所访问
    private static String user;
    private static String password;
    private static String driver;
    //文件的读取以及注册驱动,只需要读取一次即可拿到这些值,所以使用静态代码块
    static {
        //读取资源文件,获取值
        try {
            //1. 创建Properties集合类。
            Properties pro =new Properties();
            //获取src路径下的文件的方式--->ClassLoader 类加载器
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            URL res  = classLoader.getResource("jdbc.properties");
            String path = res.getPath();
            //2. 加载文件
            pro.load(new FileReader(path));
            //3. 获取数据,赋值
            url=pro.getProperty("url");
            user=pro.getProperty("user");
            password=pro.getProperty("password");
            driver=pro.getProperty("driver");
            //4. 注册驱动
            Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,user,password);
    }

    //释放资源
    public static void close(Statement stat, Connection conn){
        if(stat!=null){
            try {
                stat.close();
                //conn.close(); 这里不能把下面的conn.close()方法放到一起
                //因为如果stat.close()没有正常关闭,就会直接catch到下面了,conn.close()就会被跳过去,没有执行
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    //重载一个带ResultSet的方法
    public static void close(ResultSet rs,Statement stat, Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stat!=null){
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

JDBC控制事务:

  1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
  2. 操作:
    1. 开启事务
    2. 提交事务
    3. 回滚事务
  3. 使用Connection对象来管理事务的时机
    • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
      • 在执行sql语句之前开启事务
    • 提交事务:commit()
      • 当所有sql都执行完提交事务
    • 回滚事务:rollback()
      • 在catch中回滚事务

文章作者: Sky03
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Sky03 !
评论
 上一篇
JDBC连接池 JDBC连接池
数据库连接池概念: 其实就是一个容器(集合),存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。 好处: 节约资源 用户访问高
2019-03-21
下一篇 
Servlet-上 Servlet-上
Servlet 概念:运行在服务器端的小程序 快速入门: 创建JavaEE项目 定义一个类,实现(implements)Servlet接口 实现接口中的抽象方法(五个) 配置Servlet(web.xml) Servlet的生命周期
2019-03-16
  目录