There have been a lot of questions recently about how to call stored
procedures with MyBatis. This is an area where the documentation is,
admittedly, very weak. Until we can improve the documentation, I've
committed several tests that demonstrate the many different ways to
call stored procedures with MyBatis. You can use this as example code
for the different situations you might face. The complete test
package is here:
http://mybatis.googlecode.com/svn/trunk/src/test/java/org/apache/ibatis/submitted/sptests/
Please note that this code will only fully run with the HSQLDB 2.0.1
release candidates. In the code you will see that many of the tests
have the @Ignore annotation so we don't break the MyBatis build. Once
HSQLDB 2.0.1 is released, I'll remove the @Ignore annotation for many
of these tests.
If you are having trouble with stored procedures in MyBatis, please
review this sample code and then feel free to ask questions.
In the last couple of days we have talked about a potential problem
with MyBatis and stored procedures. Here are the circumstances under
which you will see this problem:
1. The procedure has one or more output parameters AND returns a result set.
2. You call the procedure more than once in the same session, with the
exact same input parameters.
In this case, the output parameters will not be returned properly on
subsequent calls, unless you clear the session cache manually before
each subsequent call.
But this is a VERY RARE situation indeed. So the message is that the
vast majority of stored procedures will work just fine with MyBatis as
it stands.
Enjoy!
Jeff Butler
public class SPTest {
private static SqlSessionFactory createSqlMapper() throws IOException {
String resource = "resources/sqlMapConfig.xml";
Reader reader = Resources.getResourceAsReader(resource);
return new SqlSessionFactoryBuilder().build(reader,"development");
}
public static void main(String[] args) {
SqlSession sqlSession = null;
try {
sqlSession = createSqlMapper().openSession();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
SPMapper spMapper = sqlSession.getMapper(SPMapper.class);
Map parms = new HashMap();
parms.put("first_name", "Barney");
List names = spMapper.getNames(parms);
System.out.println(names);
} finally {
sqlSession.close();
}
}
}
and I create the table without column ID:
create table names(first_name varchar(20),last_name varchar(20))
go
insert into names (first_name, last_name) values('Fred', 'Flintstone')
insert into names (first_name, last_name) values('Wilma', 'Flintstone')
insert into names (first_name, last_name) values('Barney', 'Rubble')
insert into names (first_name, last_name) values('Betty', 'Rubble')
go
I create the getNames stored procedure as below:
create proc getNames
@in varchar(10)
as
declare @cur varchar(20)
select @cur=first_name from names
select first_name,last_name from names where first_name >= @in
go
the SPMapper.xml:
I did not change other files, when run SPTest, result is null:
DEBUG PooledDataSource - Created connection 12423818.
DEBUG Connection - ooo Connection Opened
DEBUG PreparedStatement - ==> Executing: {call SET CHAINED OFF exec tempdb..getNames ?}
DEBUG PreparedStatement - ==> Parameters: null
Result names - []
DEBUG Connection - xxx Connection Closed
DEBUG PooledDataSource - Returned connection 12423818 to pool.
I'm feeling very tough about this problem, Hope you can have a look of my problem and help me on this problem, as MyBatis is so lightweight, I do not want to drop it in our new program.
Besides, I conclude the problem as: If there are more than one selection in the stored procedure, when call the sp in MyBatis, only the first selection will be executed.
1. In your HashMap, the parameter is called "first_name", in your XML
that parameter is called "in". So you need to be consistent there.
2. In the XML, the call looks wrong. You've not added the required
parenthesis, and there's a lot of extra stuff in the call. Stored
proc calls MUST follow the standard JDBC escape sequence.
So, change your XML to this and see if it improves:
{call tempdb..getNames (#{first_name,jdbcType=VARCHAR,mode=IN})}
Jeff Butler
> from names where first_name >= @in go the SPMapper.xml: I did not change
SET NOCOUNT ON
This will tell sybase not to show the intermediate rowcounts. There
have been some posts in the past about this issue.
Jeff Butler
Jeff
If you actually want to process more than one result set, then MyBatis
can do it - simply specify more than one resultMap like this:
resultMap="map1,map2,map3"
Jeff Butler