zoukankan      html  css  js  c++  java
  • MyBatis 示例之存储过程

    存储过程在数据库中比较常见,虽然大多数存储过程比较复杂,但是使用 MyBatis 调用时,用法都一样,因此我们这一节使用一个简单的存储过程来了解 MyBatis 中存储过程的使用方法。

    基本准备

    存储过程涉及表 sys_user,建表语句如下。

    DROP TABLE IF EXISTS `sys_user`;
    CREATE TABLE `sys_user` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
      `user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
      `user_password` varchar(50) DEFAULT NULL COMMENT '密码',
      `user_email` varchar(50) DEFAULT 'test@mybatis.tk' COMMENT '邮箱',
      `user_info` text COMMENT '简介',
      `head_img` blob COMMENT '头像',
      `create_time` datetime DEFAULT NULL COMMENT '创建时间',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1035 DEFAULT CHARSET=utf8 COMMENT='用户表';

    准备测试数据如下。

    INSERT INTO `sys_user` VALUES ('1', 'admin', '123456', 'admin@mybatis.tk', '管理员用户', 0x1231231230, '2016-06-07 01:11:12');
    INSERT INTO `sys_user` VALUES ('1001', 'test', '123456', 'test@mybatis.tk', '测试用户', 0x1231231230, '2016-06-07 00:00:00');

    对应实体类SysUser如下:

    /**
     * 用户表
     */
    public class SysUser implements Serializable {
        private static final long serialVersionUID = 1L;
        /**
         * 用户ID
         */
        private Long id;
        /**
         * 用户名
         */
        private String userName;
        /**
         * 密码
         */
        private String userPassword;
        /**
         * 邮箱
         */
        private String userEmail;
        /**
         * 简介
         */
        private String userInfo;
        /**
         * 头像
         */
        private byte[] headImg;
        /**
         * 创建时间
         */
        private Date createTime;
        //省略 getter 和 setter
    }

    建存储过程

    我们先创建如下的存储过程。

    # 第一个存储过程
    # 根据用户 id 查询用户其他信息
    # 方法看着很奇葩,但是展示了多个输出参数
    DROP PROCEDURE IF EXISTS `select_user_by_id`;
    DELIMITER ;;
    CREATE PROCEDURE `select_user_by_id`(
    IN userId BIGINT,
    OUT userName VARCHAR(50),
    OUT userPassword VARCHAR(50),
    OUT userEmail VARCHAR(50),
    OUT userInfo TEXT,
    OUT headImg BLOB,
    OUT createTime DATETIME)
    BEGIN
    # 根据用户 id 查询其他数据
    select user_name,user_password,user_email,user_info,head_img,create_time
    INTO userName,userPassword,userEmail,userInfo,headImg,createTime 
    from sys_user
    WHERE id = userId;
    END
    ;;
    DELIMITER ;

    创建XML方法

    <select id="selectUserById" statementType="CALLABLE" useCache="false">
        {call select_user_by_id(
            #{id, mode=IN}, 
            #{userName, mode=OUT, jdbcType=VARCHAR},
            #{userPassword, mode=OUT, jdbcType=VARCHAR},
            #{userEmail, mode=OUT, jdbcType=VARCHAR},
            #{userInfo, mode=OUT, jdbcType=VARCHAR},
            #{headImg, mode=OUT, jdbcType=BLOB, javaType=_byte[]},
            #{createTime, mode=OUT, jdbcType=TIMESTAMP}
        )}
    </select>

    在调用存储过程的方法中,我们需要把 statementType 设置为 CALLABLE,在使用 select 元素中调用存储过程时,由于存储过程方式不支持 MyBatis 的二级缓存(后面章节会介绍),为了避免缓存配置导致出错,我们直接将 select 元素的 useCache 属性设置为 false

    在存储过程中使用参数时,除了写上必要的属性名外,还必须指定参数的 mode(模式),可选值为 IN、OUT、INOUT 三种,入参使用 IN,出参使用 OUT,输入输出参数使用 INOUT。从上面代码可以轻易看出 IN 和 OUT 的两种模式的区别,那就是 OUT 模式的参数,必须指定 jdbcType。这是因为在 IN 模式下,MyBatis 提供了默认的 jdbcType,在 OUT 模式下没有提供,因此必须指定 jdbcType,另外在使用 Oracle 数据库时,如果入参存在 null 的情况,那么也必须指定 jdbcType

    除了上面提到的这几点外,headImg 还特别设置了 javaType。在 MyBatis 映射的 Java 类中我们都不推荐使用基本类型,但是数据库 BLOB 类型对应的 Java 类型我们通常都是写成 byte[] 字节数组,因为 byte[] 数组不会有默认值的问题,所以不会影响我们一般的使用。但是在不指定 javaType的情况下,MyBatis 默认使用 Byte 类型。由于我们使用的 byte 是基本类型,所以设置 javaType的时候,基本类型要使用带下划线方式的类型,在这里就是 byte[]_byte 对应的是基本类型,byte 对应的是 Byte 类型,在使用 javaType 时一定要注意。

    创建接口

    /**
     * 使用存储过程查询用户信息
     * 
     * @param user
     * @return
     */
    void selectUserById(SysUser user);

    因为我们这个存储过程没有返回值(不要和出参混淆),所以我们返回值类型使用 void,如果你把返回值设置为 SysUser 或 List<SysUser> 也不会报错,但是任何时候返回值都是 null

    编写测试

    @Test
    public void testSelectUserById(){
        SqlSession sqlSession = //获取SqlSession的方法
        try {
            //这个例子的XML和接口都定义在UserMapper中
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            SysUser user = new SysUser();
            user.setId(1L);
            userMapper.selectUserById(user);
            Assert.assertNotNull(user.getUserName());
            System.out.println("用户名:" + user.getUserName());
        } finally {
            sqlSession.close();
        }
    }

    执行测试,输出如下日志:

    DEBUG [main] - ==>  Preparing: {call select_user_by_id( ?, ?, ?, ?, ?, ?, ? )} 
    DEBUG [main] - ==> Parameters: 1(Long)
    用户名:admin

    使用出参方式的时候,通常情况下我们会使用对象中的属性接收出参的值,或者使用 Map 类型方法入参接收返回值。这两种情况下有很大的区别。当我们使用 POJO 对象接收出参时,我们必须保证所有出参在 POJO 中都有对应的属性存在,否则就会抛出类似 “Could not set property 'xxx'”的错误,这是由于 POJO 对象中不存在出参对应的 setter 方法导致的。使用 Map 类型时就不需要必须存在该属性,当 Map 接收了存储过程的出参时,可以通过 Map 对象的 get("属性名") 方法获取出参的值。

    错误提示

    除了上面提到的错误外,当你在执行存储过程时,还可能会遇到下面的错误:

    Parameter number x is not an OUT parameter

    这个错误可能的原因是因为你调用的存储过程不存在,或者 MyBatis 中写的出参和数据库存储过程的出参对应不上而导致的。

  • 相关阅读:
    .NET WinForm 状态栏添加分隔符
    使用 MMC / IE 查看证书
    配置IIS在64位Windows上运行 32 位 ASP.NET 应用程序
    WCF部署到IIS:证书必须具有能够进行密钥交换的私钥,该进程必须具有访问私钥的权限
    PB6 调用 .net Web Service
    .NET程序加壳 — 之动态加载程序集
    statusStrip 状态条 toolStripStatusLabel 居右显示
    C# 使用 Stopwatch 测量代码运行时间
    Application_Start 事件中使用 Response.Redirect
    解决IIS中部署WCF时,访问.svc文件的404错误问题
  • 原文地址:https://www.cnblogs.com/wpcnblog/p/11880807.html
Copyright © 2011-2022 走看看