gpt4 book ai didi

java - MyBatis 3 - 从映射器获取 SQL 字符串

转载 作者:搜寻专家 更新时间:2023-10-30 19:45:28 24 4
gpt4 key购买 nike

我只想使用 MyBatis3 来生成 SQL 字符串(使用 xml 映射)但我获得的 SQL 无效。

例如,我获取sql字符串:

SELECT * FROM USER WHERE NAME = john

在这个 sql 中不存在围绕字符串值 john' 字符

mybatis.xml中:

...
<mappers>
<mapper resource="sql1.xml"/>
</mappers>
...

sql1.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="sql1">
<select id="select1" parameterType="map" resultType="String" >
SELECT * FROM USERS
WHERE
name LIKE ${name} AND num = ${number}
</select>
</mapper>

MyBatisSql.java中:

SqlSessionFactory sessionFactory = ConnectionFactory.getSqlSessionFactory();
Configuration configuration = sessionFactory.getConfiguration();

Map pars = new HashMap<String, Object>();
pars.put("name", "john");
pars.put("number", 1345);

MappedStatement ms = configuration.getMappedStatement("sql1.select1);
BoundSql boundSql = ms.getBoundSql(params);
String sql = boundSql.getSql();
System.out.println(sql);

结果是

SELECT * FROM USERS
WHERE
name LIKE john AND num = 12345

在此 SQL 中,字符串 john 未包含在 ' 字符中所以它不是有效的 SQL(我的目的只是使用 myBatis 生成有效的 SQL 字符串)。我想要:

SELECT * FROM USERS
WHERE
name LIKE 'john' AND num = 12345

谢谢

最佳答案

您应该使用 #{name} 而不是 ${name}

下面的示例将生成有效的 SQL

<mapper namespace="sql1">
<select id="select1" parameterType="map" resultType="String" >
SELECT * FROM USERS
WHERE
name LIKE #{name} AND num = #{number}
</select>
</mapper>

如果使用 $ 字符,MyBatis 会直接复制粘贴字符串参数。另一方面,如果您使用 # 字符,它会使用参数绑定(bind)。

然后您应该使用 selectMap、selectList 或 selectOne 执行您的 sql,

List<String> resultSet = sessionFactory.openSession().selectList("sql1.select1", pars);

此调用会自动将参数绑定(bind)到语句并执行。

警告:

<select id="select1" parameterType="map" resultType="String" >
SELECT * FROM USERS
WHERE
name LIKE #{name} AND num = #{number}
</select>

可能无法执行,因为 MyBatis 无法将多个列 (SELECT *) 映射到单个字符串 (resultType="String") 显示了两个可能的查询更正下面:

<!--Solution One-->
<select id="select1" parameterType="map" resultType="String" >
SELECT name FROM USERS
WHERE
name LIKE #{name} AND num = #{number}
</select>

<!--Solution Two-->
<select id="select1" parameterType="map" resultType="java.util.LinkedHashMap" >
SELECT * FROM USERS
WHERE
name LIKE #{name} AND num = #{number}
</select>

对于解决方案二,您应该使用以下 java 代码执行 mybatis 查询:

List<Map<?, ?>> resultSet = sessionFactory.openSession().selectList("sql1.select1", pars);

为什么 getBoundSql 返回带 ? 的查询的详细信息:

参数绑定(bind)是在驱动级别完成的,所以你不会得到这样的 sql 字符串

SELECT * FROM USERS
WHERE
name LIKE 'john' AND num = 12345

相反,您将获得已准备好进行参数绑定(bind)的 sql 查询模板,

SELECT * FROM USERS
WHERE
name LIKE ? AND num = ?

将参数添加到 sql 字符串中允许 sql 注入(inject)。安全的方法是使用 SQL Driver 提供的参数绑定(bind)方法,而 MyBatis 总是使用参数绑定(bind)。

假设您手动将 sql 命令创建为字符串,并假设我是一个试图访问您的数据的恶意用户。我会写

john' or ''='

所以这将生成下面的 sql 命令:

SELECT * FROM USERS
WHERE
name LIKE 'john' or ''='' AND num = 12345

参数绑定(bind)的其他好处

参数绑定(bind)的第二个好处是它允许准备语句。假设您需要使用不同的参数执行相同的 sql 1000 次。

如果生成带有参数绑定(bind)的sql字符串,

SELECT * FROM USERS WHERE name LIKE 'john' AND num = 12345;
SELECT * FROM USERS WHERE name LIKE 'foo' AND num = 67890;

数据库服务器需要对每条sql命令进行一条一条的解析,然后执行。

使用参数化的sql查询,

SELECT * FROM USERS WHERE name LIKE ? AND num = ?

SQL 驱动程序缓存查询,因此只进行一次解析,然后将不同的参数绑定(bind)到相同的 SQL 命令

更新:在 MyBatis 之外使用 BoundSql

您仍然可以将参数化的 sql (boundSql) 与另一个库或 Java 的 java.sql.Connection 一起使用。下面是一个例子:

Connection myConnection;
PreparedStatement preparedStatement = myConnection.prepareStatement(boundSql);
preparedStatement.setString(1, "john"); //First parameter starts with 1 not 0!
preparedStatement.setInt(2, 12345);
ResultSet results = preparedStatement.executeQuery();

关于java - MyBatis 3 - 从映射器获取 SQL 字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33197085/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com