我有一些複雜的查詢來構建一些可選的過濾器,MyBatis似乎是生成動態SQL的理想選擇。我可以使用MyBatis生成動態SQL而不執行它嗎?
但是,我仍然希望我的查詢在與應用程序的其餘部分(不使用MyBatis)相同的框架中執行。
所以我希望做的是嚴格使用MyBatis來生成SQL,但從那裏使用我的應用程序的其餘部分來實際執行它。這可能嗎?如果是這樣,怎麼樣?
我有一些複雜的查詢來構建一些可選的過濾器,MyBatis似乎是生成動態SQL的理想選擇。我可以使用MyBatis生成動態SQL而不執行它嗎?
但是,我仍然希望我的查詢在與應用程序的其餘部分(不使用MyBatis)相同的框架中執行。
所以我希望做的是嚴格使用MyBatis來生成SQL,但從那裏使用我的應用程序的其餘部分來實際執行它。這可能嗎?如果是這樣,怎麼樣?
儘管MyBatis被設計爲在構建它之後執行查詢,但您可以利用它的配置和一點點「內部知識」來獲取所需內容。
MyBatis是一個非常好的框架,不幸的是它缺乏文檔方面的知識,所以源代碼是你的朋友。如果你在周圍挖掘,你應該碰到這些類:org.apache.ibatis.mapping.MappedStatement
和org.apache.ibatis.mapping.BoundSql
,它們是構建動態SQL的關鍵角色。這是一個基本的使用示例:
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
:
<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
顯示結果:
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'
只需添加到波格丹的正確答案:您需要傳遞一個JavaBean到getBoundSql()
與getter的你的接口參數,如果你的接口有一個更復雜的簽名。
假設您想根據登錄號碼和/或用戶名查詢用戶。您的界面可能是這樣的:
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);
}
我要離開了映射代碼,因爲它是不相關的討論,但你在AppTester代碼應該變成:
[...]
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();
[...]
每個人都知道如何使用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;"
現在,您可以序列化它以發送到其他地方運行,或者您可以將它打印到日誌中,以便將它們縫合在一起並手動運行查詢。
*代碼沒有經過測試,可能是次要問題或類似的問題
對我來說,它顯示'?'而不是實際值。例如'在哪裏登錄=?'。任何解決這個問題?謝謝 (我沒有使用mapper類) – agpt