Reputation: 3628
I've an application that use mybatis for object persistence. But there are chances I need to run arbitrary sql(from user). Can I do it with mybatis?
Update:
I choose to use dbutils (JDBC) to run user-defined sql, but I need a instance of DataSource to create QueryRunner. Is there any way I can get datasource from mybatis?
Upvotes: 14
Views: 25783
Reputation: 217
For testing I use
import org.apache.ibatis.jdbc.ScriptRunner;
import java.io.Reader;
import java.io.StringReader;
public class test {
private static final String conf = "mybatis.conf.xml";
private SqlSessionFactoryBuilder builder;
private SqlSessionFactory sessionFactory;
Reader reader;
private SqlSession session;
private ScriptRunner runner;
@Before
public void before() {
builder = new SqlSessionFactoryBuilder();
try {
reader = Resources.getResourceAsReader(conf);
} catch (IOException e) {
e.printStackTrace();
}
sessionFactory = builder.build(reader);
session = sessionFactory.openSession();
runner = new ScriptRunner(session.getConnection());
runner.setAutoCommit(true);
runner.setStopOnError(true);
}
@Test
public void testSelectChapelStatus() {
Reader populate = new StringReader("insert into person values (7553,0,'201002496','Wish','Jill','Rain',1,0,NULL,'[email protected]');\r\n"
+ "");
runner.runScript(populate);
}
Upvotes: 1
Reputation: 149
Your question is similar to How to exequte query directly from java code using mybatis?
I have already given the answer to that question. But I hope this solution will help you.
Mybatis has already this function, but you must use the adapter as follows.
create an adapter class;
public class SQLAdapter {
String sql;
public SQLAdapter(String sql) {
this.sql = sql;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
} }
create typeAlias of class SQLAdapter
<typeAlias alias="sqladapter" type="com.zj.xxx.xxx.SQLAdapter" />
put select tag in each object xml where you need to execute the sql directly.
<select id="findRecords" parameterType="SQLAdapter" resultMap="xxxxxResultMap">
${sql}
</select>
call this select method like
String _sql = "select * from table where... order by... limit..."; xxxxx.findRecords(new SQLAdapter(_sql));
Upvotes: 5
Reputation: 85
Reusable fragment of SQL can be used to create select part of query dynamically. In you mapper pass query as normal parameter:
@Param("sql")String sql
In your query just access the parameter using ${sql} instead of #{sql}. Value in parameter sql can be a fully valid sql query or a fragment of sql query.
Upvotes: 2
Reputation: 1223
Based on the answers provided, they both are good. But both of them required an Adapter
class to be used.
Using Mybatis version 3, I succeeded using a HashMap<String, String>
to keep and pass the SQL.
See the codes below.
in Mapper
class
final String sql = "${sql}";
@Select(sql)
void execute(HashMap<String, String> m);
when invoke the method:
String sql = "SELECT * FROM record limit 1";
HashMap<String, String> map = new HashMap<String, String>();
map.put("sql", sql);
mapper.execute(map);
HashMap
provides a way that you don't have to define the Class properties, or fields in code, you can use a Map to define it redomly.
Thanks.
Upvotes: 2
Reputation: 15709
I use this utilitary class:
import java.util.List;
import org.apache.ibatis.annotations.SelectProvider;
public interface SqlMapper {
static class PureSqlProvider {
public String sql(String sql) {
return sql;
}
public String count(String from) {
return "SELECT count(*) FROM " + from;
}
}
@SelectProvider(type = PureSqlProvider.class, method = "sql")
public List<?> select(String sql);
@SelectProvider(type = PureSqlProvider.class, method = "count")
public Integer count(String from);
@SelectProvider(type = PureSqlProvider.class, method = "sql")
public Integer execute(String query);
}
Upvotes: 17