JDBC (2) 基本操作

373 阅读7分钟

1. JdbcTemplate

概念: 封装一个自定义的 JdbcTemplate 类,负责获取数据源,以及封装各种类型的SQL语句的执行方法:

流程:

  1. 通过 DriverManager 创建一个连接实例 connection
  2. 通过 connection 创建一个SQL媒介实例 statement,负责运输SQL语句到数据库,执行并且拿回结果。
    • 如果是查询操作,会返回一个 ResutlSet 结果集。
    • 如果是其他操作,会返回一个影响的条目数。
  3. 解析 ResutlSet 结果集:
    • 多条结果集可以解析成一个 List<Map> 或者 List<Pojo> 结构。
    • 单条的结果可以解析成一个 Map<String, Object> 结构。
    • 单条的结果可以解析成一个 Pojo 结构。
  4. 释放资源,关闭连接。

查询流程图

2. DDL-execute()

概念: boolean execute(String sql) 用于执行DDL操作,如造表,造索引等,该方法接收一个完整的SQL语句,并返回一个 boolean 类型的结果。

流程:

  1. 通过 dataSource 实例获取一个连接实例 connection
    • Connection getConnection()
  2. 通过连接实例 connection,获取一个 Statement 类型的SQL媒介实例 statement
    • Statement createStatement()
  3. 通过SQL媒介实例 statement 将SQL发送到数据库,执行并得到 boolean 类型的结果:
    • boolean execute(String sql):结果只有是 ResultSet 对象时才返回true。
  4. 封装一个 closeStatement(Statement statement) 负责释放资源:
    • 如果资源不为null,就直接调用资源的 close() 进行关闭。
  5. 通过 dataSource 实例关闭当前连接:
    • void closeConnection(Connection connection)

3. DML-update()

概念: int[] batchUpdate(String sql, Object[]... params) 用于执行DML操作,如增,删,改数据操作,该方法接收一个包含占位符的SQL语句和对应占位符的参数列表,返回int类型结果表示本次操作所影响的条目数。

流程:

  1. 通过 dataSource 实例获取一个连接实例 connection
    • Connection getConnection()
  2. 通过连接实例 connection,获取一个 PrepareStatement 类型的SQL媒介实例 prepareStatement
    • PreparedStatement prepareStatement(String sql):获取的同时需要绑定SQL。
  3. 封装一个 sendSqlAndGetInt() 负责为SQL中的问号赋值,以及发送SQL,并拿回int类型结果:
    • void setObject(int i, Object x):第i个问号赋值x,i从1开始。
    • int executeUpdate():通过媒介将SQL发送到数据库,执行并得到结果。
  4. 封装一个 closeStatement(Statement statement) 负责释放资源:
    • 如果资源不为null,就直接调用资源的 close() 进行关闭。
  5. 通过 dataSource 实例关闭当前连接:
    • void closeConnection(Connection connection)

4. DML-batchUpdate()

概念: int[] batchUpdate() 用于执行批量DML操作,如批增,批删,批改等。

4.1 批处理同类型SQL

概念: int[] batchUpdate(String sql, Object[]... params) 负责批量处理多条相同类型的SQL,需要设置事务保护,返回批量DML操作的影响条目数数组。

流程:

  1. 通过 dataSource 实例获取一个连接实例 connection
    • Connection getConnection()
  2. 通过连接实例 connection,获取一个 PrepareStatement 类型的SQL媒介实例 prepareStatement
    • PreparedStatement prepareStatement(String sql):获取的同时需要绑定SQL。
  3. 关闭连接实例 connection 的自动提交属性:
    • void setAutoCommit(boolean autoCommit):默认为true。
  4. 封装一个 sendSqlAndGetIntArray() 负责为每条SQL中的问号赋值,以及发送SQL,并拿回int[]类型结果:
    • void setObject(int i, Object x):第i个问号赋值x,i从1开始。
    • int addBatch():将拼装完整的SQL语句加入到预执行区域,等待 executeBatch()
    • int[] executeBatch():将预执行区域中的所有SQL语句发送到数据库,执行并返回int[]类型的结果。
  5. 通过连接实例 connection,手动提交或者回滚本次操作:
    • void commit()
    • void rollback():在异常捕捉中进行处理。
  6. 在异常处理的 finally 块中,将自动提交属性还原。
    • void setAutoCommit(boolean autoCommit):默认为true。
  7. 封装一个 closeStatement(Statement statement) 负责释放资源:
    • 如果资源不为null,就直接调用资源的 close() 进行关闭。
  8. 通过 dataSource 实例关闭当前连接:
    • void closeConnection(Connection connection)

4.2 批处理不同类型SQL

概念: int[] batchUpdate(String... sqls) 负责批量处理多条不同类型的SQL,需要设置事务保护,该方法需要传入一个完整SQL的数组,返回批量DML操作的影响条目数数组。

流程:

  1. 通过 dataSource 实例获取一个连接实例 connection
    • Connection getConnection()
  2. 通过连接实例 connection,获取一个 Statement 类型的SQL媒介实例 statement
    • Statement createStatement()
  3. 关闭连接实例 connection 的自动提交属性:
    • void setAutoCommit(boolean autoCommit):默认为true。
  4. 封装一个 sendSqlAndGetIntArray() 负责将每条SQL添加到预执行区域,然后一起提交执行:
    • void addBatch(String sql):将SQL语句加入到预执行区域,等待 executeBatch()
    • int[] executeBatch():将预执行区域中的所有SQL语句发送到数据库,执行并返回int[]类型的结果。
  5. 通过连接实例 connection,手动提交或者回滚本次操作:
    • void commit()
    • void rollback():在异常捕捉中进行处理。
  6. 在异常处理的 finally 块中,将自动提交属性还原。
    • void setAutoCommit(boolean autoCommit):默认为true。
  7. 封装一个 closeStatement(Statement statement) 负责释放资源:
    • 如果资源不为null,就直接调用资源的 close() 进行关闭。
  8. 通过 dataSource 实例关闭当前连接:
    • void closeConnection(Connection connection)

5. DQL-queryForList()

概念: List<Map<String, Object>> queryForList(String sql, Object... params) 用于多行信息查询,该方法接收一个包含占位符的SQL语句和对应占位符的参数列表,返回 List<Map> 结构的结果集。

流程:

  1. 通过 dataSource 实例获取连接:
    • Connection getConnection()
  2. 通过连接实例 connection,获取一个 PrepareStatement 类型的SQL媒介实例 prepareStatement
    • PreparedStatement prepareStatement(String sql):获取的同时需要绑定SQL。
  3. 封装一个 sendSqlAndGetResultSet() 负责为SQL中的问号赋值,以及发送SQL,并拿回结果:
    • void setObject(int i, Object x):第i个问号赋值x,i从1开始。
    • ResultSet executeQuery():通过媒介将SQL发送到数据库,执行并得到 ResultSet 结果集。
  4. 封装一个 changeResultSetToList(),负责将 ResultSet 转化为 List<Map> 结构:
    • ResultSetMetaData getMetaData():通过 ResultSet 对象获取元数据。
    • int getColumnCount():通过 ResultSetMetaData 对象获取表的总列数。
    • String getColumnName(int column):通过 ResultSetMetaData 对象获取指定索引的列名,从1开始。
    • Object getObject(String columnLabel):通过 ResultSet 对象获取对应列名的值。
  5. 封装一个 closeResultSet(ResultSet resultSet) 负责释放资源:
    • 如果资源不为null,就直接调用资源的 close() 进行关闭。
  6. 封装一个 closeStatement(Statement statement) 负责释放资源:
    • 如果资源不为null,就直接调用资源的 close() 进行关闭。
  7. 通过 dataSource 实例关闭连接:
    • void closeConnection(Connection connection)

6. DQL-queryForMap()

概念: Map<String, Object> queryForMap(String sql, Object... params) 用于单行信息查询,该方法接收一个包含占位符的SQL语句和对应占位符的参数列表,返回 Map 结构的结果集。

流程:

  1. 调用 queryForList() 获得唯一一行数据。
  2. 如果数据正常,取出 List 中的唯一一条数据并返回。
  3. 如果数据异常,返回一个空Map实例。

7. DQL-queryForInt()

概念: int queryForInt(String sql, Object... params) 用于数据数量查询,该方法接收一个包含占位符的SQL语句和对应占位符的参数列表,返回int类型的结果。

流程:

  1. 调用 queryForMap() 获得包含数量信息的Map结果。
  2. 如果数据正常,取出 Map 中的结果并转成int类型。
  3. 如果数据异常,返回-1。

整体代码

源码: jdbc/JdbcTemplate

package com.yap.jdbc;

import com.yap.factory.DataSource;
import com.yap.factory.DataSourceFactory;

import java.sql.*;
import java.util.*;

/**
 * @author yap
 */
public class JdbcTemplate {

    private DataSource dataSource = DataSourceFactory.getDataSource();

    public boolean execute(String sql) {
        boolean result = false;
        Connection connection = null;
        Statement statement = null;
        try {
            connection = dataSource.getConnection();
            statement = connection.createStatement();
            result = statement.execute(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeStatement(statement);
            dataSource.closeConnection(connection);
        }
        return result;
    }

    public int update(String sql, Object... params) {
        Connection connection = null;
        PreparedStatement prepareStatement = null;
        int result = -1;
        try {
            connection = dataSource.getConnection();
            prepareStatement = connection.prepareStatement(sql);
            result = sendSqlAndGetInt(prepareStatement, params);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeStatement(prepareStatement);
            dataSource.closeConnection(connection);
        }
        return result;
    }

    public int[] batchUpdate(String sql, Object[]... params) {
        Connection connection = null;
        PreparedStatement prepareStatement = null;
        int[] result = null;
        try {
            connection = dataSource.getConnection();
            connection.setAutoCommit(false);
            prepareStatement = connection.prepareStatement(sql);
            result = sendSqlAndGetIntArray(prepareStatement, params);
            connection.commit();
        } catch (SQLException e) {
            try {
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            try {
                if (connection != null) {
                    connection.setAutoCommit(true);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            closeStatement(prepareStatement);
            dataSource.closeConnection(connection);
        }
        return result;
    }

    public int[] batchUpdate(String... sqls) {
        Connection connection = null;
        Statement statement = null;
        int[] result = null;
        try {
            connection = dataSource.getConnection();
            connection.setAutoCommit(false);
            statement = connection.createStatement();
            result = sendSqlAndGetIntArray(statement, sqls);
            connection.commit();
        } catch (SQLException e) {
            try {
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            try {
                if (connection != null) {
                    connection.setAutoCommit(true);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            closeStatement(statement);
            dataSource.closeConnection(connection);
        }
        return result;
    }

    public List<Map<String, Object>> queryForList(String sql, Object... params) {
        List<Map<String, Object>> result = new ArrayList<>();
        Connection connection = null;
        PreparedStatement prepareStatement = null;
        ResultSet resultSet = null;
        try {
            connection = dataSource.getConnection();
            prepareStatement = connection.prepareStatement(sql);
            resultSet = sendSqlAndGetResultSet(prepareStatement, params);
            result = changeResultSetToList(resultSet);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            closeResultSet(resultSet);
            closeStatement(prepareStatement);
            dataSource.closeConnection(connection);
        }
        return result;
    }

    public Map<String, Object> queryForMap(String sql, Object... params) {
        Map<String, Object> resultMap = new HashMap<>(10);
        List<Map<String, Object>> list = queryForList(sql, params);
        if (!list.isEmpty()) {
            resultMap = list.get(0);
        }
        return resultMap;
    }

    public int queryForInt(String sql, Object... params) {
        int result = -1;
        Map<String, Object> map = queryForMap(sql, params);
        Object value = null;
        for (String key : map.keySet()) {
            value = map.get(key);
            break;
        }
        if (value != null) {
            result = Integer.parseInt(value.toString());
        }
        return result;
    }

    private int[] sendSqlAndGetIntArray(Statement statement, String... sqls) throws SQLException {
        for (String sql : sqls) {
            statement.addBatch(sql);
        }
        return statement.executeBatch();
    }

    private int sendSqlAndGetInt(PreparedStatement prepareStatement, Object... params) throws SQLException {
        for (int i = 0, j = params.length; i < j; i++) {
            prepareStatement.setObject(i + 1, params[i]);
        }
        return prepareStatement.executeUpdate();
    }

    private int[] sendSqlAndGetIntArray(PreparedStatement prepareStatement, Object[]... params) throws SQLException {
        for (Object[] param : params) {
            for (int i = 0, j = param.length; i < j; i++) {
                prepareStatement.setObject(i + 1, param[i]);
            }
            prepareStatement.addBatch();
        }
        return prepareStatement.executeBatch();
    }

    private ResultSet sendSqlAndGetResultSet(PreparedStatement prepareStatement, Object... params) throws SQLException {
        for (int i = 0, j = params.length; i < j; i++) {
            prepareStatement.setObject(i + 1, params[i]);
        }
        return prepareStatement.executeQuery();
    }

    private List<Map<String, Object>> changeResultSetToList(ResultSet resultSet) throws SQLException {
        List<Map<String, Object>> resultList = new ArrayList<>();
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        Map<String, Object> tempMap;

        // rows
        while (resultSet.next()) {
            tempMap = new HashMap<>(10);
            // columns in row, iter from 1
            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnName(i);
                Object value = resultSet.getObject(columnName);
                tempMap.put(columnName, value);
            }
            resultList.add(tempMap);
        }
        return resultList;
    }

    private void closeStatement(Statement statement) {
        try {
            if (statement != null) {
                statement.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void closeResultSet(ResultSet resultSet) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

源码: test/JdbcTemplateTest

package com.yap.test;

import com.yap.jdbc.JdbcTemplate;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author yap
 */
public class JdbcTemplateTest {

    private JdbcTemplate jdbcTemplate = new JdbcTemplate();

    @Test
    public void execute() {
        String sql = "CREATE TABLE `JDBC` (" +
                "`ID` INT AUTO_INCREMENT PRIMARY KEY ," +
                "`NAME` VARCHAR(50) NOT NULL) " +
                "ENGINE = INNODB DEFAULT CHARSET UTF8MB4";
        System.out.println(jdbcTemplate.execute(sql));
    }

    @Test
    public void insert() {
        String sql = "INSERT INTO `JDBC` (`NAME`) VALUES (?)";
        System.out.println(jdbcTemplate.update(sql, "zhaosi"));
    }

    @Test
    public void update() {
        String sql = "UPDATE `JDBC` SET `NAME` = ? WHERE `ID` = ?";
        System.out.println(jdbcTemplate.update(sql, "liuneng", 1));
    }

    @Test
    public void delete() {
        String sql = "DELETE FROM `JDBC` WHERE `ID` = ?";
        System.out.println(jdbcTemplate.update(sql, 1));
    }

    @Test
    public void batchInsertWithSameSql() {
        String sql = "INSERT INTO `JDBC` (`NAME`) VALUES (?)";
        Object[] param01 = {"zhaosi"};
        Object[] param02 = {"liuneng"};
        Object[] param03 = {"guangkun"};
        int[] result = jdbcTemplate.batchUpdate(sql, param01, param02, param03);
        System.out.println(Arrays.toString(result));
    }

    @Test
    public void batchUpdateWithSameSql() {
        String sql = "UPDATE `JDBC` SET `NAME` = ? WHERE `ID` = ?";
        Object[] param01 = {"zhaosi2", 3};
        Object[] param02 = {"liuneng2", 4};
        Object[] param03 = {"guangkun2", 5};
        int[] result = jdbcTemplate.batchUpdate(sql, param01, param02, param03);
        System.out.println(Arrays.toString(result));
    }

    @Test
    public void batchDeleteWithSameSql() {
        String sql = "DELETE FROM `JDBC` WHERE `ID` = ?";
        Object[] param01 = {3};
        Object[] param02 = {4};
        Object[] param03 = {5};
        int[] result = jdbcTemplate.batchUpdate(sql, param01, param02, param03);
        System.out.println(Arrays.toString(result));
    }

    @Test
    public void batchUpdateWithDifferentSql() {
        String insertSql = "INSERT INTO `JDBC` (`NAME`) VALUES ('FEIJI')";
        String updateSql = "UPDATE `JDBC` SET `NAME` = 'DAPAO' WHERE `NAME` = 'FEIJI'";
        String[] sqls = {insertSql, updateSql};
        int[] result = jdbcTemplate.batchUpdate(sqls);
        System.out.println(Arrays.toString(result));
    }

    @Test
    public void queryForList() {
        String sql = "SELECT * FROM EMP WHERE ENAME != ? AND SAL > ?";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, "SMITH", 1500);
        for (Map<String, Object> map : list) {
            System.out.println(map);
        }
    }

    @Test
    public void queryForMap() {
        String sql = "SELECT * FROM EMP WHERE EMPNO = ?";
        Map<String, Object> map = jdbcTemplate.queryForMap(sql, 7654);
        System.out.println(map);
    }

    @Test
    public void queryForInt() {
        String sql = "SELECT COUNT(`ID`) FROM JDBC WHERE ID > ?";
        System.out.println(jdbcTemplate.queryForInt(sql,8));
    }
}