jdbc连接数据库是一种用于在Java应用程序中访问和操作数据库的技术。
如果你觉得我分享的内容或者我的努力对你有帮助,或者你只是想表达对我的支持和鼓励,请考虑给我点赞、评论、收藏。您的鼓励是我前进的动力,让我感到非常感激。
文章目录
1 jdbc操作数据库的基本步骤
JDBC连接数据库的基本步骤如下:
- 加载数据库驱动:使用Class.forName()加载特定数据库的JDBC驱动。
- 创建数据库连接:使用DriverManager.getConnection()方法建立连接。
- 创建Statement对象:通过连接对象创建Statement对象来执行SQL语句。
- 执行SQL语句:使用Statement对象执行SQL查询、更新等操作。
- 处理结果:如果是查询操作,处理结果集。
- 关闭资源:关闭结果集、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中控制事务通常涉及以下步骤:
- 关闭自动提交:调用 Connection 对象的 setAutoCommit(false) 方法,禁用自动提交,开启事务控制。
- 执行数据库操作:使用 Connection 对象进行数据库操作,如 executeUpdate 或 executeQuery。
- 如果操作成功,调用 commit() 方法提交事务。如果操作过程中出现异常,捕获异常并调用 rollback() 方法回滚事务。
- 操作完成后,关闭 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 业务介绍
- 巡检平台配置好了不同的数据源,及其需要巡检的表
- 定时执行巡检任务
- 获取当前点需要巡检的所有库表信息
- 按照库进行分组,连接库,巡检表【可以做成并行】
3.2 实现方案及代码
- 调用入口
// 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");
}
- 同步单个库的表信息
/**
* 同步单个库的表信息
*
* @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;
}
- 数据库类型与驱动枚举类
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 业务介绍
- vim-pim信息,有50个不同的模型(对应50个模型表),每个模型的解析字段都不同
- 上游传递zip包,zip包里不同的模型数据(.gzip文件【压缩后的json文件】),每个模型数据格式不同
- 需要将这些模型数据解析入库
4.2 实现方案及代码
- 配置每个模型的基本信息【用来创建表,及其解析数据】
[
{
"group": "VIM_PIM_V3",
"objectName": "Manager",
"aliasName": [],
"vimPimAttributeDto": [
{
"name": "ManagerID",
"dbType": "VARCHAR(64)",
"dataType": "String"
},
{
"name": "ManagerType",
"dbType": "VARCHAR(64)",
"dataType": "String"
}....
- 项目启动后创建临时模型表
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");
}
- 解析文件数据入库
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);
}
}