浅析`Java`数据库连接:从`Jdbc`到`Datasource`基于`springboot`搭建访问数据库的`web`项目
使用`springboot`搭建一个web项目集成数据库相关依赖
添加druid依赖管理添加相关依赖 编码实现数据库访问功能
数据库初始化注入自定义druid数据源编码持久层对象及数据访问层
浅析Java数据库连接:从Jdbc到Datasource基于springboot搭建访问数据库的web项目在Java项目中,基本都会和数据库打交道,那一个需要访问数据库的web项目,我们一般是怎么搭建的呢?在应用运行过程中,我们的Java应用是如何和数据库通讯的呢?
那我们带着这些一点问题,来从搭建一个数据库的web项目开始,来看一看Java和数据库交互的主要流程吧。
本文语雀链接:https://www.yuque.com/theskyzero/qdl2y7/qbqai8
项目仓库访问地址:https://gitee.com/theskyone/new-bird.git ,分支feature/jdbc
首先,介绍下这个demo背景,我们准备用springboot快速搭建一个web项目,在这个web项目中将用到数据库。
那么我们Java程序要访问一个数据库,需要准备哪些东西呢?
- 数据库选型:oracle、mysql等等…数据库连接驱动数据库连接池:druid、hikari、tomcat等等…数据映射/orm:spring-jdbc、mybatis、jpa等。
我们这里为示例的需要,选型为:
- 数据库:h2数据库,支持内存、文件数据库类型,支持SQL语言。数据库连接驱动:h2的数据库驱动数据库连接池:druid连接池。springboot2默认使用性能更好的hikari,我们使用久经考验的druid。orm:使用spring-jdbc。这里我们主要探讨Java和数据库的交互过程,不拘泥于如mybatis在数据映射上的抽象封装。
示例开发环境:IDEA+Maven+Git。示例程序:feature/jdbc
使用springboot搭建一个web项目超级简单,我们只要做两件事情:
- 依赖spring-boot-starter-web编写注解@SpringBootApplication的启动类
这里我们创建的是多module项目,一些关键的配置如下:
org.springframework.boot spring-boot-starter-parent 2.6.4 pom com.gitee.theskyone new-bird 1.0-SNAPSHOT bird-web
new-bird com.gitee.theskyone 1.0-SNAPSHOT bird-web org.springframework.boot spring-boot-starter-web
// SpringBoot启动类
package com.gitee.theskyone.bird;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class WebApplication {
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
至此,我们可以直接运行WebApplication.main方法,启动一个web项目。
集成数据库相关依赖 以上我们选型为h2+druid+spring-jdbc,那我们先添加相关的依赖。
h2相关的依赖定义默认spring-boot-dependencies已经提供,我们这里使用druid-spring-boot-starter来提供druid和springboot的整合。
我们在parent的pom.xml来管理项目的所有依赖定义。
添加相关依赖spring-boot-starter-parent org.springframework.boot 2.6.4 bird-web 1.2.8 com.alibaba druid-spring-boot-starter ${druid-boot.version}
在web项目中添加数据库、数据库驱动、数据库连接池、spring-jdbc依赖。
new-bird com.gitee.theskyone 1.0-SNAPSHOT bird-web org.springframework.boot spring-boot-starter-web com.h2database h2 com.alibaba druid-spring-boot-starter org.springframework.boot spring-boot-starter-jdbc
在spring-boot-starter-jdbc中,spring默认为我们提供了HikariCP数据源。之后,我们会手动注入一个DruidDataSource到Spring容器内。
编码实现数据库访问功能 数据库初始化我们借助SqlInitializationAutoConfiguration来完成数据库初始化工作。并仍使用DataSourceProperties来提供数据源的配置。
application.yml核心配置信息如下:
# h2 内存数据源配置
spring:
datasource:
# 内存数据库
url: jdbc:h2:mem:test
username: test
password: test
type: com.alibaba.druid.pool.DruidDataSource
sql:
init:
schema-locations: classpath*:/sql/ddl.sql
# /sql/ddl.sql
create table simple
(
id bigint(20) auto_increment primary key comment '主键',
name varchar(30) not null comment '名称',
description varchar(255) comment '描述',
create_time timestamp default current_timestamp() comment '创建时间',
update_time timestamp default current_timestamp() on update current_timestamp() comment '更新时间'
);
注入自定义druid数据源
这里我们手动注入DataSource,会替换DruidDataSourceAutoConfigure默认注入的DruidDataSource。
package com.gitee.theskyone.bird.jdbc.h2.ds;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.util.JdbcConstants;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;
import javax.sql.DataSource;
@Configuration
@Profile("mem")
public class DruidDatasourceConfiguration {
@Bean
@Primary
DataSource druidDataSource(DataSourceProperties dataSourceProperties) {
DruidDataSource druidDataSource = new DruidDataSource();
// 数据库连接必须参数
druidDataSource.setUrl(dataSourceProperties.determineUrl());
druidDataSource.setUsername(dataSourceProperties.determineUsername());
druidDataSource.setPassword(dataSourceProperties.determinePassword());
druidDataSource.setDriverClassName(JdbcConstants.H2_DRIVER); // 可选,druid可以通过url解析猜测
// 数据源管理参数
druidDataSource.setMinIdle(0);
druidDataSource.setMaxActive(8);
druidDataSource.setName("ds01");
return druidDataSource;
}
}
这里要注意的一点是,仓库上的代码这里使用@Profile("mem"),仅当激活application-mem.yml时配置类生效。当前默认激活使用的是application-druid.yml,使用的是druid-spring-boot-starter的自动配置。
编码持久层对象及数据访问层// SimplePO.java -> 持久层对象
package com.gitee.theskyone.bird.jdbc.h2.po;
import lombok.Data;
import java.time.Instant;
@Data
public class SimplePO {
Long id;
String name;
String description;
Instant createTime;
Instant updateTime;
}
// SimpleJdbcTemplateDao.java -> 使用JdbcTemplate实现的数据访问层
package com.gitee.theskyone.bird.jdbc.h2.dao;
import com.gitee.theskyone.bird.jdbc.h2.po.SimplePO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class SimpleJdbcTemplateDao {
@Autowired
JdbcTemplate jdbcTemplate;
public void insert(SimplePO po) {
String insertSql = "insert into simple(name,description) values(?,?)";
jdbcTemplate.update(insertSql, po.getName(), po.getDescription());
}
public List selectAll() {
String selectAll = "select * from simple";
return jdbcTemplate.query(selectAll, new BeanPropertyRowMapper(SimplePO.class));
}
}
JdbcTemplate还是比较原生的用法,直接通过DataSource获取数据库连接,并执行SQL语句。点开JdbcTemplate的实现,我们可以看到熟悉的Connection、PreparedStatement、ResultSet等等。
那么到这里,一般我们Java应用和数据库如何通过Jdbc通讯的过程就出来了,总结一下:
- 通过DataSource获取和数据库的连接Connection通过Connection向数据库请求执行Statement,返回响应。
当然,这里的Connection是如何建立的呢?以上我们并未提及到,大家也可以跟踪下DataSource.getConnection()的实现,其实最终都是通过连接驱动Driver.connect()建立产生。



