2012-11-02 3 views
11

MyBatisが動的SQLを生成するための理想的な候補のように見える、いくつかのオプションのフィルタを使用して構築する複雑なクエリがあります。Dynamic SQLを実行せずにMyBatisを使用して生成できますか?

しかし、MyBatisを使用していない残りのアプリケーションと同じフレームワークでクエリを実行したいと考えています。

私は、SQLを生成するためにMyBatisを厳密に使用することを望んでいましたが、そこから実際にそれを実行するために残りのアプリケーションを使用していました。これは可能ですか?もしそうなら、どうですか?

答えて

11

MyBatisは、作成後にクエリを実行するように設計されていますが、必要なものを得るためには、内部構成と少しの知識を活用することができます。

MyBatisは非常に素晴らしいフレームワークですが、残念ながらドキュメント側には欠けているので、ソースコードはあなたの友人です。あなたが周りを掘る場合は、動的SQLを構築するためのキープレーヤーであるorg.apache.ibatis.mapping.MappedStatementorg.apache.ibatis.mapping.BoundSqlのクラスにぶつかるべきです。ここでは基本的な使用例です。その中に、このデータと

MySQLのテーブルuser

name login 
----- ----- 
Andy a 
Barry b 
Cris c 

Userクラス:

package pack.test; 
public class User { 
    private String name; 
    private String login; 
    // getters and setters ommited 
} 

UserServiceインターフェイス:

package pack.test; 
public interface UserService { 
    // using a different sort of parameter to show some dynamic SQL 
    public User getUser(int loginNumber); 
} 

UserService.xmlマッパーファイル:

<mapper namespace="pack.test.UserService"> 
    <select id="getUser" resultType="pack.test.User" parameterType="int"> 
     <!-- dynamic change of parameter from int index to login string --> 
     select * from user where login = <choose> 
              <when test="_parameter == 1">'a'</when> 
              <when test="_parameter == 2">'b'</when> 
              <otherwise>'c'</otherwise> 
             </choose> 
    </select> 
</mapper> 

sqlmap-config.file

package pack.test; 

import java.io.Reader; 
import org.apache.ibatis.io.Resources; 
import org.apache.ibatis.mapping.BoundSql; 
import org.apache.ibatis.mapping.MappedStatement; 
import org.apache.ibatis.session.SqlSession; 
import org.apache.ibatis.session.SqlSessionFactoryBuilder; 

public class AppTester { 
    private static String CONFIGURATION_FILE = "sqlmap-config.xml"; 

    public static void main(String[] args) throws Exception { 
     Reader reader = null; 
     SqlSession session = null; 
     try { 

      reader = Resources.getResourceAsReader(CONFIGURATION_FILE); 
      session = new SqlSessionFactoryBuilder().build(reader).openSession(); 
      UserService userService = session.getMapper(UserService.class); 

      // three users retreived from index 
      for (int i = 1; i <= 3; i++) { 
       User user = userService.getUser(i); 
       System.out.println("Retreived user: " + user.getName() + " " + user.getLogin()); 

       // must mimic the internal statement key for the mapper and method you are calling 
       MappedStatement ms = session.getConfiguration().getMappedStatement(UserService.class.getName() + ".getUser"); 
       BoundSql boundSql = ms.getBoundSql(i); // parameter for the SQL statement 
       System.out.println("SQL used: " + boundSql.getSql()); 
       System.out.println(); 
      } 

     } finally { 
      if (reader != null) { 
       reader.close(); 
      } 
      if (session != null) { 
       session.close(); 
      } 
     } 
    } 
} 

そして結果:

Retreived user: Andy a 
SQL used: select * from user where login = 'a' 

Retreived user: Barry b 
SQL used: select * from user where login = 'b' 

Retreived user: Cris c 
SQL used: select * from user where login = 'c' 
+0

のようであるかもしれない、それは '示し?'の代わりに実際の値。例えば'どこログイン=? '。これを回避するには?ありがとう (私はマッパークラスを使用していません) – agpt

0

だけボグダンの正しい答えに追加する:あなたは必要

<configuration> 
    <settings> 
     <setting name="lazyLoadingEnabled" value="false" /> 
    </settings> 
    <environments default="development"> 
     <environment id="development"> 
      <transactionManager type="JDBC"/> 
      <dataSource type="POOLED"> 
       <property name="driver" value="com.mysql.jdbc.Driver"/> 
       <property name="url" value="jdbc:mysql://localhost/test"/> 
       <property name="username" value="..."/> 
       <property name="password" value="..."/> 
      </dataSource> 
     </environment> 
     </environments> 
    <mappers> 
     <mapper resource="pack/test/UserService.xml"/> 
    </mappers> 
</configuration> 

AppTester結果を表示します〜を渡すJavaBeanをgetBoundSql()に設定すると、インターフェイスのパラメータにgetterが使用されます。インターフェイスにはより複雑なシグネチャがあります。

ログイン番号および/またはユーザー名に基づいてユーザーを照会するとします。あなたのインターフェイスは、次のようになります。

それはこの議論には無関係だが、AppTesterであなたのコードになるはずなので、私はマッパーコードを残している
package pack.test; 
public interface UserService { 
    // using a different sort of parameter to show some dynamic SQL 
    public User getUser(@Param("number") int loginNumber, @Param("name") String name); 
} 

[...] 
final String name = "Andy"; 
User user = userService.getUser(i, name); 
System.out.println("Retreived user: " + user.getName() + " " + user.getLogin()); 

// must mimic the internal statement key for the mapper and method you are calling 
MappedStatement ms = session.getConfiguration().getMappedStatement(UserService.class.getName() + ".getUser"); 
BoundSql boundSql = ms.getBoundSql(new Object() { 
    // provide getters matching the @Param's in the interface declaration 
    public Object getNumber() { 
    return i; 
    } 
    public Object getName() { 
    return name; 
    } 

}); 
System.out.println("SQL used: " + boundSql.getSql()); 
System.out.println(); 
[...] 
1

誰もがBoundSqlを使用する方法を知っています。getSql()のように、MyBatisのからparamaterizedクエリ文字列を取得する:

// get parameterized query 
MappedStatement ms = configuration.getMappedStatement("MyMappedStatementId"); 
BoundSql boundSql = ms.getBoundSql(parameters); 
System.out.println("SQL" + boundSql.getSql()); 
// SELECT species FROM animal WHERE name IN (?, ?) or id = ? 

しかし、今は、式の残りの半分、疑問符に対応する値のリストが必要です。

// get parameters 
List<ParameterMapping> boundParams = boundSql.getParameterMappings(); 
String paramString = ""; 
for(ParameterMapping param : boundParams) { 
    paramString += boundSql.getAdditionalParameter(param.getProperty()) + ";"; 
} 
System.out.println("params:" + paramString); 
// "Spot;Fluffy;42;" 

これをシリアル化して別の場所に送信して実行することもできますし、ログに出力して、それらをつなぎ合わせて手動でクエリを実行することもできます。

*コードテストされていません、私のためにマイナーなタイプの問題や

関連する問題