【MyBatis】 MyBatis修炼之三 MyBatis XML方式的基本用法

我们通过一个简单的权限控制需求(RABC,Role-Based Access Control,基于角色的访问控制),来讲解通过XML方式配置MyBatis的基本用法(即select、update、insert、delete等操作的XML配置方式)。

工具

JDK 1.6及以上版本
MyBatis 3.30版本
MySQL 6.3版本
Eclipse4 及以上版本
Apache Maven 构建工具


项目源码下载地址:https://github.com/JFAlex/MyBatis/tree/master/MyBatis_No.3/alex


权限控制需求

一个用户拥有若干个角色,一个角色拥有若干权限,权限就是对某个资源的(模块)的某种操作(增、删、改、查),这样就构成了“用户--角色--权限”的授权模型。在这种模型中,用户与角色之间、角色与权限之间,一般是多对多的关系。

创建数据库表

首先我们需要创建五个表:用户表、角色表、权限表、用户角色关系表、角色权限关系表。在已经创建好的mybatis数据库中执行如下SQL脚本:

#创建数据库,并制定编码格式为UTF-8
CREATE DATABASE mybatis DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

#切换数据库到mybatis
use mybatis;

#创建用户表
create table sys_user(
    id bigint not null auto_increment comment '用户ID',
    user_name varchar(50) comment '用户名',
    user_password varchar(50) comment '密码',
    user_email varchar(50) comment '邮箱',
    user_info text comment '简介',
    head_img blob comment '头像',
    create_time datetime comment '创建时间',
    primary key (id)
    
);
alter table sys_user comment '用户表';

#创建角色表
create table sys_role(
    id bigint not null auto_increment comment '角色ID',
    role_name varchar(50) comment '角色名',
    enabled int comment '有效标志',
    create_by bigint comment '创建人',
    create_time datetime comment '创建时间',
    primary key (id)
);
alter table sys_role comment '角色表';

#创建权限表
create table sys_privilege(
    id bigint not null auto_increment comment '权限ID',
    privilege_name varchar(50) comment '权限名称',
    privilege_uri varchar(200) comment '权限URL',
    primary key (id)
);
alter table sys_privilege comment '权限表';

#创建用户角色关系表
create table sys_user_role(
    user_id bigint comment '用户ID',
    role_id bigint comment '角色ID'
);
alter table sys_user_role comment '用户角色关联表';

#创建角色权限关系表
create table sys_role_privilege(
    role_id bigint comment '角色ID',
    privilege bigint comment '权限ID'
);
alter table sys_role_privilege comment '角色权限关联表';

##测试数据
insert into sys_user(id,user_name, user_password, user_email, user_info, head_img, create_time) 
values(1,'admin','123456','admin@mybais.alex','管理员',null,'2017-8-09 15:26:52'),
(2,'test','123456','test@mybais.alex','测试用户',null,'2017-8-09 15:27:30');

insert into sys_role(id,role_name, enabled, create_by, create_time) 
values(1,'管理员','1','1','2017-8-09 15:26:52'),(2,'普通用户','1','1','2017-8-09 15:26:52');

insert into sys_privilege(id,privilege_name, privilege_uri)
values(1,'用户管理','/users'),(2,'角色管理','/roles'),(3,'系统日志','/logs'),(4,'人员维护','/persons'),(5,'部门维护','/companies');

insert into sys_user_role values(1,1),(1,2),(2,2);
insert into sys_role_privilege values(1,1),(1,2),(1,3),(2,4),(2,5);

此处没有创建表之间的外键关系。对于表之间的关系,我们可以通过业务逻辑来进行限制。

创建实体类

MyBatis默认遵循“下划线转驼峰”命名方式,所以在创建实体类时一般都按照这种方式进行创建。而具体采用什么命名方式并不重要,在我们使用对象的时候,可以通过resultMap对数据库的列和类的字段配置隐射关系。

用户类SysUser

package mybatis.simple.model;

import java.util.Arrays;
import java.util.Date;

public class SysUser {

    private Long id;
    private String userName;
    private String userPassword;
    private String userEmail;
    private String userInfo;
    private byte[] headImg;
    private Date createTime;

    public SysUser() {
        super();
    }

    public SysUser(Long id, String userName, String userPassword, String userEmail, String userInfo, byte[] headImg,
            Date createTime) {
        super();
        this.id = id;
        this.userName = userName;
        this.userPassword = userPassword;
        this.userEmail = userEmail;
        this.userInfo = userInfo;
        this.headImg = headImg;
        this.createTime = createTime;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    public String getUserInfo() {
        return userInfo;
    }

    public void setUserInfo(String userInfo) {
        this.userInfo = userInfo;
    }

    public byte[] getHeadImg() {
        return headImg;
    }

    public void setHeadImg(byte[] headImg) {
        this.headImg = headImg;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "SysUser [id=" + id + ", userName=" + userName + ", userPassword=" + userPassword + ", userEmail="
                + userEmail + ", userInfo=" + userInfo + ", headImg=" + Arrays.toString(headImg) + ", createTime="
                + createTime + "]";
    }

}

角色类SysRole

package mybatis.simple.model;

import java.sql.Date;

public class SysRole {
    private Long id;
    private String role_name;
    private Integer enabled;
    private Long create_by;
    private Date create_time;

    public SysRole() {
        super();
    }

    public SysRole(Long id, String role_name, Integer enabled, Long create_by, Date create_time) {
        super();
        this.id = id;
        this.role_name = role_name;
        this.enabled = enabled;
        this.create_by = create_by;
        this.create_time = create_time;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getRole_name() {
        return role_name;
    }

    public void setRole_name(String role_name) {
        this.role_name = role_name;
    }

    public Integer getEnabled() {
        return enabled;
    }

    public void setEnabled(Integer enabled) {
        this.enabled = enabled;
    }

    public Long getCreate_by() {
        return create_by;
    }

    public void setCreate_by(Long create_by) {
        this.create_by = create_by;
    }

    public Date getCreate_time() {
        return create_time;
    }

    public void setCreate_time(Date create_time) {
        this.create_time = create_time;
    }

    @Override
    public String toString() {
        return "SysRole [id=" + id + ", role_name=" + role_name + ", enabled=" + enabled + ", create_by=" + create_by
                + ", create_time=" + create_time + "]";
    }

}

权限类SysPrivilege

package mybatis.simple.model;

public class SysPrivilege {

    private Long id;
    private String privilege_name;
    private String privilege_uri;

    public SysPrivilege() {
        super();
    }

    public SysPrivilege(Long id, String privilege_name, String privilege_uri) {
        super();
        this.id = id;
        this.privilege_name = privilege_name;
        this.privilege_uri = privilege_uri;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getPrivilege_name() {
        return privilege_name;
    }

    public void setPrivilege_name(String privilege_name) {
        this.privilege_name = privilege_name;
    }

    public String getPrivilege_uri() {
        return privilege_uri;
    }

    public void setPrivilege_uri(String privilege_uri) {
        this.privilege_uri = privilege_uri;
    }

    @Override
    public String toString() {
        return "SysPrivilege [id=" + id + ", privilege_name=" + privilege_name + ", privilege_uri=" + privilege_uri
                + "]";
    }

}

用户角色关系类SysUserRole

package mybatis.simple.model;

public class SysUserRole {
    private Long user_id;
    private Long role_id;

    public SysUserRole() {
        super();
    }

    public SysUserRole(Long user_id, Long role_id) {
        super();
        this.user_id = user_id;
        this.role_id = role_id;
    }

    public Long getUser_id() {
        return user_id;
    }

    public void setUser_id(Long user_id) {
        this.user_id = user_id;
    }


    public Long getRole_id() {
        return role_id;
    }

    public void setRole_id(Long role_id) {
        this.role_id = role_id;
    }

    @Override
    public String toString() {
        return "SysUserRole [user_id=" + user_id + ", role_id=" + role_id + "]";
    }
}

角色权限关系类

package mybatis.simple.model;

public class SysRolePrivilege {
    private Long role_id;
    private Long privilege;

    public SysRolePrivilege() {
        super();
    }

    public SysRolePrivilege(Long role_id, Long privilege) {
        super();
        this.role_id = role_id;
        this.privilege = privilege;
    }

    public Long getRole_id() {
        return role_id;
    }

    public void setRole_id(Long role_id) {
        this.role_id = role_id;
    }

    public Long getPrivilege() {
        return privilege;
    }

    public void setPrivilege(Long privilege) {
        this.privilege = privilege;
    }

    @Override
    public String toString() {
        return "SysRolePrivilege [role_id=" + role_id + ", privilege=" + privilege + "]";
    }

}

在完成上面5个实体类的创建之后,下面我们开始MyBatis XML方式的基本用法。

使用XML方式

MyBatis的真正强大之处在于它的映射语句,由于他的映射语句异常强大,映射器的XML文件就显得相对简单。而MyBatis3.0相比2.0版本的一个最大变化,就是支持使用接口的来调用方法。

在【MyBatis修炼之二】中我们使用的是SqlSession通过命名空间调用MyBatis方法,我们需要用到命名空间和方法id组成的字符串来调用相应的方法。而当参数多于1个的时候,需要将参数放到一个Map对象中。通过Map传递多个参数,使用起来很不方便。

使用接口调用的方式就会方便很多,MyBatis使用Java的动态代理可以直接通过接口来调用相应的方法,不需要提供接口的实现类,并且也不需要使用SqlSession以通过命名空间间接调用。同时,当有多个参数时,可以通过在参数之前添加@Param("fieldName")设置参数的名字,这样我们就可以不用手动构造Map参数了,尤其是在Spring中使用的时候,可以配置为自动扫描所有的接口类,直接将接口注入需要用到的地方。

接下来我们便开始使用MyBatis的XML方式。
首先,在src/main/resource的mybatis.simple.mapper目录下创建和我们创建的5个表对应的XML文件,分别为UserMapper.xml、RoleMapper.xml、PrivilegeMapper.xml、UserRoleMapper.xml、RolePrivilegeMapper.xml,然后在src/main/java下面创建包mybatis.simple.mapper,接着在该包下创建XML文件对应的接口类,分别为UserMapper.java、RoleMapper.java、PrivilegeMapper.java、UserRoleMapper.java、RolePrivilegeMapper.java。
下面以用户表对应的Mapper接口UserMapper.java为例进行说明。

package mybatis.simple.mapper;

public interface UserMapper {
    

}

现在这些文件都是空的,后续使用的时候我们将陆续向其中添加接口方法。创建了所有的接口文件之后,打开UserMapper.xml文件,并录入一下内容

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mybatis.simple.mapper.UserMapper">

</mapper>

我们特别需要注意的地方是<mapper>根标签namespace属性。当Mapper接口和XML文件关联的时候,命名空间namespace的值就需要配置成接口的权限定名称(包名+接口类名),MyBatis内部将通过这个值将接口和XML关联在一起。按照相同的方法创建另外4个Mapper.xml文件。准备好这些XML映射文件后,我们需要在mybatis-config.xml配置文件中的mappers元素中配置所有的mapper,部分配置代码如下。

  <mappers>
      <mapper resource="mybatis/simple/mapper/CountryMapper.xml"/>
      <mapper resource="mybatis/simple/mapper/UserMapper.xml"/>
      <mapper resource="mybatis/simple/mapper/RoleMapper.xml"/>
      <mapper resource="mybatis/simple/mapper/PrivilegeMapper.xml"/>
      <mapper resource="mybatis/simple/mapper/UserRoleMapper.xml"/>
      <mapper resource="mybatis/simple/mapper/RolePrivilegeMapper.xml"/>
  </mappers>

这种配置方式需要将所有的映射文件一一列举出来,如果增加了新的映射文件,还需要在此处进行配置,操作起来比较麻烦,因为此处所有的XML映射文件都多有对应的Mapper接口,所有还有一种更简单的配置方式:

    <mappers>
        <package name="mybatis.simple.mapper"/>
    </mappers>

这种配置会先查找mybatis.simple.mapper包下的所有接口,然后循环对接口进行如下操作:
① 判断接口对应的命名空间是否已经存在,如果存在就抛出异常,不存在就继续进行接下来的操作。
② 加载接口对应的XML映射文件,将接口权限定名转换为路径,例如,将接口mybatis.simple.mapper.UserMapper转换为mybatis/simple/mapper/UserMapper.xml,以.xml为后缀搜索XML资源,如果找打就解析XML。
③ 处理接口中的注解方法。
注意: 使用Mapper接口包名批量加载的方式时,需要将Mapper接口类名和Mapper.xml映射文件名称保持一致并且包名一致(Mapper.xml可以放在src/main/resource目录下,但是需要和接口类的包名保持一致,Mapper.xml也可以和接口类在同一个包下),因此直接配置接口包名,就可以自动扫描包下的接口和XML映射文件

完整mybatis-config.xml文件如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
<configuration>
    
    <!-- 配置指定使用LOG4J输出日志 -->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    
    <!-- 配置包的别名,这样我们在mapper中定义时,就不需要使用类的全限定名称,只需要使用类名即可 -->
    <typeAliases>
        <package name="mybatis.simple.model"/>
    </typeAliases>
    
    <!-- 数据库配置 -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

    <!-- mybatis的SQL语句和映射配置文件 -->
    <mappers>
        <package name="mybatis.simple.mapper"/>
    </mappers>

</configuration>

select用法

我们执行查询操作,使用MyBatis,我们只需要在XML中添加select元素,然后写上SQL语句,然后再做一些简单的配置,就可以将查询的结果直接映射到对象中。

详细说明:XML方式的基本用法(SELECT)

insert用法

和select相比,insert要简单的多。只有让他返回主键时,由于不同数据库的主键生成方式不同,这种情况下会有一些复杂。

详细说明:XML方式的基本用法(INSERT)

update、delete用法

详细说明:XML方式的基本用法(UPDATE、DELETE)

特别注意:
不论是SELECT、INSERT、UPDATE还是DELETE,XML配置中的SQL语句结尾都不能添加分号。
不能添加分号……不能添加分号……不能添加分号……


项目源码下载地址:https://github.com/JFAlex/MyBatis/tree/master/MyBatis_No.3/alex


上一篇: 【MyBatis】MyBatis修炼之二 Maven项目配置MyBatis连接mySQL

下一篇: 【MyBatis】 MyBatis修炼之四 MyBatis XML方式的基本用法(SELECT)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容