在Java应用程序开发中,与数据库进行交互是核心功能之一,无论是企业级应用还是移动端后端服务,几乎都离不开数据的持久化存储与读取,Java提供了多种方式调用数据库,从传统的JDBC到现代的ORM框架,每种方式都有其适用场景和优缺点,本文将系统介绍Java调用数据库的主流方法,涵盖技术原理、实践步骤及最佳实践,帮助开发者根据项目需求选择合适的方案。

JDBC:Java数据库连接的基础
JDBC(Java Database Connectivity)是Java访问数据库的标准API,它为开发者提供了一套统一的接口,使得Java程序能够与各种关系型数据库(如MySQL、Oracle、PostgreSQL等)进行交互,JDBC的核心思想是通过驱动程序(Driver)建立Java应用程序与数据库之间的连接,进而执行SQL语句并处理结果。
JDBC核心组件与工作流程
JDBC的主要组件包括:
- DriverManager:管理数据库驱动程序,负责建立与数据库的连接。
- Connection:代表与数据库的连接对象,用于创建Statement或PreparedStatement。
- Statement/PreparedStatement:用于执行SQL语句的工具,PreparedStatement支持参数化查询,能有效防止SQL注入。
- ResultSet:查询结果集,封装了数据库返回的数据。
典型的工作流程为:加载驱动 → 获取连接 → 创建执行语句 → 执行SQL → 处理结果 → 关闭资源。
实践步骤示例
以MySQL数据库为例,以下是使用JDBC查询数据的完整代码示例:
// 1. 加载驱动(MySQL 8.0+驱动类名)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 获取连接(URL格式:jdbc:mysql://主机:端口/数据库名?参数)
String url = "jdbc:mysql://localhost:3306/test_db?useSSL=false&serverTimezone=UTC";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
// 3. 创建PreparedStatement(防止SQL注入)
String sql = "SELECT id, name, age FROM users WHERE age > ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 18); // 设置参数
// 4. 执行查询并处理结果
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
System.out.println("ID: " + id + ", Name: " + name + ", Age: " + age);
}
// 5. 关闭资源(先开后闭原则)
rs.close();
pstmt.close();
conn.close();
注意事项
- 资源释放:必须确保Connection、Statement、ResultSet等资源在使用后关闭,通常通过try-catch-finally或try-with-resources(Java 7+)实现。
- SQL注入防护:优先使用PreparedStatement,避免直接拼接SQL字符串。
- 连接管理:频繁创建和关闭连接会影响性能,实际开发中需使用连接池(如HikariCP、Druid)。
连接池:优化数据库连接管理
直接使用JDBC时,每次操作都需要创建和销毁连接,这在高并发场景下会导致性能瓶颈,连接池技术通过预先维护一组数据库连接,供应用程序复用,显著提升系统性能,主流连接池包括HikariCP、Druid、C3P0等,其中HikariCP以其高性能和稳定性被广泛使用(如Spring Boot默认集成)。
连接池配置示例(HikariCP)
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test_db");
config.setUsername("root");
config.setPassword("123456");
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setMaximumPoolSize(10); // 最大连接数
config.setMinimumIdle(5); // 最小空闲连接
config.setConnectionTimeout(30000); // 连接超时时间(毫秒)
HikariDataSource dataSource = new HikariDataSource(config);
Connection conn = dataSource.getConnection();
// 使用后无需手动关闭,连接池会自动回收
ORM框架:简化数据库操作
ORM(Object-Relational Mapping,对象关系映射)框架通过将数据库表映射为Java对象,使开发者可以使用面向对象的方式操作数据库,而无需编写复杂的SQL语句,主流ORM框架包括Hibernate、MyBatis、JPA等。
Hibernate:全自动ORM框架
Hibernate是Java领域最成熟的ORM框架之一,它实现了JPA(Java Persistence API)规范,支持自动生成SQL、缓存、事务管理等功能,开发者只需定义实体类和映射关系,Hibernate即可完成数据库操作。

实体类示例(User.java):
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "name")
private String name;
@Column(name = "age")
private int age;
// getter/setter方法
}
使用Hibernate查询数据:
// 1. 获取SessionFactory(全局唯一,通常在应用启动时初始化)
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
// 2. 打开Session(相当于JDBC的Connection)
Session session = sessionFactory.openSession();
// 3. 执行HQL(Hibernate Query Language,类似SQL,但面向对象)
String hql = "FROM User WHERE age > :minAge";
Query<User> query = session.createQuery(hql, User.class);
query.setParameter("minAge", 18);
// 4. 获取结果
List<User> users = query.list();
for (User user : users) {
System.out.println("Name: " + user.getName() + ", Age: " + user.getAge());
}
// 5. 关闭资源
session.close();
sessionFactory.close();
MyBatis:半自动ORM框架
MyBatis相比Hibernate更灵活,它允许开发者手动编写SQL语句,同时提供了结果映射、动态SQL等功能,适用于复杂查询场景,MyBatis的核心是Mapper接口和XML配置文件(或注解)。
Mapper接口示例:
public interface UserMapper {
@Select("SELECT * FROM users WHERE age > #{minAge}")
List<User> findUsersByAge(@Param("minAge") int minAge);
}
使用MyBatis查询数据:
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.findUsersByAge(18);
users.forEach(user -> System.out.println("Name: " + user.getName()));
}
Spring Data JPA:进一步简化数据访问
在Spring生态中,Spring Data JPA通过规范化的接口定义,进一步简化了数据库操作,开发者只需定义继承Repository或CrudRepository的接口,Spring Data JPA会自动实现基本的CRUD(增删改查)方法,甚至支持自定义查询方法(通过方法名自动生成SQL)。
示例代码:

// 1. 定义实体类(与Hibernate示例相同)
@Entity
public class User { ... }
// 2. 定义Repository接口
public interface UserRepository extends JpaRepository<User, Integer> {
// 自定义查询方法:根据年龄查询用户
List<User> findByAgeGreaterThan(int age);
}
// 3. 在Service中使用
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> getAdultUsers() {
return userRepository.findByAgeGreaterThan(18);
}
}
Spring Data JPA底层默认使用Hibernate作为实现,但开发者可以轻松切换其他JPA提供商,同时与Spring的事务管理、AOP等功能无缝集成。
事务管理:确保数据一致性
在数据库操作中,事务(Transaction)是保证数据一致性的关键,Java事务管理分为编程式事务(如使用TransactionTemplate)和声明式事务(通过注解@Transactional),声明式事务因其简洁性成为主流,尤其在Spring框架中。
示例(Spring声明式事务):
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
public void transferMoney(int fromUserId, int toUserId, double amount) {
// 扣款操作
User fromUser = userRepository.findById(fromUserId).orElseThrow();
fromUser.setBalance(fromUser.getBalance() - amount);
userRepository.save(fromUser);
// 模拟异常
if (amount < 0) {
throw new RuntimeException("金额不能为负");
}
// 加款操作
User toUser = userRepository.findById(toUserId).orElseThrow();
toUser.setBalance(toUser.getBalance() + amount);
userRepository.save(toUser);
}
}
上述方法中,@Transactional注解确保了transferMoney方法内的所有操作要么全部成功,要么全部回滚,保证了数据的一致性。
总结与选择建议
Java调用数据库的技术方案多样,开发者需根据项目需求选择:
- JDBC:适合简单场景或对性能要求极高的底层操作,但开发效率较低。
- 连接池:所有Java应用的基础,HikariCP是当前的首选。
- Hibernate:适合快速开发,希望完全屏蔽SQL的场景,但学习成本较高,灵活性较低。
- MyBatis:适合复杂查询或需要精细控制SQL的场景,在金融、电商等领域广泛应用。
- Spring Data JPA:基于Spring生态,适合中小型项目,能极大提升开发效率。
无论选择哪种技术,都需关注SQL注入防护、连接池优化、事务管理等核心问题,以确保系统的安全性和稳定性。