hibernate预编译SQL语句中的setParameter和setParameterList

预编译SQL语句通过占位符避免了字符串拼接带来的复杂性和潜在错误,提高了代码可读性和性能。Hibernate提供了setParameter和setParameterList方法来替换JDBC中的占位参数。其中,setParameterList在处理'in'查询时更为便捷,体现了Hibernate API的良好设计,为开发者提供了更多选择。

使用预编译SQL语句和占位符参数(在jdbc中是?),能够避免因为使用字符串拼接sql语句带来的复杂性。我们先来简单的看下,使用预编译SQL语句的好处。使用String sql = "select * from Student where name=" + name;如果name的值是1或 "aty"或"aty'aty",就会产生下面错误的sql

--ORA-01722 invalid number
select * from student where name=1;

--ORA-00904 invalid identifier
select * from student where name=aty;

--ORA-01756: quoted string not properly terminated
select * from student where name=aty'aty;

在构造sql的时候,使如果用了字符串拼接,就必须考虑数据类型,是否需要加单引号等细节问题,稍微不注意,就会导致错误sql语句。当拼接字符串很多的时候,代码几乎不可读,定位问题也十分困难。这是预编译sql在代码可读性和简单性上的优势。还有就是性能上的优势,可以参考我的另一篇博文:HQL或SQL使用?带来的好处:减少SQL解析时间、降低内存开销、防止SQL注入

 

JDBC提供PreparedStatement.setXXX()来替换占位参数,hibernate对应的是setParameter和setParameterList。

setParametersetParameterList的区别在于,使用in的时候。

Object[] params = new Integer[]{1, 2};

String hqlF = "from Student where id in (?,?)";
Query query = session.createQuery(hqlF);
for (int i = 0; i < params.length; i++)
{
    query.setParameter(i, params[i]);
}

//String hqlS = "from Student where id in :valueList";
String hqlS = "from Student where id in (:valueList)";
Query queryS = session.createQuery(hqlS);     
queryS.setParameterList("valueList", params);

很显然,使用setParameterList代码更简单。这里也赞美下hibernate的API设计,既提供了常规繁琐的做法setParameter,也提供了简洁易用的setParameterList。这种一致性,对于熟悉和不熟悉hibernate的人来说,提供了更多的选择。

### Java中使用setParameter方法动态拼接SQL语句的安全性及正确用法 在Java中,`setParameter`方法通常与`PreparedStatement`或ORM框架(如Hibernate、MyBatis)结合使用,以防止SQL注入攻击。以下是关于其安全性正确用法的详细说明。 #### 1. 安全性分析 使用`setParameter`方法是防止SQL注入的有效方式之一。通过预编译语句参数绑定机制,数据库驱动程序会自动对参数进行转义处理,从而避免恶意输入被解析为SQL代码的一部分[^1]。例如: ```java String sql = "SELECT c.name FROM Category c WHERE c.id = :id"; Query query = session.createQuery(sql); query.setParameter("id", userId); ``` 上述代码中,`:id`是一个命名占位符,`setParameter`方法将用户输入的`userId`绑定到该占位符上。无论用户输入的内容是什么,它都会被视为一个普通的字符串或数值,而不会改变SQL语句的结构。 相比之下,直接拼接SQL字符串的方式存在严重的安全隐患。例如: ```java String sql = "SELECT * FROM users WHERE id = " + req.getParameter("id"); ``` 如果用户输入`id=1 OR 1=1`,最终生成的SQL语句将是`SELECT * FROM users WHERE id = 1 OR 1=1`,这可能导致查询返回所有用户的记录[^2]。 #### 2. 正确用法 以下是使用`setParameter`方法的正确示例及其注意事项。 ##### 示例1:使用`PreparedStatement` `PreparedStatement`是JDBC提供的标准接口,用于执行预编译SQL语句。以下是一个简单的示例: ```java String sql = "SELECT * FROM users WHERE username = ? AND password = ?"; try (PreparedStatement pstmt = connection.prepareStatement(sql)) { pstmt.setString(1, username); pstmt.setString(2, password); ResultSet rs = pstmt.executeQuery(); // 处理结果集 } ``` 在此示例中,`?`是占位符,`setString`方法将用户输入的值绑定到对应的占位符位置。这种方式确保了输入内容不会影响SQL语句的逻辑结构。 ##### 示例2:使用Hibernate的`Query`对象 在Hibernate中,可以使用`Query`对象执行带有参数的HQL(Hibernate Query Language)查询。例如: ```java String hql = "FROM User u WHERE u.username = :username AND u.password = :password"; Query query = session.createQuery(hql); query.setParameter("username", username); query.setParameter("password", password); List<User> users = query.list(); ``` 这里,`:username``:password`是命名占位符,`setParameter`方法将实际值绑定到这些占位符上。Hibernate会自动处理参数的转义,确保安全性[^3]。 ##### 示例3:使用MyBatis的`#{}`占位符 在MyBatis中,可以通过XML映射文件或注解定义参数化查询。例如: ```xml <select id="findUserByUsernameAndPassword" resultType="User"> SELECT * FROM users WHERE username = #{username} AND password = #{password} </select> ``` 对应的Java接口如下: ```java public interface UserMapper { User findUserByUsernameAndPassword(@Param("username") String username, @Param("password") String password); } ``` 调用时: ```java User user = userMapper.findUserByUsernameAndPassword(username, password); ``` MyBatis会自动将`#{}`占位符替换为安全的参数绑定表达式,从而防止SQL注入[^3]。 #### 3. 注意事项 - **避免使用`$`符号**:在MyBatis中,`$`符号会将变量直接插入到SQL语句中,而不进行任何转义。因此,应尽量避免使用`$`,改用`#{}`以确保安全性。 - **输入验证**:即使使用了`setParameter`方法,仍然建议对用户输入进行严格的格式校验清理,以进一步降低潜在风险[^5]。 - **数据库权限管理**:为数据库用户分配最小必要的权限,限制其仅能访问特定的表或视图,从而减少SQL注入带来的损害。 ### 总结 在Java中,使用`setParameter`方法动态拼接SQL语句是一种安全的做法,前提是正确地结合`PreparedStatement`、Hibernate或MyBatis等工具。这种方法通过参数绑定机制有效防止了SQL注入攻击,同时提高了代码的可读性维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值