JDBC

JDBC 基本概念

JDBC: Java DataBase Connectivity, 即 Java 数据库连接.

 

JDBC本质: 是官方定义的一套操作所有关系型数据库的规则, 即接口, 各个数据库厂商去实现这套接口, 提供数据库驱动 jar 包, 我们可以使用这套 (JDBC) 编程, 真正执行的代码是驱动 jar 包中的实现类.

 

Java 连接 MySQL 需要驱动包,最新版下载地址为:http://dev.mysql.com/downloads/connector/j/,解压后得到jar库文件,然后在对应的项目中导入该库文件.

 

JDBC 初步使用 (创建表)

使用 mysql jar 包操作数据库的步骤:

首先需在 mysql 上创建数据库

  1. 在项目里边导入 mysql jar 包, 注册驱动

  2. 获取数据库连接对象, 获取游标对象 cursor

  3. 组织 sql 语句

  4. 使用 cursor 执行 sql

  5. 处理结果

  6. 释放资源

 

demo: 

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

/**
 * JDBC 初步使用
 */
public class ConnectDataBase {
    public static void main(String[] args) throws Exception {
        // 导入 mysql jar 包, 注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 获取数据库连接对象, 获取 cursor
        Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.0.115/JDBC", "username", "passwd");
        Statement st = conn.createStatement();
        // 写 sql
        String sql = "create table student(id int unsigned primary key auto_increment not null, name varchar(150))";
        // 执行 sql
        int num = st.executeUpdate(sql);
        // 处理结果
        // 执行成功返回 0, 再次执行: Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'student' already exists
        System.out.println(num);
        // 释放资源
        st.close();
        conn.close();
    }
}

 

JDBC 包中各个实现类详解

DriverManager: 驱动管理对象

  1. 导入 mysql jar 包, 注册驱动

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

    通过查看源码发现, 在 com.mysql.jdbc.Driver 类中存在静态代码块:

    static {
        try {
            java.sql.DriverManager.registerDriver(new Dirver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    提示: mysql 1.5版本之后的 jar 包可以省略注册驱动的步骤 (会根据配置文件自动导入)

     

  2. 获取数据库连接

    public static Connection getConnection(String url, String user, String password)

    url: jdbc:mysql://IP:PORT/DataBaseName

 

Connection: 数据库连接对象

  1. 获取执行 sql 的cursor 对象

    Statement createStatement();

    PreparedStatement prepareStatement(String sql);

     

  2. 管理事务

    开启事务: void setAutoCommit(boolean autoCommit);

    提交事务: commit()

    回滚事务: rollback()

 

Statement: 执行 sql 的对象

  1. 执行sql

    int executeUpdate(String sql): 执行 DML (insert, update, delete) , DDL (create, alter, drop)

    ResultSet executeQuery(String sql): 执行DQL (select)

    boolean execute(String sql): 可以执行任意的sql (不常用)

 

ResultSet: 结果集对象

封装查询结果

常用方法:

  1. boolean next(): 游标向下移动一行

  2. int getInt(int columnIndex): 获取一个 int 类型的值 (传编号[编号从1开始] 或 列名)

  3. int getInt(String columnLabel)

  4. String getString(int columnIndex): 获取一个 String 类型的值 (传编号 或 列名)

  5. String getString(String columnLabel)

 

PreparedStatement: 执行 sql 的对象

使用 PreparedStatement 对象能解决 sql 注入的问题,

 

JDBC 操作数据库练习

插入一条数据:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 使用 JDBC 插入一条数据
 */
public class JdbcDemo01 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        try {
            // 1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2.编写sql
            String sql = "insert into student values(null, 'johny')";
            // 3.获取数据库连接
            conn = DriverManager.getConnection("jdbc:mysql://192.168.0.115:3306/JDBC", "username", "passwd");
            // 4.获取statement操作对象
            st = conn.createStatement();
            // 5.执行sql
            int num = st.executeUpdate(sql);
            // 6.处理sql执行结果
            System.out.println(num);  // 1
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7.释放资源
            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
View Code

 

查询一条数据:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;

/**
 * 使用 JDBC 查询一条数据
 */
public class JdbcDemo01 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet ret = null;
        try {
            // 1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 2.编写sql
            String sql = "select * from student";
            // 3.获取数据库连接
            conn = DriverManager.getConnection("jdbc:mysql://192.168.0.115:3306/JDBC", "username", "passwd");
            // 4.获取statement操作对象
            st = conn.createStatement();
            // 5.执行sql
            ret = st.executeQuery(sql);
            // 6.处理sql执行结果
            ret.next();
            int id = ret.getInt(1);
            String name = ret.getString("name");
            System.out.println(String.format("id: %s, name: %s", id, name));   // id: 1, name: johny

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7.释放资源
            try {
                ret.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }

            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
View Code

 

抽取 JDBC 工具类

步骤:

  1. 封装 JDBCUtils 工具类

  2. 通过 properties 配置文件来读取数据库连接信息

  3. 通过静态代码块来初始化, 连接到数据库

  4. 封装释放资源的静态方法

 

jdbc.properties:

ipaddr=192.168.0.115
port=3306
dbname=JDBC
username=chenkai
passwd=chenkai

 

JDBCUtils:

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


/**
 * 封装 JDBC 的工具类
 */
public class JDBCUtils {
    private static String ipaddr;
    private static String port;
    private static String dbname;
    private static String username;
    private static String passwd;

    static {
        try {
            // 读取配置文件, 初始化连接数据库
            Properties pro = new Properties();
            // 获取 src 路径下的文件 --> ClassLoader
            ClassLoader cl = JDBCUtils.class.getClassLoader();
            URL url = cl.getResource("jdbc.properties");
            String path = url.getPath();  // 配置文件的绝对路径
            // 加载配置文件
            pro.load(new FileReader(path));
            // 获取配置文件中的参数
            ipaddr = pro.getProperty("ipaddr");
            port = pro.getProperty("port");
            dbname = pro.getProperty("dbname");
            username = pro.getProperty("username");
            passwd = pro.getProperty("passwd");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 获取连接
    public static Connection getConnection(){
        try {
            // 注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 获取连接
            Connection conn = DriverManager.getConnection(String.format("jdbc:mysql://%s:%s/%s", ipaddr, port, dbname), username, passwd);
            return conn;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //
        return null;
    }

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

        if (statement!=null) {
            try {
                ret.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (conn!=null) {
            try {
                ret.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void close(PreparedStatement pstatement, Connection conn){
        if (pstatement!=null) {
            try {
                pstatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if (conn!=null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
View Code

 

demo: 

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;

/**
 * 使用 JDBC 查询一条数据
 */
public class JdbcDemo01 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement st = null;
        ResultSet ret = null;
        try {
            // 1.获取数据库连接
            conn = JDBCUtils.getConnection();
            // 2.编写sql
            String sql = "select * from student";
            // 4.获取statement操作对象
            st = conn.createStatement();
            // 5.执行sql
            ret = st.executeQuery(sql);
            // 6.处理sql执行结果
            ret.next();
            int id = ret.getInt(1);
            String name = ret.getString("name");
            System.out.println(String.format("id: %s, name: %s", id, name));

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7.释放资源
            JDBCUtils.close(ret, st, conn);
        }
    }
}

 

PreparedStatement & sql注入

使用 PreparedStatement 对象执行sql的步骤:

  1. 导入驱动包

  2. 获取数据库连接对象

  3. 定义 sql (使用 ? 作为占位符)

  4. 获取sql执行对象 (PreparedStatement)

  5. 给 ? 赋值(setInt, setString... 传递两个参数, 位置和值, 位置从 1 开始)

  6. 执行sql (不需要再传递 sql 语句)

  7. 处理结果

  8. 释放资源

 

后边操作数据库都用 PreparedStatement 对象来完成增删改查的所有操作

 

模拟用户登录, 处理 sql 注入问题: 

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

/**
 * 模拟用户登录, 处理sql注入问题
 */
public class UserLogin {
    public Connection conn = null;
    public PreparedStatement pstat = null;
    public ResultSet ret = null;


    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username = sc.nextLine();
        System.out.print("请输入密码:");
        String passwd = sc.nextLine();

        boolean ret = new UserLogin().login(username, passwd);
        if (ret) {
            System.out.println("登录成功");
        } else {
            System.out.println("用户名或密码输入错误!");
        }
    }

    public boolean login(String username, String passwd){
        if (username == null | passwd == null) {
            return false;
        }

        try{
            // 通过 JDBCUtils 获取数据库连接
            conn = JDBCUtils.getConnection();
            // 拼写sql
            String sql = "select * from user where username = ? and passwd = ?";
            // 获取 PreparedStatement 对象
            pstat = conn.prepareStatement(sql);
            // 给 sql 赋值
            pstat.setString(1, username);
            pstat.setString(2, passwd);
            // 执行 sql
            ret = pstat.executeQuery();
            // 处理结果
            return ret.next();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(ret, pstat, conn);
        }
        return false;
    }
}

 

JDBC 控制事务

事务: 它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的操作单位.

使用 Connection 对象来管理事务

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

    执行 sql 前开启事务.

  2. 提交事务: commit()

    所有 sql 都执行完提交事务.

  3. 回滚事务: rollback()

    在 catch 中回滚事务.

 

demo: 

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 *  JDBC 事务的应用, 模拟转账
 */
public class JdbcDemo02 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement pstat1 = null;
        PreparedStatement pstat2 = null;

        try {
            // 获取数据库连接
            conn = JDBCUtils.getConnection();
            // 开启事务!!!
            conn.setAutoCommit(false);
            // 编写sql
            String sql1 = "update user set balance = balance - 500 where username = ?";
            String sql2 = "update user set balance = balance + 500 where username = ?";
            // 获取 preparedStatement 对象
            pstat1 = conn.prepareStatement(sql1);
            pstat2 = conn.prepareStatement(sql2);
            // 给 sql 赋值
            pstat1.setString(1, "xiaoming");
            pstat2.setString(1, "xiaohong");
            // 执行sql
            pstat1.executeUpdate();
            pstat2.executeUpdate();

            //手动抛出异常
            int a = 3 / 0;

            // 提交事务
            conn.commit();
            System.out.println("处理完成");
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚事务, 数据库连接不为空的时候进行回滚  (不会滚也不会更新成功, 回滚是不是在释放资源 ?)
            if (conn != null) {
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
        } finally {
            // 释放资源
            JDBCUtils.close(pstat1, conn);
            JDBCUtils.close(pstat2, null);
        }
    }
}

 

 

ending ~ 

 

 

posted @ 2019-11-15 10:47  kaichenkai  阅读(192)  评论(0编辑  收藏  举报