2012-11-02 11 views
11

Mam kilka złożonych zapytań do zbudowania z wieloma opcjonalnymi filtrami, dla których MyBatis wydaje się idealnym kandydatem do generowania dynamicznego SQL.Czy mogę używać MyBatis do generowania dynamicznego SQL bez jego wykonywania?

Jednak nadal chcę, aby moje zapytanie zostało wykonane w tych samych ramach co reszta aplikacji (która nie korzysta z MyBatis).

Więc miałem nadzieję, że użyję MyBatis wyłącznie do wygenerowania kodu SQL, ale stamtąd użyję reszty mojej aplikacji, aby ją wykonać. czy to możliwe? Jeśli tak to jak?

Odpowiedz

11

Mimo że MyBatis został zaprojektowany do wykonywania zapytania po jego zbudowaniu, możesz skorzystać z jego konfiguracji i odrobiny "wewnętrznej wiedzy", aby dostać się do tego, czego potrzebujesz.

MyBatis jest bardzo ładną ramą, niestety brakuje jej po stronie dokumentacji, więc kod źródłowy jest twoim przyjacielem. Jeśli kopiesz dookoła, powinieneś natknąć się na te klasy: org.apache.ibatis.mapping.MappedStatement i org.apache.ibatis.mapping.BoundSql, które są kluczowymi graczami w budowaniu dynamicznego SQL. Oto prosty przykład użycia:

MySQL tabela user z tymi danymi w nim:

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

User klasa:

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

UserService interfejs: plik

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

UserService.xml odwzorowujący :

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

<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 pokazać wynik:

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(); 
      } 
     } 
    } 
} 

a wynik:

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

dla mnie pokazuje "?" Zamiast rzeczywistej wartości. na przykład 'gdzie login =?'. jakieś prace nad tym? dzięki (nie używam klasy mapper) – agpt

0

Wystarczy dodać do poprawnej odpowiedzi Bogdana: Musisz przekazać a JavaBean do getBoundSql() z geterem za parametry interfejsu, jeśli interfejs ma bardziej złożony podpis.

Załóżmy, że chcesz zapytać użytkownika na podstawie numeru logowania i/lub nazwy użytkownika. Twój interfejs może wyglądać następująco:

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); 
} 

Wyjeżdżam z kodu Mapper ponieważ jest to bez znaczenia dla tej dyskusji, ale Twój kod w AppTester powinny stać się:

[...] 
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

Każdy wie, jak używać BoundSql .getSql(), aby uzyskać paramaterized ciąg kwerendy z MyBatis, tak:

// 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 = ? 

Ale teraz trzeba drugą połowę równania, listę wartości, które odpowiadają znaki zapytania:

// 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;" 

Teraz możesz serializować go, aby wysłać gdzie indziej, aby uruchomić, lub możesz wydrukować go do dziennika, dzięki czemu można połączyć je razem i uruchomić zapytanie ręcznie.

* kod nie testowany, może być pomniejszony lub coś w tym stylu.

Powiązane problemy