在了解HiKari之前,我们需要先了解关于数据访问的相关概念:
JDBC(Java Database Connectivity)是Java编程语言用于与数据库进行交互的标准API。它提供了一组类和接口,用于执行数据库操作,如连接到数据库、执行SQL语句、处理查询结果等。
JDBC允许开发人员使用Java代码与不同的关系型数据库进行通信,无论是MySQL、Oracle、SQL Server还是其他支持JDBC的数据库系统。
通过JDBC,开发人员可以使用标准的Java语法和面向对象的方式来执行数据库操作。它提供了一种独立于特定数据库的通用方式来访问和操作数据库,使得应用程序可以轻松地切换和兼容不同的数据库系统。
JDBC的核心组件包括DriverManager、Connection、Statement和ResultSet等。
DriverManager用于管理数据库驱动程序,Connection用于建立与数据库的连接,Statement用于执行SQL语句,ResultSet用于处理查询结果。
通过JDBC,开发人员可以使用Java语言编写数据库应用程序,执行各种数据库操作,如插入、更新、删除数据,以及查询和处理查询结果。这使得开发人员能够轻松地将数据库集成到他们的应用程序中,并与数据库进行交互。
数据源(Data Source)是指数据库或其他数据存储系统的物理或逻辑位置,它提供了访问和操作数据的接口。数据源可以是关系型数据库、文件系统、内存数据库、消息队列等。
在软件开发中,数据源通常用于连接和管理数据存储系统,并提供数据的读取、写入和查询功能。它是应用程序与数据存储系统之间的中间层,隐藏了底层数据存储系统的细节,使得应用程序可以以统一的方式访问不同类型的数据。
使用数据源可以提供以下好处:
抽象化:数据源提供了一个抽象层,使得应用程序可以以统一的方式访问各种数据存储系统,无需关心底层细节。
连接管理:数据源负责管理与数据存储系统之间的连接,包括连接的创建、释放和连接池管理,提供了高效的连接管理机制。
事务管理:数据源可以支持事务管理,确保数据操作的一致性和完整性
查询优化:数据源可以对查询进行优化,提供更高效的数据访问和查询性能。
在Java中,常见的数据源包括JDBC数据源、连接池数据源(如HikariCP、Apache Commons DBCP)、JNDI数据源等。这些数据源可以通过配置文件或代码来配置和使用,以便应用程序可以连接和操作数据库。
HikariCP是一个高性能的JDBC(Java数据库连接)连接池库,用于管理数据库连接的分配和释放。它旨在提供快速、轻量级和可伸缩的数据库连接池,特别适用于Java应用程序,如Spring Boot应用程序。
HikariCP的主要特点包括:
HikariCP在Java生态系统中得到广泛使用,特别是在Spring Boot应用程序中,因为它与Spring Boot集成得很好,并且能够提供可靠的数据库连接池管理。通过使用HikariCP,你可以更好地管理和优化数据库连接,从而提高应用程序的性能和可伸缩性。
在Spring Boot自动化配置中,对于数据源的配置可以分为两类:
通用配置:以spring.datasource.*
的形式存在,主要是对一些即使使用不同数据源也都需要配置的一些常规内容。比如:数据库链接地址、用户名、密码等。这里就不做过多说明了,通常就这些配置:
# MySQL
#spring.datasource.url=jdbc:mysql://localhost:3306/test
#spring.datasource.username=root
#spring.datasource.password=
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# Oracle
spring.datasource.url=jdbc:oracle:thin:@localhost:1521/orcl
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
数据源连接池配置:以spring.datasource.<数据源名称>.*
的形式存在,比如:Hikari的配置参数就是spring.datasource.hikari.*
形式。下面这个是我们最常用的几个配置项及对应说明:
# 最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size
spring.datasource.hikari.minimum-idle=10
# 最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值
spring.datasource.hikari.maximum-pool-size=20
# 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。
spring.datasource.hikari.idle-timeout=500000
# 连接最大存活时间.不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
spring.datasource.hikari.max-lifetime=540000
# 连接超时时间:毫秒,小于250毫秒,否则被重置为默认值30秒
spring.datasource.hikari.connection-timeout=60000
# 用于测试连接是否可用的查询语句
spring.datasource.hikari.connection-test-query=SELECT 1 from useradd
更多相关配置请参照
spring.datasource.hikari.connectionTimeout
: 连接超时时间(毫秒)。连接池在尝试获取连接时等待的最长时间。
spring.datasource.hikari.maximumPoolSize
: 连接池的最大连接数。连接池将尝试维护的最大活动连接数。
spring.datasource.hikari.minimumIdle
: 连接池的最小空闲连接数。连接池会尝试保持的最小空闲连接数。
spring.datasource.hikari.idleTimeout
: 连接的最大空闲时间(毫秒)。超过此时间的空闲连接将被关闭并从池中删除。
spring.datasource.hikari.maxLifetime
: 连接的最大生存时间(毫秒)。连接在连接池中的最长寿命。一旦达到此时间,连接将被关闭并从池中删除。
spring.datasource.hikari.connectionTestQuery
: 用于测试连接的SQL查询语句。当从连接池中获取连接时,连接池将执行此查询以确保连接的有效性。
spring.datasource.hikari.poolName
: 连接池的名称。用于标识连接池的名称。
spring.datasource.hikari.dataSourceClassName
: 数据源的完整类名。用于指定JDBC驱动程序的类。
spring.datasource.hikari.username
: 数据库用户名。
spring.datasource.hikari.password
: 数据库密码。
spring.datasource.hikari.autoCommit
: 是否自动提交事务,默认为true。
spring.datasource.hikari.transactionIsolation
: 数据库连接的事务隔离级别。可以设置为 “DEFAULT”、“TRANSACTION_READ_UNCOMMITTED”、“TRANSACTION_READ_COMMITTED”、“TRANSACTION_REPEATABLE_READ”、“TRANSACTION_SERIALIZABLE” 等值。
spring.datasource.hikari.initializationFailTimeout
: 连接池初始化失败时的超时时间(毫秒)。如果连接池初始化失败,将等待此时间。
spring.datasource.hikari.isolateInternalQueries
: 是否隔离内部查询。默认为false。
spring.datasource.hikari.allowPoolSuspension
: 是否允许连接池暂停。默认为false。
这些配置项可以在application.properties或application.yml文件中进行设置,根据你的应用程序的需求,可以调整这些配置项以获得最佳性能和可靠性。
给出我在测试阶段的相关代码:
第一步在Spring Boot中引入相关依赖:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>com.oracle.ojdbcgroupId>
<artifactId>ojdbc8artifactId>
<version>19.3.0.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
第二步,在application.properties配置相关依赖:
#spring.datasource.url=jdbc:mysql://localhost:3306/test
#spring.datasource.username=root
#spring.datasource.password=
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521/orcl
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
# 最小空闲连接,默认值10,小于0或大于maximum-pool-size,都会重置为maximum-pool-size
spring.datasource.hikari.minimum-idle=10
# 最大连接数,小于等于0会被重置为默认值10;大于零小于1会被重置为minimum-idle的值
spring.datasource.hikari.maximum-pool-size=20
# 空闲连接超时时间,默认值600000(10分钟),大于等于max-lifetime且max-lifetime>0,会被重置为0;不等于0且小于10秒,会被重置为10秒。
spring.datasource.hikari.idle-timeout=500000
# 连接最大存活时间.不等于0且小于30秒,会被重置为默认值30分钟.设置应该比mysql设置的超时时间短
spring.datasource.hikari.max-lifetime=540000
# 连接超时时间:毫秒,小于250毫秒,否则被重置为默认值30秒
spring.datasource.hikari.connection-timeout=60000
# 用于测试连接是否可用的查询语句
spring.datasource.hikari.connection-test-query=SELECT 1 from useradd
第三步,设计数据库:
PS: 我采用的是Oracle 数据库,语法与MySQL有所差别
CREATE TABLE useradd (
name varchar2 (100) NOT NULL,
age integer NOT NULL
)
第四步,创建对应的实体类对象:
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return name.equals(user.name) && age.equals(user.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
第五步,设计相关接口信息:
public interface UserService {
/**
* 新增一个用户
*
* @param name
* @param age
*/
int create(String name, Integer age);
/**
* 根据name查询用户
*
* @param name
* @return
*/
List<User> getByName(String name);
/**
* 根据name删除用户
*
* @param name
*/
int deleteByName(String name);
/**
* 获取用户总量
*/
int getAllUsers();
/**
* 删除所有用户
*/
int deleteAllUsers();
}
第六步,设计接口实现类:
@Service
public class UserServiceImpl implements UserService {
private JdbcTemplate jdbcTemplate;
UserServiceImpl(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public int create(String name, Integer age) {
return jdbcTemplate.update("insert into USERADD(NAME, AGE) values(?, ?)", name, age);
}
@Override
public List<User> getByName(String name) {
List<User> users = jdbcTemplate.query("select NAME, AGE from USERADD where NAME = ?", (resultSet, i) -> {
User user = new User();
user.setName(resultSet.getString("NAME"));
user.setAge(resultSet.getInt("AGE"));
return user;
}, name);
return users;
}
@Override
public int deleteByName(String name) {
return jdbcTemplate.update("delete from USERADD where NAME = ?", name);
}
@Override
public int getAllUsers() {
return jdbcTemplate.queryForObject("select count(1) from USERADD", Integer.class);
}
@Override
public int deleteAllUsers() {
return jdbcTemplate.update("delete from USERADD");
}
}
第七步,我们通过设计单元测试进行测试:
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter32ApplicationTests {
@Autowired
private UserService userSerivce;
@Autowired
private DataSource dataSource;
@Before
public void setUp() {
// 准备,清空user表
userSerivce.deleteAllUsers();
}
@Test
public void test() throws Exception {
// 插入5个用户
userSerivce.create("Tom", 10);
userSerivce.create("Mike", 11);
userSerivce.create("Didispace", 30);
userSerivce.create("Oscar", 21);
userSerivce.create("Linda", 17);
// 查询名为Oscar的用户,判断年龄是否匹配
List<User> userList = userSerivce.getByName("Oscar");
Assert.assertEquals(21, userList.get(0).getAge().intValue());
// 查数据库,应该有5个用户
Assert.assertEquals(5, userSerivce.getAllUsers());
// 删除两个用户
userSerivce.deleteByName("Tom");
userSerivce.deleteByName("Mike");
// 查数据库,应该有5个用户
Assert.assertEquals(3, userSerivce.getAllUsers());
}
}