mybatis条件查询Integer条件查询写法问题记录

本文探讨了在MyBatis中使用if标签进行Integer类型条件判断时出现的问题,当orderStatus值为0时,由于OGNL表达式的解析方式,导致条件判断失败。文章提供了正确的写法,并解释了如何避免此类问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.问题写法

        <if test="orderStatus != null and orderStatus != '' ">
            and fpr.status=#{orderStatus}
        </if>



如图在orderStatus != ’ ’ 中,当orderStatus 值为0时,sql语句未通过条件判断,这是因为mybatis在预编译sql时,使用OGNL表达式来解析if标签,对于Integer类型属性,在判断不等于 ’ ’ 时,例如orderStatus != ‘’,OGNL会返回’'的长度,源码:(s.length() == 0) ? 0.0 : Double.parseDouble( s ),因此表达式orderStatus != ''被当做age != 0来判断,所以当orderStatus 为0时,if条件判断不通过。

2.正确写法

        <if test="orderStatus != null and orderStatus != '' or orderStatus==0">
            and fpr.status=#{orderStatus}
        </if>

加入判断or orderStatus==0;

参考:https://blog.youkuaiyun.com/qq_30038111/article/details/82665763
<think>我们正在讨论的是Java中如何编写带有条件的SQL查询语句。根据引用内容,我们可以总结出几种常见的处理方式,特别是处理多条件查询时如何动态构建SQL语句。 引用[1]和[2]提到,当存在多个条件时,直接拼接SQL语句可能会导致语法错误(比如出现多个WHERE关键字)。引用[2]介绍了一种常见的技巧:使用`WHERE 1=1`作为条件开头,这样后续每个条件都可以用`AND`连接,避免判断第一个条件是否需要WHERE关键字。 引用[3]和[4]展示了在Java中拼接SQL字符串的示例,但这种方式容易引发SQL注入攻击,因此不推荐。 现代Java开发中,我们通常使用预编译语句(PreparedStatement)来防止SQL注入,同时结合一些技巧来动态构建SQL。 下面我将介绍几种在Java中编写条件查询SQL的方法: 1. **使用PreparedStatement动态拼接SQL(基础方法)** 这种方法适用于条件数量固定的情况,但条件可能为空的场景。 2. **使用StringBuilder动态构建SQL(需要谨慎防止SQL注入)** 如果条件数量不固定,我们可以动态构建SQL字符串,但参数部分仍然使用占位符`?`,然后通过PreparedStatement设置参数。 3. **使用第三方库(如MyBatis, Spring Data JPA等)** 这些库提供了更优雅的动态SQL构建方式。 下面我们逐一介绍: ### 方法1:使用PreparedStatement固定条件 假设我们有两个条件:name和address,它们都可能为空。 ```java String baseSql = "SELECT * FROM user WHERE 1=1"; List<String> conditions = new ArrayList<>(); List<Object> parameters = new ArrayList<>(); if (name != null && !name.isEmpty()) { conditions.add("name LIKE ?"); parameters.add("%" + name + "%"); } if (address != null && !address.isEmpty()) { conditions.add("address LIKE ?"); parameters.add("%" + address + "%"); } if (!conditions.isEmpty()) { baseSql += " AND " + String.join(" AND ", conditions); } try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(baseSql)) { // 设置参数 for (int i = 0; i < parameters.size(); i++) { pstmt.setObject(i+1, parameters.get(i)); } ResultSet rs = pstmt.executeQuery(); // 处理结果集 } ``` ### 方法2:使用StringBuilder构建(更灵活) 当条件较多时,使用StringBuilder可以更高效地构建SQL字符串。 ```java StringBuilder sqlBuilder = new StringBuilder("SELECT * FROM user WHERE 1=1"); List<Object> params = new ArrayList<>(); if (name != null && !name.isEmpty()) { sqlBuilder.append(" AND name LIKE ?"); params.add("%" + name + "%"); } if (address != null && !address.isEmpty()) { sqlBuilder.append(" AND address LIKE ?"); params.add("%" + address + "%"); } try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sqlBuilder.toString())) { for (int i = 0; i < params.size(); i++) { pstmt.setObject(i+1, params.get(i)); } ResultSet rs = pstmt.executeQuery(); // ... } ``` ### 方法3:使用MyBatis的动态SQL 如果你使用MyBatis作为ORM框架,可以使用其提供的动态SQL功能: ```xml <select id="findUsers" resultType="User"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="address != null and address != ''"> AND address LIKE CONCAT('%', #{address}, '%') </if> </where> </select> ``` 在Java中调用这个映射语句即可。 ### 方法4:使用JPA Criteria API 如果你使用JPA(如Hibernate),可以使用Criteria API构建动态查询: ```java CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery<User> query = cb.createQuery(User.class); Root<User> root = query.from(User.class); List<Predicate> predicates = new ArrayList<>(); if (name != null && !name.isEmpty()) { predicates.add(cb.like(root.get("name"), "%" + name + "%")); } if (address != null && !address.isEmpty()) { predicates.add(cb.like(root.get("address"), "%" + address + "%")); } query.where(predicates.toArray(new Predicate[0])); List<User> users = entityManager.createQuery(query).getResultList(); ``` ### 注意事项 - **防止SQL注入**:绝对不要直接拼接用户输入的值到SQL语句中(如引用[4]所示),而应使用PreparedStatement的占位符`?`。 - **性能考虑**:在构建动态SQL时,注意索引的使用,避免因条件变化导致索引失效。 通过以上方法,你可以根据项目的实际情况选择适合的方式编写条件查询SQL。 §§相关问题§§ 1. 如何防止Java中的SQL注入攻击? 2. MyBatis动态SQL标签有哪些? 3. JPA Criteria API如何进行多表联合查询? 4. 在Spring Data JPA中如何实现动态查询?</think>### Java中编写条件查询SQL语句的完整指南 在Java中编写条件查询SQL语句时,需要特别注意**SQL注入防护**和**动态条件拼接**。以下是详细解决方案: #### 1. 基础条件查询(固定条件) ```java // 使用PreparedStatement防止SQL注入 String name = "John"; String sql = "SELECT * FROM users WHERE name = ? AND age > ?"; try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, name); // 设置第一个参数 pstmt.setInt(2, 18); // 设置第二个参数 ResultSet rs = pstmt.executeQuery(); // 处理结果集... } ``` #### 2. 动态多条件查询(推荐方案) 使用`StringBuilder`和条件判断构建安全查询: ```java public List<User> findUsers(String name, Integer minAge, String address) { StringBuilder sql = new StringBuilder("SELECT * FROM users WHERE 1=1"); List<Object> params = new ArrayList<>(); if (name != null) { sql.append(" AND name LIKE ?"); params.add("%" + name + "%"); // 模糊查询 } if (minAge != null) { sql.append(" AND age >= ?"); params.add(minAge); } if (address != null) { sql.append(" AND address = ?"); params.add(address); } try (Connection conn = dataSource.getConnection(); PreparedStatement pstmt = conn.prepareStatement(sql.toString())) { // 动态设置参数 for (int i = 0; i < params.size(); i++) { pstmt.setObject(i + 1, params.get(i)); } ResultSet rs = pstmt.executeQuery(); // 转换结果集为对象... } } ``` #### 3. 使用框架简化(MyBatis示例) ```xml <!-- MyBatis映射文件 --> <select id="findUsers" resultType="User"> SELECT * FROM users <where> <if test="name != null"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="minAge != null"> AND age >= #{minAge} </if> </where> </select> ``` #### 4. 关键注意事项 1. **SQL注入防护** - 永远不要拼接字符串:`"SELECT ... WHERE id = " + input` ❌ - 必须使用参数化查询:`PreparedStatement` + `?`占位符 ✅ 2. **动态条件技巧** - 使用`WHERE 1=1`作为占位避免条件判断 - 用`StringBuilder`高效构建SQL - 参数与SQL分离存储(如示例中的`params`列表) 3. **模糊查询规范** ```java // 正确写法 sql.append(" AND name LIKE ?"); params.add("%" + searchTerm + "%"); // 在参数中添加通配符 ``` 4. **空值处理** ```java // 使用Optional避免空指针 Optional.ofNullable(address).ifPresent(addr -> { sql.append(" AND address = ?"); params.add(addr); }); ``` #### 5. 完整示例(带分页) ```java public List<User> searchUsers(String keyword, int page, int size) { StringBuilder sql = new StringBuilder("SELECT * FROM users WHERE 1=1"); List<Object> params = new ArrayList<>(); if (keyword != null) { sql.append(" AND (name LIKE ? OR email LIKE ?)"); params.add("%" + keyword + "%"); params.add("%" + keyword + "%"); } sql.append(" LIMIT ? OFFSET ?"); params.add(size); params.add((page - 1) * size); // 执行查询... } ``` > **最佳实践**:对于复杂业务场景,推荐使用MyBatis、Spring Data JPA等框架,它们提供更安全的动态SQL支持[^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值