MyBatis从入门到精通(第3章): MyBatis注解方式的基本使用

MyBatis 注解方式就是将 SQL 语句直接写在DAO层的接口上。

在黑马2018年录制的双元视频课:\08 SSM整合案例【企业权限管理系统】\07.订单操作  有使用mybatis注解进行多表关联查询的案例,在下文会有使用注解的补充说明。

这种方式的优点是 , 对于需求比较简单的系统,效率较高。缺点是 ,当 SQL 有变化时都需要重新编译代码, 一般情况下不建议使用MyBatis的注解方式 。

因此, (原书)本章不会进行深入讲解。 在 MyBatis 注解 SQL 中,最基本的就是@Select 、@Insert 、@Update 和@Delete 四种 。 下面以 RoleMapper 为例,对这几个注解的用法进行讲解 。

-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘角色ID‘,
  `role_name` varchar(50) DEFAULT NULL COMMENT ‘角色名‘,
  `enabled` int(11) DEFAULT NULL COMMENT ‘有效标志‘,
  `create_by` bigint(20) DEFAULT NULL COMMENT ‘创建人‘,
  `create_time` datetime DEFAULT NULL COMMENT ‘创建时间‘,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT=‘角色表‘;

-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (‘1‘, ‘管理员‘, ‘1‘, ‘1‘, ‘2016-04-01 17:02:14‘);
INSERT INTO `sys_role` VALUES (‘2‘, ‘普通用户‘, ‘1‘, ‘1‘, ‘2016-04-01 17:02:34‘);

pom.xml

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

3.1 @Select 注解

在 cn.bjut.example.mapper.RoleMapper 接口中添加如下注解方法 。

package cn.bjut.example.mapper;

import cn.bjut.example.model.SysRole;
import org.apache.ibatis.annotations.Select;

public interface RoleMapper {
    @Select({"select id,role_name roleName, enabled, create_by createBy, create_time createTime from sys_role where id = #{id}"})
    SysRole selectById(Long id);
}

使用注解方式同样需要考虑表字段和 Java 属性字段映射的问题,在第 2 章 中己经讲过 XML方式是如何实现宇段映射的,接下来看一下注解方式是如何实现的 。第一种是通过 SQL 语句使用别名来实现,上面的例子中已经使用过 。 除此之外还有另外两种方式分别是:
  1. 使用mapUnderscoreToCamelCase 配置
  2. 以及使用 resultMap 方式,下面详细说明 。

3.1.1 使用 mapUnderscoreToCamelCase 配置

在数据库中,由于大多数数据库设置不区分大小写 ,因此下画线方式的命名很常见,如 user_name 、 user_email 。在 Java 中, 一般都使用驼峰式命名,如 userName 、 userEmail 。

因为数据库和 Java 中的这两种命名方式很常见,因此 MyBatis 还提供 了 一个全局属性
mapUnderscoreToCamelCase ,通过配置这个属性为 true 可以自动将以下画线方式命名的
数据库列映射到 Java对象的驼峰式命名属性中。这个属性默认为 false ,如果想要使用该功能,
需要在 MyBatis 的配置文件(第 l 章中 的 mybatis-config.xml 文件)中增加如下配置。

    <settings>

        <!-- 其他mybatis配置 -->
        <setting name=" mapUnderscoreToCamelCase" value="true"/>
    </settings>

使用这种配置方式不需要手动指定别名 , MyBatis 字段按照 “下画线转驼峰”的方式 自动

映射,@Select 注解中的 SQL 可以写成如下这种方式。

    @Select("select id,role_name, enabled, create_by, create_time from sys_role where id = #{id}")
    SysRole selectById2(Long id);

3.1.2  使用resultMap方式

XML中的 resultMap 元素有一个对应的 Java 注解@Results ,使用这个注解来实现属性
映射,新增一个 selectById2 方法,代码如下 。

    @Results(id = "roleResultMap", value = {
        @Result(property = "id", column = "id", id = true),
        @Result(property = "roleName", column = "role_name"),
        @Result(property = "enabled", column = "enabled"),
        @Result(property = "createBy", column = "create_by"),
        @Result(property = "createTime", column = "create_time")
    })
    @Select("select id,role_name, enabled, create_by, create_time from sys_role where id = #{id}")
    SysRole selectById2(Long id);

从MyBatis 3.3.1版本开始,@Results注解增加了一个id属性,设置了id属性后,就可以通过id属性引用同一个@Results配置了,

示例代码如上:

如何引用这个@Results呢?新增一个 selectAll方法,代码如下。

    @ResultMap("roleResultMap")
    @Select("select * from sys_role")
    List<SysRole> selectAll();

注意: 使用@ResultMap注解引用即可,当配合着使用XML配置方式的时候,还可以是XML中 <resultMap>元素的id属性值。

在RoleMapperTest 中写出以上示例方法的测试方法。

BaseMapperTest.java

/**
 * 基础测试类
 */
public class BaseMapperTest {
    private static SqlSessionFactory sqlSessionFactory;

    @BeforeClass
    public static void init(){
        try {
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (IOException ignore) {
            ignore.printStackTrace();
        }
    }

    public SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

}

testSelectById、testSelectById2、testSelectAll

方法的测试代码如下:

public class RoleMapperTest extends BaseMapperTest {

@Test
    public void testSelectById(){
        //获取 sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            //获取 RoleMapper 接口
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            //调用 selectById 方法,查询 id = 1 的角色
            SysRole role = roleMapper.selectById(1l);
            //role 不为空
            Assert.assertNotNull(role);
            //roleName = 管理员
            Assert.assertEquals("管理员", role.getRoleName());
        } finally {
            //不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }

    @Test
    public void testSelectById2(){
        //获取 sqlSession
        SqlSession sqlSession = getSqlSession();
        try {
            //获取 RoleMapper 接口
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            //调用 selectById 方法,查询 id = 1 的角色
            SysRole role = roleMapper.selectById2(1l);
            //role 不为空
            Assert.assertNotNull(role);
            //roleName = 管理员
            Assert.assertEquals("管理员", role.getRoleName());
        } finally {
            //不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }

    @Test
    public void testSelectAll(){
        SqlSession sqlSession = getSqlSession();
        try {
            RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
            //调用 selectAll 方法查询所有角色
            List<SysRole> roleList = roleMapper.selectAll();
            //结果不为空
            Assert.assertNotNull(roleList);
            //角色数量大于 0 个
            Assert.assertTrue(roleList.size() > 0);
            //验证下划线字段是否映射成功
            Assert.assertNotNull(roleList.get(0).getRoleName());
        } finally {
            //不要忘记关闭 sqlSession
            sqlSession.close();
        }
    }

}

3.2  @Insert注解

@Insert 注解本身是简单的,但如果需要返回主键的值,情况会变得稍微复杂一些。

3.2.1  不需要返回主键

这个方法和XML中的SQL完全一样,这里不做特别介绍,代码如下。

    @Insert({"insert into sys_role(id, role_name, enabled, create_by, create_time)",
             "values(#{id}, #{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})"})
    int insert(SysRole sysRole);

3.2.2  返回自增主键

新增 insert2方法,代码如下。

    @Insert({"insert into sys_role(role_name, enabled, create_by, create_time)",
    "values(#{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})"})
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert2(SysRole sysRole);

和上面的insert方法相比,insert2方法中的SQL中少了 id一列,注解多了一个

@Options ,我们在这个注解中设置了 useGeneratedKeys 和 keyProperty 属性,用法和XML相同,

当需要配置多个列时,这个注解也提供了 keyColumn 属性,可以像XML中那样配置使用。

3.2.3  返回非自增主键

新增 insert3 方法,代码如下。

    @Insert({"insert into sys_role(role_name, enabled, create_by, create_time)",
     "values(#{roleName}, #{enabled}, #{createBy}, #{createTime, jdbcType=TIMESTAMP})"})
    @SelectKey(statement = "SELECT LAST_INSERT_ID()",
                keyProperty = "id",
                resultType = Long.class,
                before = false)
    int insert3(SysRole sysRole);

使用@SelectKey注解,以下代码是前面XML中配置的 selectKey

        <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>

3.3 @Update 和@Delete注解

    @Update({"update sys_role",
             "set role_name = #{roleName},",
                 "enabled = #{enabled},",
                 "create_by = #{createBy},",
                 "create_time = #{createTime, jdbcType=TIMESTAMP}",
             "where id = #{id}"
        })
    int updateById(SysRole sysRole);

    @Delete("delete from sys_role where id = #{id}")
    int deleteById(Long id);

3.4 多表关联查询的@One 和@Many注解

数据库使用:oracle

图形化界面:PL/SQL Developer

案例的介绍:一个销售旅游产品的网站。

查询的要求:根据订单的ID查询,订单的详细信息 ,这是一个多表关联查询。使用mybatis注解+接口实现SSM整合,把查询结果反馈到JSP。

Product

public class Product {

    private String id; // 主键
    private String productNum; // 编号 唯一
    private String productName; // 名称
    private String cityName; // 出发城市
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm")
    private Date departureTime; // 出发时间
    private String departureTimeStr;  //为了页面显示,数据库里没有的字段
    private double productPrice; // 产品价格
    private String productDesc; // 产品描述
    private Integer productStatus; // 状态 0 关闭 1 开启
    private String productStatusStr;  //为了页面显示,数据库里没有的字段

//部分实体类的代码省略get/set方法
Orders


//订单表的实体类
public class Orders {
    private String id;
    private String orderNum;
    private Date orderTime;
    private String orderTimeStr;
    private int orderStatus;
    private int peopleCount;
    private Product product;
    private List<Traveller> travellers;
    private Member member;
    private Integer payType;
    private String payTypeStr;
    private String orderDesc;
    private String orderStatusStr;
    //============================================
    //通过在SET方法的方法体里直接赋值字符串内容实现
    public String getOrderStatusStr() {
        //订单状态 (0未支付 1已支付)
        if(orderStatus ==0){
            orderStatusStr= "未支付";
        }else if (orderStatus ==1){
            orderStatusStr= "已支付";
        }
        return orderStatusStr;
    }
    //=============================================
    //以下省略一些GET/SET方法




package cn.bjut.ssm.dao;

import cn.bjut.ssm.domain.Traveller;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface ITravellerDao {
    @Select("select * from traveller where id in ( select travellerId from order_traveller where orderId=#{ordersId})")
    public  List<Traveller> findByOrdersId(String ordersId) throws Exception;

}


package cn.bjut.ssm.dao;

import cn.bjut.ssm.domain.Member;
import org.apache.ibatis.annotations.Select;

public interface IMemberDao {

    //通过订单ID查询会员,目的是供订单查询的@Select下@Result注解引用
    @Select("select * from MEMBER where id=#{memberId}")
    Member findById(String memberId) throws Exception;
}
    //通过订单主键ID查询订单详情(多表关联查询)
    @Select("select * from ORDERS where id = #{ordersId}" )  //oracle数据库TABLE名不区分大小写
    @Results({    //为了网页显示的后缀Str类型的实体类属性不用对应出来
            @Result(property ="id",column = "id",id = true ),  //主键声明id = true
            @Result(property ="orderNum",column = "orderMum"),
            @Result(property ="orderTime",column = "orderTime"),
            @Result(property ="orderStatus",column = "orderStatus"),
            @Result(property ="peopleCount",column = "peopleCount"),
            @Result(property ="payType",column = "payType"),
            @Result(property ="orderDesc",column = "orderDesc"),
            //多表关联查询,声明“引用实体类”的封装通过:javaType= Xxx实体类.class
            @Result(property ="product",column = "productId",javaType = Product.class ,one [email protected](select = "cn.bjut.ssm.dao.IProductDao.findById")),
            @Result(property ="member",column = "memberId",javaType = Member.class ,one [email protected](select = "cn.bjut.ssm.dao.IMemberDao.findById")),
            //通过中间表查询多对多关系,返回一个其它实体类的List集合
            @Result(property = "travellers",column ="id",javaType = java.util.List.class,many = @Many(select = "cn.bjut.ssm.dao.ITravellerDao.findByOrdersId"))
    })
    public Orders findById(String ordersId)throws Exception;
 

====================

end

 

原文地址:https://www.cnblogs.com/MarlonKang/p/11491217.html

时间: 2024-11-08 12:33:57

MyBatis从入门到精通(第3章): MyBatis注解方式的基本使用的相关文章

MyBatis从入门到精通(第4章):MyBatis动态SQL

(第4章):MyBatis动态SQL:本章详细介绍了MyBatis最强大的动态SQL功能,通过丰富的示例讲解了各种动态SQL的用法,还提供了动态SQL中常用的OGNL用法. (第4章):MyBatis动态SQL MyBatis 3.5.2版本采用了功能强大的OGNL(Object-Graph Navigation Language)表达式语言,以下是MyBatis的动态SQL在XML中支持的几种标签. if choose(when.otherwise) trim(where.set) forea

MyBatis从入门到精通:第二章数据的创建与插入文件

数据库表的创建: create table sys_user ( id bigint not null auto_increment, user_name varchar(50), user_password varchar(50), user_email varchar(50), user_info text, head_img blob, create_time datetime, primary key(id) ); create table sys_role ( id bigint no

MyBatis从入门到精通(一):MyBatis入门

最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 1. MyBatis简介 ? 2001年,Clinton Begin发起了一个名为iBATIS的开源项目,最初侧重于密码软件的研发,后来发展成为一款基于Java的持久层框架. ? 2004年,Clinton将iBATIS的名字和源码捐赠给了Apache软件基金会. ? 2010年,核心开发团队决定离开Apache软件基金会,并且将iBATIS改名

MyBatis从入门到精通(六):MyBatis动态Sql之if标签的用法

最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解如何使用if标签生成动态的Sql,主要包含以下3个场景: 根据查询条件实现动态查询 根据参数值实现动态更新某些列 根据参数值实现动态插入某些列 1. 使用if标签实现动态查询 假设有这样1个需求:根据用户的输入条件来查询用户列表,如果输入了用户名,就根据用户名模糊查询,如果输入了邮箱,就根据邮箱精确查询,如果同时输入了用户名和邮箱

mybatis从入门到精通(二) 增删查改

mybatis从入门到精通(二) 增删查改 一丶前言 "增删查改"是后台开发的常用操作, 因此, 学习mybatis或者其他orm框架有必要统一学习一下"增删查改". 二丶准备开发环境 使用"mybatis从入门到精通(一) 入门"准备的开发环境 三丶查 -- <select/> UserMapper.java User selectUser(@Param("userId") int userId); UserMa

mybatis从入门到精通(三) 结果映射

mybatis从入门到精通(三) 结果映射 一丶什么是结果映射 结果映射是用于将数据库表字段和实体类中的属性名映射起来, 即究竟是哪个字段名与属性名对应. 映射之后, 即可通过mybatis将从数据库查询的结果转换成对应的实体类对象类型, 除去了人工转换的麻烦. 二丶自动映射 所谓的自动映射, 即是默认java实体类的属性名是驼峰式, 而数据库表字段名是以下划线分隔, 如 属性名userName 与 表字段user_name相对应, 如果是这种简单通用的规则, 即可通过配置mybatis, 使得

MyBatis从入门到精通(十一):MyBatis高级结果映射之一对多映射

最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解MyBatis中如何使用collection标签实现查询结果一对多映射. 1. 使用collection标签 需求:根据用户id查询用户信息的同时获取用户拥有的角色,一个用户可以拥有1个或多个角色. 一般情况下,不建议直接修改数据库表对应的实体类. 所以这里我们延用之前博客中新建的类SysUserExtend,并添加如下代码,如下

MyBatis从入门到精通(十二):使用collection标签实现嵌套查询

最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解使用collection标签实现嵌套查询的方法. 1. 需求升级 在上篇博客中,我们实现了需求:根据用户id查询用户信息的同时获取用户拥有的角色. 因为角色可以拥有多个权限,所以本篇博客我们升级需求为:根据用户id查询用户信息的同时获取用户拥有的角色以及角色包含的权限. 2. 实现方式 因为我们需要使用到权限表的映射,所以我们需要

mybatis从入门到精通(四) 动态SQL

mybatis从入门到精通(四) 动态SQL 一丶简介 Mybatis的强大特性之一是动态SQL, 它可以动态拼接sql语句, 减轻开发的工作量. Mybatis的动态sql标签如下4种类型 1. if 2. choose (when, otherwise) 3. trim (where, set) 4. foreach 二丶<if/> <if/>标签相当于java语言中的if语句, 通过判断是否符合预置条件来拼接sql语句.其中判断条件可以使用ongl表达式, 如e.method