0306-JDBC技术

  • JDBC技术

JDBC:
在 Java 中连接数据库的技术。
在 Java 代码中想操作数据库中的数据。就必须使用到 JDBC 技术。
通过 JDBC 从 Java 代码中向数据库发送执行的 SQL 语句。

JDBC 是什么?

JDBC : Java DataBase Connector 中文:Java 数据库连接技术。
JDBC 是一种技术。一种在 Java 程序中连接数据库的技术。
使用 JDBC 可以实现在 Java 代码中去操作数据库的表中的记录。

JDBC 是一个持久化技术。

持久化:

化:过程。

数据是分为 临时状态 和 持久状态 。
-临时状态:数据保存在内存中。代码在运行时的数据。
-持久状态:数据保存在硬盘中,以文件的方式长期保存的数据。

持久化:数据从 临时状态 与 持久状态 之间进行切换的过程。

  1. 将 Java 程序中的数据保存到数据库中。
  2. 将数据库中的数据读取到 Java 程序中。

  • JDBC 是一套规范也是标准

JDBC 是指一套规范,约定了 Java 语言连接到不同数据库产品时的标准。

任何数据库产品,想让自己的产品,可以使用 JDBC 连接到 Java 程序,就要按 JDBC 的标准编写数据库的驱动。

数据库的驱动是数据库厂商按 JDBC 标准,由各数据库厂商自己编写的
JDBC 本身就是一组接口。各大数据库厂商需要根据自己的数据库去实现这一组接口。


  • JDBC 中的三个核心接口

Connection 接口

Connection 是连接对象,负责创建 Java 程序与数据库之间的连接。

Connection 接口的实现类由各数据库厂商提供。称为驱动类。操作数据库之前必先获得驱动类。

Statement 接口

常用的子接口 PreparedStatement 接口

PreparedStatement 是操作对象。负责通过 Connection 的连接,向数据库执行 SQL 语句。

ResultSet 接口

ResultSet 是结果集接口,当我们使PreparedStatement 向数据库执行 Select 命令时,Java 程序需要接收到查询结果。

在Java程序端就是使用 ResultSet 对象来接收查询结果的。

数据库的查询结果就是一个二维表格。

ResultSet 也是一个表格的处理方式。


  • 使用 JDBC 操作数据库的基本步骤

使用 JDBC 操作数据库的步骤就三步:

  1. 打开连接
    将 Java 程序与数据库创建连接。
  2. 操作数据库
    通过 Java 程序向数据库发送 SQL 语句执行。
    分增删改,和 查询。
    查询有返回值,返回值叫结果集。
  3. 关闭连接
    释放资源,一定要执行的部分。finally块中执行。

打开连接:

打开连接,先获取连接数据库的驱动类。
驱动类是数据库厂商提供。是个Jar包。

还要再确定四个参数:

  1. 驱动类的名称
  2. 连接数据库的字符串
  3. 数据库账号
  4. 密码
//四大参数
String driverClassName="oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:thin:@localhost:1521:XE";
String userName = "scott";
String userPass = "tiger";
//获得连接对象
Connection conn = DriverManager.getConnection(url,userName,userPass);

操作数据库:

  1. 增删改
//通过PreparedStatement对象来操作数据库
String sql = "insert into users_no5(user_id,user_name) values( SEQ01.nextval , '都醒着')";
PreparedStatement pstat = conn.prepareStatement(sql);
pstat.executeUpdate();//执行增删改语句的方法
  1. 查询

rs 对象就是一个指向二维表格的引用。rs 对象每次只能指向一行。通过next() 向下移动一行。

通过 getXXX() 方法获取指定列的值。

//通过PreparedStatement对象来操作数据库
String sql = "select * from users_no5";
PreparedStatement pstat = conn.prepareStatement(sql);
ResultSet rs = pstat.executeQuery();//rs就是一个二维表格。
while(rs.next()){//向下移一行。
    System.out.println(rs.getInt("user_id"));
    System.out.println(rs.getString("user_name"));
    System.out.println("----------");
}

关闭连接:

关闭数据库连接对象

//关闭连接
conn.close();

  • 预编译的操作接口 PreparedStatement

使用 PreparedStatement 可以提前将要执行的 SQL 语句进行数据库端的预编译。
使用 PreparedStatement 可以提高执行效率。并且安全。防止 SQL 注入。

在哪提前写 SQL 语句:

在创建 pstat 对象时,就已经提前将 SQL 写好了。

String sql = "insert into users_no5(user_id,user_name) values(seq01.nextval,'XXX')" ;
PreparedStatement pstat = conn.prepareStatement(sql);

可以使用 ? 在 SQL 语句中定义变量:

String sql = "insert into users_no5(user_id,user_name) values(seq01.nextval,?)" ;
PreparedStatement pstat = conn.prepareStatement(sql);

可以使用 setXXX() 方法为 ? 赋值:

一定是在 SQL 语句执行之前,先为所有的 ? 号进行赋值。

public abstract void setString(int parameterIndex,String x)
参数:parameterIndex 表示 ? 的索引。从1开始。 x 表示值。

String sql = "insert into users_no5(user_id,user_name) values(seq01.nextval,?)" ;
PreparedStatement pstat = conn.prepareStatement(sql);
pstat.setString(1,"???");
int i = pstat.executeUpdate();

  • 经典面试题:

Statement 与 PreparedStatement 之间的区别?

  1. PreparedStatement 可以使用占位符,是预编译的,批处理比 Statement 效率高。
  2. Statement 用于执行静态 SQL 语句,在执行时,必须指定一个事先准备好的 SQL 语句。
  3. PrepareStatement 是预编译的 SQL 语句对象,sql 语句被预编译并保存在对象中。被封装的 sql 语句代表某一类操作,语句中可以包含动态参数“?”,在执行时可以为“?”动态设置参数值。
  4. 使用 PrepareStatement 对象执行 sql 时,sql 被数据库进行解析和编译,然后被放到命令缓冲区,每当执行同一个 PrepareStatement 对象时,它就会被解析一次,但不会被再次编译。在缓冲区可以发现预编译的命令,并且可以重用。
  5. PrepareStatement 可以减少编译次数,从而提高数据库性能。
  6. PreparedStatement 可防止 SQL 注入。

PS:批处理时,以数据量大小为标准选择 Statement 与 PrepareStatement 时的标准:

  1. 量比较小,二者皆差别不大。
  2. 量比较多,在 PreparedStatement 预编译空间范围之内,选择PreparedStatement,因为其只预编译一次 sql 语句。
  3. 量特别大,使用 Statement,因为 PrepareStatement 的预编译空间有限,当数据量特别大时,会发生异常。

  • 结果集对象-ResultSet 接口

ResultSet 对象是用来接收查询结果的对象。
数据库的查询结果就是一个二维表格。

rs 对象就是一个指向查询结果每一行的一个指针。

如何获得 RS 对象:

通过 pstat 对象执行 executeQuery() 方法获得一个 RS 对象。

String sql = "select * from users_no5 order by user_id ";
PreparedStatement pstat = conn.prepareStatement(sql);
ResultSet rs = pstat.executeQuery();

  • EOF 和 BOF

BOF 表示第一行的上面。
EOF 表示最后一行的下面。

rs 对象就是一个指向查询结果每一行的一个指针。
rs 对象默认指向 BOF。只有调用一次 next() 方法才能指向第一行。
rs 对象调用next()方法,指向了EOF,就表示当前查询结果已经没有了。next() 方法返回 False;


  • next() 方法

boolean next() throws SQLException;
向下移动一行。当指向 EOF 时返回 false。

ResultSet rs = pstat.executeQuery();
while(rs.next()){
    int userId = rs.getInt("user_id");
    String name = rs.getString("user_name");
    System.out.println(userId+":"+name);
    System.out.println("----------");
}

  • getString() 方法

String getString (String columnLabel) throws SQLException;
int getInt (String columnLabel) throws SQLException;

传入参数为列名,用来获取指针指向的这列的数据。


  • 封装 JDBC 的操作

封装原则:

封装原则:将变化的 和 不变化的 分开进行封装。
以实现,在需求改时,对变化的部分进行修改时,不会影响到不变化 的部分。

数据库操作步骤的封装:

数据库的操作步骤:3步。
1 打开连接
2 操作数据库
3 关闭连接

----变化 :2 操作数据库 (DAO 数据访问对象)
这部分内容是根据操作的不同,代码不一致。
针对不同的表。针对同一张表的不同的 CRUD。

----不变化 :1 打开连接 和 3 关闭连接 (工具类)
不管对数据库进行什么操作, 都必须先打开连接,最后关闭连接。


  • 封装连接对象的工具类(第一版)

在这个工具类中,要封装两个行为。
1 打开连接
3 关闭连接

/**
 * 在这个工具类中,要封装二个行为。
 * 1 打开连接   getConn()
 * 3 关闭连接   closeConn()
 */
public class ConnUtils {
    private static Connection conn;
    private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:XE";//SID数据库实例名
    private static final String USER_NAME = "no5";
    private static final String USER_PASS = "123456";
    private static final String CLASS_NAME = "oracle.jdbc.driver.OracleDriver";

    /**
     * 打开连接
     *
     * @return 连接对象
     */
    public static Connection getConn() throws SQLException {
        if (conn == null || conn.isClosed()) {
            conn = DriverManager.getConnection(URL, USER_NAME, USER_PASS);
        }
        return conn;
    }

    /**
     * 关闭连接
     */
    public static void closeConn() throws SQLException {
        try {
            if (conn != null && !conn.isClosed()) {
                conn.close();
            }
        } finally {
            conn = null;
        }
    }
}

编写实体类,映射数据库表:

数据库表:users_no5
表示的是用户信息。
表中的每一第记录就是一个用户实体。
表结构:
在这里插入图片描述
表记录:
在这里插入图片描述

用户实体 在 Java 程序中使用什么表示?

//users_no5
public class Users {
    //    USER_ID  NUMBER(7,0)
    private Integer userId;
    //    USER_NAME    VARCHAR2(20 BYTE)
    private String userName;
    ......
}

  • 编写DAO

DAO:数据访问对象。负责封装操作数据库的代码。

编写 UsersDAO 类:

案例代码如下所示:

    /**
     * 增加用户信息方法
     * @param user
     */
    public void insertUser(Users user) throws SQLException {
        String sql = "insert into user_testdb (user_id,user_name) values (seq01.nextval,?)";
        Connection conn = ConnUtils.getConn();
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setString(1,user.getUserName());
        pstmt.executeUpdate();
    }

    /**
     * 查询所有用户信息方法
     * @return
     * @throws SQLException
     */
    public List<Users> selectAll() throws SQLException {
        List<Users> users = new ArrayList<>();
        Connection conn = ConnUtils.getConn();
        String sql = "select * from user_testdb";
        PreparedStatement pstmt = conn.prepareStatement(sql);
        ResultSet rs = pstmt.executeQuery();
        while (rs.next()) {
            Users user = new Users(rs.getInt("user_id"),rs.getString("user_name"));
            users.add(user);
        }
        return users;
    }

    /**
     * 删除用户的方法
     * @throws SQLException
     */
    public void deleteUser(Integer id) throws SQLException {
        String sql = "delete from user_testdb where user_id=?";
        Connection conn = ConnUtils.getConn();
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setInt(1,id);
        pstmt.executeUpdate();
    }

    /**
     * 更新记录
     * @param user
     * @throws SQLException
     */
    public void updateUser(Users user) throws SQLException {
        String sql = "update user_testdb set user_name=? where user_id=?";
        Connection conn = ConnUtils.getConn();
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setString(1,user.getUserName());
        pstmt.setInt(2,user.getUserId());
        pstmt.executeUpdate();
    }

    /**
     * 按id来查信息
     * @param id 需要查询信息的ID
     * @return Users对象
     * @throws SQLException
     */
    public Users selectById(Integer id) throws SQLException {
        String sql = "select * from user_testdb where user_id=?";
        Connection conn = ConnUtils.getConn();
        PreparedStatement pstmt = conn.prepareStatement(sql);
        pstmt.setInt(1,id);
        ResultSet rs = pstmt.executeQuery();
        if (rs.next()){
            Users user = new Users();
            user.setUserId(rs.getInt("user_id"));
            user.setUserName(rs.getString("user_name"));
            return user;
        }else{
            return null;
        }
    }

  • 使用 JUnit 进行单元测试

Junit 是一个单元测试的软件。
我们编写的类中方法,使用 Junit 可以方便的进行单元测试。

@Test
public void selectById(){
    UsersDAO usersDAO = new UsersDAO();
    try {
        Users users = usersDAO.selectById(1);
        System.out.println(users);
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        try {
            ConnUtils.closeConn();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

@Test
public void updateUser(){
    Users users = new Users(21,"陆奥克兰");
    UsersDAO usersDAO = new UsersDAO();
    try {
        usersDAO.updateUser(users);
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        try {
            ConnUtils.closeConn();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

@Test
public void deleteUser(){
    UsersDAO usersDAO = new UsersDAO();
    try {
        usersDAO.deleteUser(21);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

@Test
public void insertUser(){
    Users users = new Users();
    users.setUserName("阿里");
    UsersDAO usersDAO = new UsersDAO();
    try {
        usersDAO.insertUser(users);
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        try {
            ConnUtils.closeConn();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

@Test
public void selectAll(){
    UsersDAO usersDAO = new UsersDAO();
    List<Users> users = null;
    try {
        users = usersDAO.selectAll();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    System.out.println(users);
}

  • 封装连接对象的工具类(第二版)

第一版在单用户使用时,没有问题。

我们后面一定会学习 web 应用程序开发的。像 taobao,jd 这些是 web 应用程序?

Web 应用程序本身就是一个多用户的应用程序。每一个用户是一个单独的线程。

private static Connection conn;

static 静态,属于类的属性,整个应用程序只有一份。
单用户应用时,只用一个连接对象没关系。
多用户应用时,就变成所有用户使用同一个连接对象。

ThreadLoacl 类:

本地线程容器对象。每一个线程都有一个自己的 ThreadLocal 对象。

这个对象只能保存一个内容。

使用 ThreadLoacl 类修改 ConnUtils 工具类:

public class ConnUtils {
    private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();
    private static final String URL = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
    private static final String USER_NAME = "no5";
    private static final String USER_PASS = "123456";
    private static final String CLASS_NAME = "oracle.jdbc.driver.OracleDriver";
    /**
     * 打开连接
     *
     * @return 连接对象
     */
    public static Connection getConn() throws SQLException {
        Connection conn = THREAD_LOCAL.get();
        if (conn == null || conn.isClosed()) {
            conn = DriverManager.getConnection(URL, USER_NAME, USER_PASS);
            THREAD_LOCAL.set(conn);
        }
        return conn;
    }
    /**
     * 关闭连接
     */
    public static void closeConn() throws SQLException {
        try {
            Connection conn = THREAD_LOCAL.get();
            if (conn != null && !conn.isClosed()) {
                conn.close();
            }
        } finally {
            THREAD_LOCAL.set(null);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值