web-dev-qa-db-ja.com

MyBatis 3-マッパーからSQL文字列を取得

MyBatis3を使用して(xmlマッピングを使用して)SQL文字列を生成したいのですが、取得したSQLが無効です。

例、sql文字列を取得します。

SELECT * FROM USER WHERE NAME = john

このsqlには存在しません'文字列値を囲む文字john

in 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>

in 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

ありがとう

14
Lof

$ {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は文字列パラメータを直接コピーして貼り付けます。一方、#文字を使用すると、パラメータバインディングが使用されます。

次に、selectMap、selectList、またはselectOneを使用してSQLを実行する必要があります。

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

この呼び出しは、パラメーターをステートメントに自動的にバインドして実行します。

警告:

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

myBatisは複数の列(SELECT *)を単一の文字列(resultType = "String")にマップできないため、実行に失敗する可能性があります。クエリに対する2つの可能な修正を以下に示します。

<!--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>

ソリューション2の場合、Java以下のコードを使用してmybatisクエリを実行する必要があります。

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

GetBoundSqlが?でクエリを返す理由の詳細:

パラメータのバインドはドライバレベルで行われるため、このようなSQL文字列は取得されません

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

代わりに、パラメーターバインディングの準備ができているSQLクエリテンプレートを取得します。

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

SQL文字列にパラメーターを追加すると、SQLインジェクションが許可されます。安全な方法は、SQLドライバーで提供されるパラメーターバインディングメソッドを使用することです。MyBatisは常にパラメーターバインディングを使用します。

Sqlコマンドを文字列として手動で作成したとします。また、私がデータにアクセスしようとしている悪意のあるユーザーであるとします。私は書くことができます

john' or ''='

したがって、以下のsqlコマンドが生成されます。

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

パラメータバインディングのその他の利点

パラメータバインディングの2番目の利点は、準備されたステートメントを使用できることです。同じSQLを異なるパラメーターで1000回実行する必要があるとします。

パラメータがバインドされたSQL文字列を生成する場合、

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

データベースサーバーは、各sqlコマンドを1つずつ解析して実行する必要があります。

パラメータ化されたSQLクエリでは、

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

SQLドライバーはクエリをキャッシュするため、解析は1回だけ行われ、その後、異なるパラメーターを同じ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();
9
vahapt
            SELECT(" * ");
            FROM(" student ");
            WHERE(" ten LIKE '%' #{ten} '%' ");

使用でき、 '%'と#{}の間にスペース(_)を挿入する必要があります

0
Trang NT