java-08 jdbc

发布于:2024-10-12 ⋅ 阅读:(122) ⋅ 点赞:(0)

jdbc连接数据库是一种用于在Java应用程序中访问和操作数据库的技术。

如果你觉得我分享的内容或者我的努力对你有帮助,或者你只是想表达对我的支持和鼓励,请考虑给我点赞、评论、收藏。您的鼓励是我前进的动力,让我感到非常感激。

1 jdbc操作数据库的基本步骤

JDBC连接数据库的基本步骤如下:

  1. 加载数据库驱动:使用Class.forName()加载特定数据库的JDBC驱动。
  2. 创建数据库连接:使用DriverManager.getConnection()方法建立连接。
  3. 创建Statement对象:通过连接对象创建Statement对象来执行SQL语句。
  4. 执行SQL语句:使用Statement对象执行SQL查询、更新等操作。
  5. 处理结果:如果是查询操作,处理结果集。
  6. 关闭资源:关闭结果集、Statement和连接对象,释放资源。

以下是一个简单的示例代码:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
 
public class JdbcExample {
    public static void main(String[] args) {
        String jdbcUrl = "jdbc:mysql://localhost:3306/mydatabase";
        String username = "root";
        String password = "password";
 
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
 
        try {
            // 加载数据库驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            
            // 建立数据库连接
            conn = DriverManager.getConnection(jdbcUrl, username, password);
            
            // 创建Statement对象
            stmt = conn.createStatement();
            
            // 执行SQL查询
            String sql = "SELECT * FROM mytable";
            rs = stmt.executeQuery(sql);
            
            // 处理结果集
            while (rs.next()) {
                // 获取并处理数据
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
        }
    }
}

2 jdbc事务操作

在JDBC中控制事务通常涉及以下步骤:

  1. 关闭自动提交:调用 Connection 对象的 setAutoCommit(false) 方法,禁用自动提交,开启事务控制。
  2. 执行数据库操作:使用 Connection 对象进行数据库操作,如 executeUpdate 或 executeQuery。
  3. 如果操作成功,调用 commit() 方法提交事务。如果操作过程中出现异常,捕获异常并调用 rollback() 方法回滚事务。
  4. 操作完成后,关闭 Connection 对象。

下面是一个简单的例子:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
 
public class JDBCTransactionExample {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
 
        try {
            // 加载并Register JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
 
            // 建立连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "user", "password");
 
            // 关闭自动提交
            conn.setAutoCommit(false);
 
            // 创建Statement
            stmt = conn.createStatement();
 
            // 执行SQL更新
            String sql1 = "UPDATE mytable SET age = age + 1 WHERE id = 1";
            stmt.executeUpdate(sql1);
 
            // 可以添加更多的SQL操作
            // String sql2 = "INSERT INTO mytable (name, age) VALUES ('John', 25)";
            // stmt.executeUpdate(sql2);
 
            // 提交事务
            conn.commit();
            System.out.println("事务已提交");
 
        } catch (ClassNotFoundException | SQLException e) {
            try {
                // 出现异常时回滚事务
                if (conn != null) {
                    conn.rollback();
                    System.out.println("事务已回滚");
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            // 关闭资源
            try {
                if (stmt != null) stmt.close();
                if (conn != null) conn.close();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
}

3 jdbc使用案例1-数据巡检

3.1 业务介绍

  1. 巡检平台配置好了不同的数据源,及其需要巡检的表
  2. 定时执行巡检任务
  3. 获取当前点需要巡检的所有库表信息
  4. 按照库进行分组,连接库,巡检表【可以做成并行】

3.2 实现方案及代码

  1. 调用入口
	// 2 获取所有数据连接信息【包含需要巡检的表信息】
	List<PmiDatabaseConfBean> dbInfoList = dbTableSyncDao.getDbInfoList();
	if (CollectionUtils.isEmpty(dbInfoList)) {
	    LOGGER.warn("The database configuration list is empty.");
	} else {
	    for (PmiDatabaseConfBean dbInfo : dbInfoList) { // 这里可以做成并行
	        syncDBTableInfo(dbInfo);
	    }
	    LOGGER.info("syncAllDBTableInfo Finish");
	}
  1. 同步单个库的表信息
	/**
     * 同步单个库的表信息
     *
     * @param dbInfo 数据库信息
     * @return RespResult 结果
     */
    private RespResult syncDBTableInfo(PmiDatabaseConfBean dbInfo) {
        // 0 获取连接基本信息
        String dbType = dbInfo.getDbType();
        Optional<String> driverNameOptional = DriverTypeEnum.getDriveByDataType(dbType);
        String jdbcUrl = jdbcStrategyContext.getDatabaseUrl(dbInfo);
        LOGGER.info("syncDBTableInfo Start. jdbcUrl:{}", jdbcUrl);
        try {
            // 1 注册驱动,注册失败后,本库同步库表信息任务失败
            Class.forName(driverNameOptional.get());
            // 2 解密密码
            String passWord = KMSUtils.decryptSingle(dbInfo.getPassword());
            if (StringUtils.isEmpty(passWord)) {
                LOGGER.info("syncDBTableInfo Failure. KMS decryption failed. jdbcUrl:{}", jdbcUrl);
                return RespResult.resultFail(RespCodeEnum.EXP.getValue(), RespCodeEnum.EXP.getDesc());
            }
            // 3 获取连接,和Statement
            try (Connection connection = DriverManager.getConnection(jdbcUrl, dbInfo.getUser(), passWord);
                    Statement statement = connection.createStatement();
                    PreparedStatement preparedStatement = connection.prepareStatement(MYSQL_DB_TABLE_INFO_QUERY_SQL);) {
                statement.setQueryTimeout(dbTableInfoRefreshQueryOutTime);
                preparedStatement.setQueryTimeout(dbTableInfoRefreshQueryOutTime);
                // 4 查询数据
                ResultSet queryResult = getQueryResultSet(dbInfo, dbType, connection, statement, preparedStatement);
                // 5 封装数据
                ArrayList<DBTableInfo> dbTableInfoList = getToSaveDbTableInfoList(dbInfo, queryResult);
                // 6 入库
                saveDBTableInfo(dbTableInfoList);
                LOGGER.info("syncDBTableInfo Finish. jdbcUrl:{}", jdbcUrl);
                return RespResult.resultOK(RespCodeEnum.SUCCESS.getDesc());
            } catch (SQLException exp) {
                ExceptionUtils.printExceptionInfo(exp);
                LOGGER.error("syncDBTableInfo Failure. SQLException. jdbcUrl:{}", jdbcUrl);
            }
        } catch (DataAccessException exp) {
            ExceptionUtils.printExceptionInfo(exp);
            LOGGER.error("syncDBTableInfo Failure. SaveDataException. jdbcUrl:{}", jdbcUrl);
        } catch (ClassNotFoundException | NoSuchElementException exp) {
            ExceptionUtils.printExceptionInfo(exp);
            LOGGER.error("Failed to register the driver.. dbType:{}", dbType);
            LOGGER.error("syncDBTableInfo Failure. jdbcUrl:{}", jdbcUrl);
        }
        return RespResult.resultFail(RespCodeEnum.EXP.getValue(), RespCodeEnum.EXP.getDesc());
    }


    /**
     * 获取查询结果
     *
     * @param dbInfo 数据库信息
     * @param dbType 数据库类型
     * @param connection 连接对象
     * @param statement 执行的Statement
     * @param preparedStatement 执行的PreparedStatement
     * @return ResultSet
     * @throws SQLException
     */
    private ResultSet getQueryResultSet(PmiDatabaseConfBean dbInfo, String dbType, Connection connection,
            Statement statement, PreparedStatement preparedStatement) throws SQLException {
        ResultSet queryResult = null;
        if (MYSQL.equalsIgnoreCase(dbType)) {
            preparedStatement.setString(1, dbInfo.getDatabaseName());
            queryResult = preparedStatement.executeQuery();
        } else if (ORACLE.equalsIgnoreCase(dbType) || ORACLESTRINGACLE.equalsIgnoreCase(dbType)) {
            queryResult = statement.executeQuery(ORACLE_DB_TABLE_INFO_QUERY_SQL);
        } else if (POSTGRESQL.equalsIgnoreCase(dbType) || GAUSSDB.equalsIgnoreCase(dbType)) {
            queryResult = statement.executeQuery(
                    String.format(Locale.ROOT, POSTGRESQL_DB_TABLE_INFO_QUERY_SQL, dbInfo.getModel()));
        } else {
            LOGGER.warn("The database type is not supported.. dbType:{}", dbType);
        }
        return queryResult;
    }
  1. 数据库类型与驱动枚举类
public enum DriverTypeEnum {
    ORACLE("Oracle", "oracle.jdbc.driver.OracleDriver"),
    ORACLESTRING("Oracle-连接串", "oracle.jdbc.driver.OracleDriver"),
    MYSQL("MySQL", "com.mysql.cj.jdbc.Driver"),
    POSTGRESQL("PostgreSQL", "org.postgresql.Driver"),
    GAUSSDB("GaussDB", "org.postgresql.Driver");

    private String dataType;
    private String driveClassName;

    DriverTypeEnum(final String dataType, final String driveClassName) {
        this.dataType = dataType;
        this.driveClassName = driveClassName;
    }

    /**
     * <获取数据库类型>
     *
     * @return String 数据
     */
    public String getDataType() {
        return dataType;
    }

    /**
     * <获取驱动>
     *
     * @return String 数据
     */
    public String getDriveClassName() {
        return driveClassName;
    }

    /**
     * 通过类型获取驱动
     *
     * @param dataType 参数
     * @return 结果
     */
    public static Optional<String> getDriveByDataType(String dataType) {
        for (DriverTypeEnum value : DriverTypeEnum.values()) {
            if (value.getDataType().equalsIgnoreCase(dataType)) {
                return Optional.ofNullable(value.getDriveClassName());
            }
        }
        return Optional.empty();
    }
}

4 jdbc使用案例2-vim&pim解析

4.1 业务介绍

  1. vim-pim信息,有50个不同的模型(对应50个模型表),每个模型的解析字段都不同
  2. 上游传递zip包,zip包里不同的模型数据(.gzip文件【压缩后的json文件】),每个模型数据格式不同
  3. 需要将这些模型数据解析入库

4.2 实现方案及代码

  1. 配置每个模型的基本信息【用来创建表,及其解析数据】
[
  {
    "group": "VIM_PIM_V3",
    "objectName": "Manager",
    "aliasName": [],
    "vimPimAttributeDto": [
      {
        "name": "ManagerID",
        "dbType": "VARCHAR(64)",
        "dataType": "String"
      },
      {
        "name": "ManagerType",
        "dbType": "VARCHAR(64)",
        "dataType": "String"
      }....
  1. 项目启动后创建临时模型表
    public void creatTempTable() {
        log.info("creat ods vim and pim temp table start");
        for (VimPimModelDto vimPimModelDto : vimPimModelList) {
            // 删除表
            String dropTableSql = getDropTableSql(vimPimModelDto);
            vimPimRepository.dropTempTable(dropTableSql);

            // 创建表
            String creatTableSql = getCreatTableSql(vimPimModelDto);
            vimPimRepository.creatTempTable(creatTableSql);
        }
        log.info("creat ods vim and pim temp table finish");
    }
  1. 解析文件数据入库
    private void parseModelData(CollectionTaskDto task, File unGzFile) throws IOException {

        // 1 解析json数据
        String progressResultJson = FileUtils.readFileToString(FileUtils.getFile(unGzFile),
            EncodingDetectUtils.detectEncoding(unGzFile));
        JSONObject collectModelMap = JSON.parseObject(progressResultJson);

        // 2 json数据为Map对象,可能有多个资源对象,逐个处理
        Long creatTime = Date.from(Instant.now()).getTime();
        for (String collectModelName : collectModelMap.keySet()) {
            // 3 根据采集来的模型名称,找预置的模型数据
            VimPimModelDto baseModel = getBaseModelInfo(collectModelName);

            if (baseModel != null) {
                if (baseModel.isObject()) {
                    // 4.1 采集的模型数据是对象,按照对象来解析
                    JSONObject modelDataObject = collectModelMap.getJSONObject(collectModelName);
                    parseModelDataAndSave(task, baseModel, modelDataObject, creatTime, unGzFile.getName());
                } else {
                    // 4.2 采集的模型数据是列表格式,按照列表来解析
                    JSONArray modelDataArray = collectModelMap.getJSONArray(collectModelName);
                    parseModelDataListAndSave(task, baseModel, modelDataArray, creatTime, unGzFile.getName());
                }
            } else {
                // 5 采集来的对象,不是预置好模型对象
                log.warn("The file content is abnormal. The object does not exist. objectName:{} ", collectModelName);
            }
        }
    }

    private void parseModelDataAndSave(CollectionTaskDto task, VimPimModelDto baseModel, JSONObject modelDataObject,
        Long creatTime, String fileName) {
        try (
            // 2 获取连接,和Statement
            Connection connection = dataSource.getConnection();
            PreparedStatement ps = connection.prepareStatement(getInsertSql(baseModel))) {

            // 3 设置参数
            ps.setObject(1, task.getTaskId());
            ps.setObject(2, task.getTaskSn());
            ps.setObject(3, fileName);
            List<VimPimAttributeDto> vimPimAttributeDtoList = baseModel.getVimPimAttributeDto();
            for (int j = 0; j < vimPimAttributeDtoList.size(); j++) {
                ps.setObject(j + 4, getModelAttrValue(baseModel, vimPimAttributeDtoList.get(j), modelDataObject, 0));
            }
            ps.setObject(vimPimAttributeDtoList.size() + 4, creatTime);

            // 4 积攒sql
            ps.addBatch();

            // 5 批量执行
            ps.executeBatch();

        } catch (SQLException exp) {
            log.error("insert SQLException. objectName: {} ", baseModel.getObjectName());
            ExceptionUtils.printExceptionInfo(exp);
        }
    }

    private void parseModelDataListAndSave(CollectionTaskDto task, VimPimModelDto baseModel, JSONArray modelDataArray,
        Long creatTime, String fileName) {
        try (
            // 2 获取连接,和Statement
            Connection connection = dataSource.getConnection();
            PreparedStatement ps = connection.prepareStatement(getInsertSql(baseModel))) {
            for (List<Object> modelDataArrayList : Lists.partition(modelDataArray, 1000)) {
                JSONArray sonModelDataArray = JSONArray.parseArray(JSON.toJSONString(modelDataArrayList));

                // 3 设置参数
                for (int i = 0; i < sonModelDataArray.size(); i++) {
                    setParam(task, baseModel, creatTime, fileName, ps, sonModelDataArray, i);

                    // 4 积攒sql
                    ps.addBatch();
                }

                // 5 批量执行
                ps.executeBatch();
            }

        } catch (SQLException exp) {
            log.error("insert SQLException. objectName: {} ", baseModel.getObjectName());
            ExceptionUtils.printExceptionInfo(exp);
        }
    }

5 springboot项目里事务管理(除过注解方式,自行管理)

    // 多数据源时,可以指定@Resource(name = "xxxxx")
    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Autowired
    private TransactionDefinition transactionDefinition;

    /**
     * 数据入库
     *
     * @param dbTableInfoList 库表信息列表
     * @see [类、类#方法、类#成员]
     */
    private void saveDBTableInfo(ArrayList<DBTableInfo> dbTableInfoList) {
        // 开启事务进行入库操作
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            if (dbTableInfoList.size() > 0) {
                dbTableSyncDao.deleteData(dbTableInfoList.get(0));
                dbTableSyncDao.saveData(dbTableInfoList);
            }
            dataSourceTransactionManager.commit(transaction);
        } catch (DataAccessException exp) {
            LOGGER.warn("Failed to save data to the database");
            dataSourceTransactionManager.rollback(transaction);
        }
    }

网站公告

今日签到

点亮在社区的每一天
去签到