在Java应用开发中,数据查询是与数据库交互的核心操作之一,无论是简单的单表查询,还是复杂的多表关联,掌握Java查询语句的写法都是开发者必备的技能,本文将从基础到进阶,分模块介绍Java中不同场景下的查询语句实现方式,帮助开发者构建清晰、高效的数据访问逻辑。

基础查询:JDBC原生实现
JDBC(Java Database Connectivity)是Java操作数据库的底层API,通过原生JDBC编写查询语句,能直观理解数据库交互的本质,其核心步骤包括:加载驱动、建立连接、创建语句对象、执行查询、处理结果集、关闭资源。
以查询用户表为例,关键代码如下:
String sql = "SELECT id, username, age FROM users WHERE age > ?";
try (Connection conn = DriverManager.getConnection(url, username, password);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, 18); // 设置参数,防止SQL注入
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("username");
int age = rs.getInt("age");
System.out.println(id + ": " + name + ", " + age);
}
} catch (SQLException e) {
e.printStackTrace();
}
关键点:使用PreparedStatement而非Statement,通过参数化查询(占位符)避免SQL注入;try-with-resources确保连接、语句等资源自动关闭,防止泄漏。
ORM框架下的查询:MyBatis实践
MyBatis是主流的半自动ORM框架,将SQL语句与Java代码分离,通过XML或注解配置,简化查询操作。
XML映射方式
在Mapper XML文件中定义SQL语句:
<select id="selectUsersByAge" resultType="com.example.User">
SELECT id, username, age FROM users
<where>
<if test="age != null">age > #{age}</if>
</where>
</select>
对应Mapper接口:
public interface UserMapper {
List<User> selectUsersByAge(Integer age);
}
通过#{age}传入参数,MyBatis自动预处理,防止SQL注入;<where>标签动态拼接条件,避免SQL语法错误。

注解方式
对于简单查询,可直接在Mapper接口方法上使用注解:
@Select("SELECT id, username, age FROM users WHERE status = #{status}")
List<User> selectActiveUsers(String status);
注解方式简洁,适合SQL逻辑简单的场景,复杂查询仍推荐XML配置。
JPA简化查询:Spring Data JPA
Spring Data JPA基于JPA规范,通过Repository接口定义方法名,自动生成查询语句,大幅减少样板代码。
方法名解析
继承JpaRepository接口,按约定定义方法名:
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByUsernameAndAgeGreaterThan(String username, int age);
User findByEmail(String email);
}
Spring Data JPA会自动解析方法名,生成对应的JPQL(Java Persistence Query Language)语句,如findByUsernameAndAgeGreaterThan会解析为SELECT u FROM User u WHERE u.username = ?1 AND u.age > ?2。
@Query注解自定义SQL
当方法名解析无法满足需求时,可通过@Query注解手动编写SQL或JPQL:
@Query("SELECT u FROM User u WHERE u.age BETWEEN :minAge AND :maxAge")
List<User> findUsersByAgeRange(@Param("minAge") int minAge, @Param("maxAge") int maxAge);
@Query(value = "SELECT * FROM users WHERE create_time > ?1", nativeQuery = true)
List<User> findUsersCreatedAfter(Date date);
nativeQuery = true表示使用原生SQL而非JPQL,参数可通过@Param注解命名绑定,提高可读性。

动态查询与高级特性
实际业务中,查询条件常动态变化,需灵活处理动态SQL。
MyBatis动态SQL
MyBatis提供<if>、<where>、<foreach>等标签实现动态拼接:
<select id="selectUsersByCondition" resultType="User">
SELECT * FROM users
<where>
<if test="username != null">AND username LIKE CONCAT('%', #{username}, '%')</if>
<if test="status != null">AND status = #{status}</if>
<if test="roleIds != null">
AND id IN
<foreach collection="roleIds" item="roleId" open="(" separator="," close=")">
#{roleId}
</foreach>
</if>
</where>
</select>
<foreach>用于处理集合参数,如IN查询;<where>自动去除多余的AND/OR。
JPA动态查询(Specification)
JPA通过Specification接口实现动态查询,适用于复杂条件组合:
public List<User> findUsersWithDynamicSpec(UserQuery query) {
Specification<User> spec = (root, criteriaQuery, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (query.getUsername() != null) {
predicates.add(cb.like(root.get("username"), "%" + query.getUsername() + "%"));
}
if (query.getMinAge() != null) {
predicates.add(cb.ge(root.get("age"), query.getMinAge()));
}
return cb.and(predicates.toArray(new Predicate[0]));
};
return userRepository.findAll(spec);
}
Specification通过Criteria API构建查询条件,灵活度高,适合动态查询场景。
查询性能优化与注意事项
- 避免N+1查询问题:关联查询时,使用JOIN一次性获取数据,而非先查主表再循环查关联表(如JPA的
@EntityGraph,MyBatis的<collection>标签)。 - 只查询必要字段:避免
SELECT *,明确指定列名,减少数据传输量。 - 合理使用索引:确保查询条件字段有索引,对大表查询进行分页(如JPA的
Pageable,MyBatis的PageHelper)。 - 缓存策略:对频繁查询且不常变的数据,使用二级缓存(如MyBatis的
<cache>,Redis缓存)。
从JDBC到ORM框架,Java查询语句的写法不断演进,核心始终是“安全、高效、可维护”,开发者需根据业务场景选择合适的技术:简单查询用JDBC或MyBatis注解,复杂业务用MyBatis XML或Spring Data JPA,同时注重性能优化和代码规范,才能构建稳定可靠的数据访问层。



















