当前位置 : 主页 > 编程语言 > java >

JDBC基本使用

来源:互联网 收集:自由互联 发布时间:2023-12-28
1. 简介 JDBC(Java Data Base Connectivity) 是 Java 访问数据库的标准规范.,为 多种关系数据库提供统一访问。它由一组用Java语言编写的类和接口组成。 JDBC只是Java提供的一些接口,而这些接口

1. 简介

JDBC(Java Data Base Connectivity) 是 Java 访问数据库的标准规范.,为 多种关系数据库提供统一访问。它由一组用Java语言编写的类和接口组成。

JDBC只是Java提供的一些接口,而这些接口的实现类是由各个数据库厂商提供的,称之为数据库连接驱动。这样一来,我们就可以面向接口编程,以一种统一的方式访问多种数据库。

2. JDBC使用流程

  1. 下载对应版本的数据库连接驱动,并导入项目。
  2. 注册驱动
    通过 Class.froName("Driver实现类路径"); 加载Driver驱动并注册到DriverManager中。
    对于MySQL而言,不同版本的 "Driver实现类路径" 也是不同的:
    5.x版本为:com.mysql.jdbc.Driver
    8.x版本为:com.mysql.cj.jdbc.Driver
    原理为: Driver类在静态代码块中创建Driver对象,并注册到DriverManager中。

**注意:**在JDK1.6中DriverManager明确指出,在JDBC4.0及之后版本中可以不用forName显示加载驱动。这是因为在获取连接时,可以根据url判断并自动加载对应的驱动。但是一般开发中还是 要写forName,因为有些场合并不会自动加载,如Tomcat中,由于类加载器不同,省略forName就会找不到类。

  1. 创建连接
    通过 DriverManager的getConnection方法获取连接
Connection getConnection(url,userName,password);
  • url:jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=UTC
    jdbc:mysql是 协议 名,固定写法
    localhost:3306为服务器地址 及 端口号
    test是要连接的数据库名
    characterEncoding=UTF-8的作用为,告诉mysql,将数据转化为 utf-8 格式之后再传给我的程序。
    serverTimezone=UTC有时候不指定时区会报错。
  • userName 登录MySQL的用户名
  • password 密码
  1. 执行SQL语句
    通过connection对象的createStatement()方法获取Statement对象,然后通过Statement对象的executeUpdate()executeQuery()方法执行SQL语句:
    executeUpdate():方法用于执行insert update delete语句,返回受影响的行数。
    executeQuery():执行select语句, 返回ResultSet结果集对象。
  2. 处理结果集
    ResultSet的作用为 封装查询结果,然后通过其next方法和getXxx方法遍历结果集。

方法

说明

boolean next()

1) 游标向下一行

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

xxx getXxx( String or int)

1) 通过列名,参数是 String 类型。返回不同的类型

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

  1. 释放资源
    释放原则为:先开的后关,一次关闭 ResultSet对象,Statement对象,Connection对象
  2. 示例
@Test
    public void test(){
        String url = "jdbc:mysql://192.168.65.131:3306/test?characterEncoding=UTF-8&serverTimezone=UTC";
        String userName = "mochen";
        String password = "123456";
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;  // 查询数据

        try {
            // 加载Driver类,并注册到DriverManager
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 获取连接
            conn = DriverManager.getConnection(url, userName, password);
            // 获取Statement对象
            stmt = conn.createStatement();
            // 执行SQL语句
            stmt.executeUpdate("insert into jdbc_user values(null,'王蛋','abcd','2014-05-12 13:21:00')");  // 插入数据
            rs = stmt.executeQuery("select * from jdbc_user");
            // 处理结果集
            while(rs.next()){
                System.out.println(rs.getString(1)+"\t\t"+rs.getString(2)
                                   +"\t\t"+rs.getString(3)+"\t\t"
                                   +rs.getString(4));
            }
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        } finally { // 释放资源
            if(null!=rs){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(null!=stmt){
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(null!=conn){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

3. SQL注入 与 PreparedStatement

3.1 SQL注入

什么是SQL注入:

当要执行的SQL语句 是由用户输入的参数 拼接而来时,如果用户可以输入一些有特殊意义的内容,就可以改变原有的SQL的意义,从而进行非法操作。这种情况就称为SQL注入。

举例:

如 验证用户登录的SQL语句:

String sql = "select * from jdbc_user " +
"where username = " + " '" + name +"' " +" and password = " +" '" + pass +"'";

如果用户输入的密码为:' or '1'=1因为1=1肯定是真,or 又是有真即真,所以where条件的结果总为true。这就改变了SQL原有的含义。

真正的SQL注入可能要复杂的多,但原理应该都是

3.2 PreparedStatement

1. 简介

PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语 句对象。预编译:是指SQL 语句被预编译,并存储在 PreparedStatement 对象中。然后可以使用此对象多次高效地执行该语句。

2. 使用

// 获取 PreparedStatement
conn.prepareStatement(String sql);  // Sql中可以使用 ? 作为参数的占位符,然后使用setXxx方法赋值

// 常用方法
int executeUpdate();
ResultSet executeQuery(); // 注意:这里不必填入SQL

JDBC基本使用_bc

3. 示例

PreparedStatement ps = conn.prepareStatement("select * from employee where id=? and name=?");
ps.setInt(1,1);
ps.setString(2,"孙悟空");
rs = ps.executeQuery();
while (rs.next()){
    for(int i=0;i<6;i++){
        System.out.print(rs.getObject(i+1)+"\t");
    }
}

4. JDBC工具类

如何编写:

  1. 用常量记录 DRIVERNAME、URL 、USER 、PASSWORD ,也可以用配置文件
  2. 静态代码块中注册驱动(或者是创建数据源)
  3. 提供静态方法 获取连接、 关闭对象。
    其他的方法(像直接执行SQL的方法)就不要提供了,因为如果这样调用者中就没有Connection和Statement的引用,而这两者又只能在处理结果后才能关闭,这就不是静态方法能够实现的功能了。
  4. 工具类类一般都是提供静态方法,不能创建对象。
    我认为所谓工具就是要足够简单,独立,与主程序逻辑没什么关系。拿来即用,用完就不需要有什么后续操作。所以要用静态方法。为了保证它的绝对简单,最好提供private 构造方法,明确禁止创建对象。

示例:

/**
 * JDBC 工具类
 */
public class JDBCUtils {
    //1. 定义字符串常量, 记录获取连接所需要的信息
    public static final String DRIVERNAME = "com.mysql.jdbc.Driver";
    public static final String URL = "jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8";
    public static final String USER = "root";
    public static final String PASSWORD = "123456";
    //2. 静态代码块, 随着类的加载而加载
    static{
        try {
            //注册驱动
            Class.forName(DRIVERNAME);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //3.获取连接的静态方法
    public static Connection getConnection(){
        try {
            //获取连接对象
            Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
            //返回连接对象
            return connection;
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }
    //关闭资源的方法
    public static void close(Connection con, Statement st){
        if(con != null && st != null){
            try {
                st.close();
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static void close(Connection con, Statement st, ResultSet rs){
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        close(con,st);
    }
}

5. 事务控制

mysql的自动事务为每一条DML语句都开启一个事务。JDBC可以通过关闭自动提交来打开事务。

相关方法:

void setAutoCommit(boolean autoCommit);  // 设置为 false 关闭事务的自动提交
void commit();		// 事务提交
void rollback();    // 事务回滚

示例:

//1. 获取连接
con = JDBCUtils.getConnection();
//2. 开启事务
con.setAutoCommit(false);
//3. 获取到 PreparedStatement 执行两次更新操作
//3.1 tom 账户 -500
ps = con.prepareStatement("update account set money = money - ? where name = ? ");
ps.setDouble(1,500.0);
ps.setString(2,"tom");
ps.executeUpdate();
//模拟tom转账后 出现异常
System.out.println(1 / 0);
//3.2 jack 账户 +500
ps = con.prepareStatement("update account set money = money + ? where name = ? ");
ps.setDouble(1,500.0);
ps.setString(2,"jack");
ps.executeUpdate();
//4. 正常情况下提交事务
con.commit();
System.out.println("转账成功!");

6. 批处理

6.1 简介

批处理指的是一次操作中执行多条SQL语句,批处理相比于一次一次执行效率会提高很多。主要用途就是批量操作,如一键生成一千个用户,从提交的文件中提取并导入大批量的数据 等。

6.2 实现

Statement和PreparedStatement都支持批处理操作。

相关方法:

void addBatch();  // 将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。
int[] executeBatch();  // 提交一批命令到数据库中执行,返回的数组是每条命令所影响的行数

示例:

@Test  // Statement 批处理 测试
public void test135() throws Exception{
    Connection conn = DruidUtils.getConnection();
    Statement stmt = conn.createStatement();
    for(int i=0;i<10;i++) {
        stmt.addBatch("insert into appdate values(123,'猪悟能')");
    }
    int[] ints = stmt.executeBatch();
    System.out.println(Arrays.toString(ints));
}

@Test  // PreparedStatement 批处理 测试
public void test150() throws Exception{
    Connection conn = DruidUtils.getConnection();
    PreparedStatement ps = conn.prepareStatement("insert into appdate values(?,?)");
    for(int i=0;i<10;i++) {
        ps.setInt(1, 123);
        ps.setString(2,"猪悟能");
        ps.addBatch();
    }
    int[] ints = ps.executeBatch();
    System.out.println(Arrays.toString(ints));
}

**注意:**批处理中不能进行查询

JDBC基本使用_System_02

7. 获取元数据

相关类:DatabaseMetaData、ResultSetMetaData

使用方法:

DatabaseMetaData:

@Test // DatabaseMetaData 测试
public void test165() throws Exception{
    Connection conn = DruidUtils.getConnection();
    // 通过 Connection 获取 DatabaseMetaData 对象
    DatabaseMetaData dmd = conn.getMetaData();

    // 通过 DatabaseMetaData 对象(dmd) 获取 元数据
    System.out.println(dmd.getDriverName());   // 驱动器名,如:MySQL Connector/J
    System.out.println(dmd.getURL());          // 就是连接是传入的URL 
    System.out.println(dmd.getUserName());     // 登录的用户名,如:root@localhost
    System.out.println(dmd.isReadOnly());      // 是否 只读 

    System.out.println(dmd.getDatabaseProductName());     // 获取数据库软件的名字,如:MySQL
    System.out.println(dmd.getDatabaseProductVersion());  // 获取数据库软件的版本,如:8.0.21
}

ResultSetMetaData

@Test // ResultSetMetaData 测试
public void test178() throws Exception{
    Connection conn = DruidUtils.getConnection();
    PreparedStatement ps = conn.prepareStatement("select * from employee");
    ps.executeQuery();
    // 同过 PreparedStatement 获取 ResultSetMetaData 对象,注意 Statemet 不行。
    ResultSetMetaData rsmd = ps.getMetaData();
    // 通过 ResultsetMetaData 对象获取元数据
    System.out.println(rsmd.getColumnCount());  // 获取结果集的 列数
    System.out.println(rsmd.getColumnName(2)); // 获取结果集 某一列的列名
    System.out.println(rsmd.getColumnTypeName(2)); // 返回对应列的 数据类型(MySQL类型)名字,如:VARCHAR
    System.out.println(rsmd.getColumnClassName(2)); // 返回对应列的 数据类型对应的java类路径,如:java.lang.String
}

8. 注意

  1. statement的方法使用说明
execute()
executeUpdate() 可以进行:
    数据的 增 删 改、
    表的 增 删 改

executeQuery() 可以查询:
    表中 数据
    有哪些表 和 数据库 show tables, show databases
    当前表名 select database()
    表结构 desc 表名 返回 表结构包括:Field、TYPE、NULL、Key、Default、Extra

暂时只能想到这些操作,其余的用到了在补充吧!

  1. Statement与PreparedStatement的选择
    当一次同一SQL要执行很多次时,选择preparedStatement。
    当涉及到查询参数时,使用PreparedStatement。
    其余情况:
    即 只是 简单的 执行单独一条SQL语句,也不用有什么参数限制时,使用Statement即可。
    姑且这么认为吧,对不对的 总得先有个判别依据,要不然太混乱了。
上一篇:date 怎么判空java
下一篇:没有了
网友评论