10.3 MyBatis调用存储过程 SQL语句在执行的时候需要先编译,然后执行。数据库的存储过程(Procedure)是组为了完成特定功能的SQL语句,编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用存储过程。 使用存储过程可提高数据库执行速度,并且存储过程可以重复使用,从而减少数据库开发人员的工作量。 下面重点介绍如何使用MyBatis调用存储过程。
10.3.1插入数据 测试数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 DROP  TABLE  IF  EXISTS  `tb_user` ;CREATE  TABLE  `tb_user`  (  `id`  int (11 ) NOT  NULL  AUTO_INCREMENT,   `name`  varchar (18 ) DEFAULT  NULL ,   `sex`  char (2 ) DEFAULT  NULL ,   `age`  int (11 ) DEFAULT  NULL ,   PRIMARY KEY  (`id` ) ) ENGINE =InnoDB  DEFAULT  CHARSET =utf8mb4; INSERT  INTO  `tb_user`  VALUES  ('1' , '小明' , '男' , '21' );INSERT  INTO  `tb_user`  VALUES  ('2' , '小王' , '男' , '22' );INSERT  INTO  `tb_user`  VALUES  ('3' , '小丽' , '女' , '18' );INSERT  INTO  `tb_user`  VALUES  ('4' , '小芳' , '女' , '18' );
 
创建存储过程 在之前创建的mybatis数据库中创建一个插入tb_user表数据的存储过程,SQL脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 drop  procedure  if  exists  insert_user;DELIMITER $$  CREATE  PROCEDURE  insert_user (    OUT  v_id int ,     in  v_name varchar (18 ),     in  v_sex varchar (19 ),     in  v_age int  ) BEGIN 	INSERT  INTO  tb_user (name ,sex,age) VALUES  (v_name,v_sex,v_age); 	SET  v_id=LAST_INSERT_ID (); END $$ DELIMITER ; 
 
存储过程代码详解 以上存储过程代码解释如下:
DELIMITER是MySQL解释器,用于规定SQL语句的结束符,默认情况SQL语句的结束符是分号(;).为了录入存储过程中的SQL语句,我们需要先把默认的结束符(;)换成其他字符,录入结束后再把结束符换回分号. 
在存储过程中使用参数时,除了参数名和参数类型之外,还建议指定参数的mode(模式),可选值为IN、OUT和INOUT三种。
输入参数使用IN, 
输出参数(返回)使用OUT, 
输入输出参数使用 INOUT。 
 
 
LAST_INSERT_ID是 MySQL的函数,和AUTO_INCREMENT属性一起使用,当往带有AUTO_INCREMENT属性字段的表中新增数据时, LAST_INSERT_ID函数返回该字段的值。 
 
命令行调用存储过程 调用示例如下:
1 call  insert_user(@output ,'小王' ,'男' ,22 );
 
第一个参数@output是一个变量,用来接收存储过程的输出. 其三个参数是存储过程的输入.
显示存储过程的输出 select 输出变量名;即可显示存储过程的输出,如下代码所示:
 
运行结果如下:
1 2 3 4 5 6 7 8 9 mysql> call  insert_user(@output,'小王','男',22 ); Database changed mysql> select @output; +---------+ | @output | +---------+ |       5  | +---------+ 1  row in  set 
 
此时tb_user表中的数据如下:
1 2 3 4 5 6 7 8 9 10 11 mysql> select * from tb_user; +----+------+-----+-----+ | id | name | sex | age | +----+------+-----+-----+ |  1  | 小明 | 男  |  21  | |  2  | 小王 | 男  |  22  | |  3  | 小丽 | 女  |  18  | |  4  | 小芳 | 女  |  18  | |  5  | 小王 | 男  |  22  | +----+------+-----+-----+ 5  rows in  set 
 
创建持久化对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package  domain;public  class  User   {    private  Integer id;     private  String name;     private  String sex;     private  Integer age;     public  User ()       {        super ();     }          @Override      public  String toString ()       {        return  "User [id="  + id + ", name="  + name + ", sex="  + sex + ", age="  + age + "]" ;     } } 
 
编写Mapper.xml映射文件 1 2 3 4 5 6 7 8 9 10 11 <insert      id ="inserUser"      parameterType ="domain.User"      statementType ="CALLABLE" >  {    call insert_user(         #{id,mode=OUT,jdbcType=INTEGER},         #{name,mode=IN},         #{sex,mode=IN},         #{age,mode=IN}     ) } </insert > 
 
insert标签调用名为”insert_user“的存储过程完成一个插入数据的操作。调用存储过程时,需要把statementType属性的值设置为”CALLABLE“。 “call“是用来调用存储过程的关键字,需要注意的是,OUT模式的参数必须指定jdbcType,这是因为在IN模式下,MyBatis提供了默认的jdbcType,而在OUT模式下没有提供。 注意id列的参数jdbcType不要写成javaType.
编写mapper接口 1 2 3 4 5 package  mapper;import  domain.User;public  interface  UserMapper   {    void  inserUser (User user)  ; } 
 
编写测试类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package  test;import  domain.User;import  org.apache.ibatis.session.SqlSession;import  fractory.SqlSessionFratoryTools;import  mapper.UserMapper;public  class  inserTest   {    public  static  void  main (String[] args)       {        SqlSession sqlSession = null ;                  sqlSession = SqlSessionFratoryTools.getSqlSession();         try          {                          UserMapper userMapper = sqlSession.getMapper(UserMapper.class);             User user = new  User();             user.setAge(23 );             user.setName("小李" );             user.setSex("男" );                          userMapper.inserUser(user);                          sqlSession.commit();             System.out.println("自动生成的Id:"  + user.getId());         } catch  (Exception e)         {                          sqlSession.rollback();             e.printStackTrace();         } finally          {                          if  (sqlSession != null )             {                 sqlSession.close();             }         }     } } 
 
运行效果 此时tb_user表中的数据如下:
1 2 3 4 5 6 7 8 9 10 11 mysql> select * from tb_user; +----+------+-----+-----+ | id | name | sex | age | +----+------+-----+-----+ |  1  | 小明 | 男  |  21  | |  2  | 小王 | 男  |  22  | |  3  | 小丽 | 女  |  18  | |  4  | 小芳 | 女  |  18  | |  5  | 小王 | 男  |  22  | +----+------+-----+-----+ 5  rows in  set 
 
运行测试类,inserUser()方法将会插入一个用户记录到数据库表中,并输出自动生成的id值。控制台显示如下:
1 2 3 4 DEBUG [main] ==>  Preparing: { call  insert_user( ?, ?, ?, ? ) }  DEBUG [main] ==> Parameters: 小李(String), 男(String), 23 (Integer) DEBUG [main] <==    Updates: 1  自动生成的Id:6  
 
可以看到,MyBatis调用了名为”insert_user“的存储过程,并且传入了4个参数.其中第一个参数id用来接收存储过程的输出.所以尽管我们没有给user对象的id属性复制,但是存储过程插入成功后,id属性的值变成了6. 查询数据库,可以看到tb_user表中插入了一条新的记录,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 mysql> select * from tb_user; +----+------+-----+-----+ | id | name | sex | age | +----+------+-----+-----+ |  1  | 小明 | 男  |  21  | |  2  | 小王 | 男  |  22  | |  3  | 小丽 | 女  |  18  | |  4  | 小芳 | 女  |  18  | |  5  | 小王 | 男  |  22  | |  6  | 小李 | 男  |  23  | +----+------+-----+-----+ 6  rows in  set 
 
原文链接: 10.3 MyBatis调用存储过程 10.3.1插入数据