MyBatis from entry to the master (B): MyBatis XML way of basic usage of Select

Liuzeng Hui teacher recently read the book "MyBatis from entry to the master," a book, rewarding, so the learning process of their own output in a blog format, if wrong, please correct me, as to help you, honored!

1. clear demand

Mentioned in the book needs is a role-based access control requirements (RBAC, namely Role-Based Access Control), referred to rights management, I believe everyone is familiar with, because most of the rights management systems are needed, and I one of the company responsible for the system is the system of privileges, and design ideas mentioned in the book about the same, roughly described as follows:

1) point for managing resource permissions to control authority, such as a page, a button.

2) create a role, assign permissions to some point to this role, such as rights to all pages of the commodity module.

3) Create a new user, the user is assigned to certain roles.

Data diagram shown below:

2. Data Preparation

First, execute the following script to create the image above five tables: a user table, table role, authority table, table associated with user roles, role permissions associated table.

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_url 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_id BIGINT COMMENT '权限ID'
);
ALTER TABLE sys_role_privilege COMMENT '角色权限关联表';

Then execute the following script to add test data:

INSERT INTO sys_user VALUES (1,'admin','123456','[email protected]','管理员',NULL,current_timestamp);
INSERT INTO sys_user VALUES (1001,'test','123456','[email protected]','测试用户',NULL,current_timestamp);

INSERT INTO sys_role VALUES (1,'管理员',1,1,current_timestamp);
INSERT INTO sys_role VALUES (2,'普通用户',1,1,current_timestamp);

INSERT INTO sys_user_role VALUES (1,1);
INSERT INTO sys_user_role VALUES (1,2);
INSERT INTO sys_user_role VALUES (1001,2);

INSERT INTO sys_privilege VALUES (1,'用户管理','/users');
INSERT INTO sys_privilege VALUES (2,'角色管理','/roles');
INSERT INTO sys_privilege VALUES (3,'系统日志','/logs');
INSERT INTO sys_privilege VALUES (4,'人员维护','/persons');
INSERT INTO sys_privilege VALUES (5,'单位维护','/companies');

INSERT INTO sys_role_privilege VALUES (1,1);
INSERT INTO sys_role_privilege VALUES (1,2);
INSERT INTO sys_role_privilege VALUES (1,3);
INSERT INTO sys_role_privilege VALUES (2,4);
INSERT INTO sys_role_privilege VALUES (2,5);

3. Create entity classes

Create five tables corresponding to the package entity classes sequentially com.zwwhnly.mybatisaction.model:

package com.zwwhnly.mybatisaction.model;

import java.util.Date;

/**
 * 用户表
 */
public class SysUser {
    /**
     * 用户ID
     */
    private Long id;

    /**
     * 用户名
     */
    private String userName;

    /**
     * 密码
     */
    private String userPassword;

    /**
     * 邮箱
     */
    private String userEmail;

    /**
     * 简介
     */
    private String userInfo;

    /**
     * 头像
     */
    private byte[] headImg;

    /**
     * 创建时间
     */
    private Date createTime;

    // 按Alt+Insert快捷键生成get和set方法
}
package com.zwwhnly.mybatisaction.model;

import java.util.Date;

/**
 * 角色表
 */
public class SysRole {
    /**
     * 角色ID
     */
    private Long id;

    /**
     * 角色名
     */
    private String roleName;

    /**
     * 有效标志
     */
    private Integer enabled;

    /**
     * 创建人
     */
    private Long createBy;

    /**
     * 创建时间
     */
    private Date createTime;
    
    // 按Alt+Insert快捷键生成get和set方法
}

You can refer to a similar naming create SysPrivilege.java, SysUserRole.java, SysRolePrivilege.java.

Can also be downloaded at the source as the source address of the end of the text provided.

Precautions:

1) MyBatis default follow the "underline turn hump" named.

As sys_user entity class corresponding to the table name Sys_User, user_name database field corresponding entity class field is userName.

2) Do not use Java primitive types in the entity class, basic types include byte, int, short, long, float, doubule, char, boolean.

Because Java basic types have default values, such as the presence of private int age in a class; while field, age default value 0, it is not possible to meet the case where the null of age, age = null if used, the total result! is ture, will lead to some hidden bug.

4. Create a file Mapper.xml

com under src / main / resources of / in order to create a five Mapper.xml file corresponding to the table under zwwhnly / mybatisaction / mapper directory.

In order to follow-up more quickly create Mapper.xml file, we can add the template, follow these steps:

The figure above content box, enter the following:

<?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>
</mapper>

Then select the directory shown, right new file, as shown below:


Just generated SysUserMapper.xml reads as follows:

<?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>
</mapper>

We just need to give mapper Tags Add a namespace property:

<?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="com.zwwhnly.mybatisaction.mapper.SysUserMapper">
</mapper>

Creating SysRoleMapper.xml, SysPrivilegeMapper.xml, SysUserRoleMapper.xml and SysRolePrivilegeMapper.xml turn in the same way.

Once created, open mybatis-config.xml file we created in Part blog, modify Content of the node is:

<mappers>
    <mapper resource="com/zwwhnly/mybatisaction/mapper/CountryMapper.xml"/>
    <mapper resource="com/zwwhnly/mybatisaction/mapper/SysUserMapper.xml"/>
    <mapper resource="com/zwwhnly/mybatisaction/mapper/SysRoleMapper.xml"/>
    <mapper resource="com/zwwhnly/mybatisaction/mapper/SysPrivilegeMapper.xml"/>
    <mapper resource="com/zwwhnly/mybatisaction/mapper/SysUserRoleMapper.xml"/>
    <mapper resource="com/zwwhnly/mybatisaction/mapper/SysRolePrivilegeMapper.xml"/>
</mappers>

This way, the most obvious drawback is that, if we follow the Mapper.xml new file, still need to modify the file, very bad maintenance, so we modified the following configuration to configure a package name:

<mappers>
    <package name="com.zwwhnly.mybatisaction.mapper"/>
</mappers>

After editing, run unit tests CountryMapperTest in the blog post, the report found that the implementation of the following error:

The reason given is that the blog post, we did not create the corresponding interface CountryMapper.xml file, using the name of the package configuration, you need to create, so the solution is in src / main / java New Package com.zwwhnly. under mybatisaction.mapper, and new interfaces CountryMapper in the packet, then add in the interface method selectAll ().

package com.zwwhnly.mybatisaction.mapper;

import com.zwwhnly.mybatisaction.model.Country;

import java.util.List;

public interface CountryMapper {
    /**
     * 查询全部国家
     *
     * @return
     */
    List<Country> selectAll();
}

5. Create Mapper Interface

Com.zwwhnly.mybatisaction.mapper find the package under src / main / java directory, create an XML file corresponding interface class in this package, namely SysUserMapper.java, SysRoleMapper.java, SysPrivilegeMapper.java, SysUserRoleMapper.java, SysRolePrivilegeMapper. java.

这里只展示下SysUserMapper.java的代码:

package com.zwwhnly.mybatisaction.mapper;

public interface SysUserMapper {
    
}

注意事项:当Mapper接口和XML文件关联的时候,命名空间namespace的值需要配置成接口的全限定名称,MyBatis内部就是通过这个值将接口和XML关联起来的。

例如SysUserMapper.xml中配置的namespace就com.zwwhnly.mybatisaction.mapper.SysUserMapper

6. select用法

6.1 查询单条数据

假设我们需要通过id查询用户的信息,首先,我们需要打开SysUserMapper.java接口定义方法:

/**
 * 通过id查询用户
 *
 * @param id
 * @return
 */
SysUser selectById(Long id);

然后打开对应的SysUserMapper.xml文件添加如下内容:

<resultMap id="sysUserMap" type="com.zwwhnly.mybatisaction.model.SysUser">
    <id property="id" column="id"/>
    <result property="userName" column="user_name"/>
    <result property="userPassword" column="user_password"/>
    <result property="userEmail" column="user_email"/>
    <result property="userInfo" column="user_info"/>
    <result property="headImg" column="head_img" jdbcType="BLOB"/>
    <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
</resultMap>

<select id="selectById" resultMap="sysUserMap">
    SELECT * FROM sys_user WHERE id = #{id}
</select>

说明:

1)MyBatis通过select标签的id属性值和接口的名称进行关联。

2)标签的id属性值不能出现英文句号"."。

3)标签的id属性值在同一个命名空间下不能重复。

4)因为接口方法是可以重载的,所以接口中可以出现多个同名但参数不同的方法,但是XML中id的值不能重复,因此接口中的所有同名方法会对应着XML中的同一个id的方法。

为了验证第2点,我们将selectById修改成select.ById:

<select id="select.ById" resultMap="sysUserMap">
    SELECT * FROM sys_user WHERE id = #{id}
</select>

此时如果调用该方法,会报如下错误:

为了验证第3点,我们将XML内容修改为如下:

<select id="selectById" resultMap="sysUserMap">
    SELECT * FROM sys_user WHERE id = #{id}
</select>
<select id="selectById" resultMap="sysUserMap">
    SELECT * FROM sys_user WHERE id = #{id}
</select>

此时如果调用该方法,会报如下错误:

XML 代码讲解:

  • select:映射查询语句使用的标签。
  • id:查询语句的唯一标识符,可用来代表这条语句。
  • resultMap:用于设置数据库返回列和Java对象的映射关系。
  • SELECT * FROM sys_user WHERE id = #{id}是查询语句。
  • {id}:MyBatis SQL中使用预编译参数的一种方式,大括号中的id代表传入的参数名。

resultMap标签用于配置Java对象的属性和查询结果列的对应关系,通过resultMap中配置的column和property可以将查询列的值映射到type对象的属性上。

上面查询语句用到的resultMap标签讲解:

  • id:必填且唯一。select标签resultMap属性的值为此处id设置的值。
  • type:必填。用于配置查询列所映射到的Java对象模型。
  • column:从数据库中得到的列名或者列的别名。
  • property:要映射到的列结果的属性,即Java对象模型的属性。
  • jdbcType:列对应的数据库类型。

6.2 查询多条数据

假设我们需要查询所有用户的信息,首先,我们需要打开SysUserMapper.java接口定义方法:

/**
 * 查询全部用户
 *
 * @return
 */
List<SysUser> selectAll();

然后打开对应的SysUserMapper.xml文件添加如下内容:

<select id="selectAll" resultType="com.zwwhnly.mybatisaction.model.SysUser">
    SELECT id,
           user_name     userName,
           user_password userPassword,
           user_email    userEmail,
           user_info     userInfo,
           head_img      headImg,
           create_time   createTime
    FROM sys_user
</select>

注意事项:这里我们并没有使用resultMap属性来设置要返回结果的类型,而是通过resultType属性直接指定

要返回结果的类型,使用此种方式需要设置查询列的别名,别名要和resultType指定对象的属性名保持一致,

进而实现自动映射。

MyBatis提供了一个全局属性mapUnderscoreToCamelCase,将这个属性的值设置为ture可以自动将以下划线命名的数据库列映射到Java对象的驼峰式命名属性中。

那么如何打开呢?

方法是打开我们在上篇博客中新建的mybatis-config文件,在settings节点添加如下配置:

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

此时,前面的selectAll语句可以简化为如下。

<select id="selectAll" resultType="com.zwwhnly.mybatisaction.model.SysUser">
    SELECT id,
           user_name,
           user_password,
           user_email,
           user_info,
           head_img,
           create_time
    FROM sys_user
</select>

7. 单元测试

新建基础测试类BaseMapperTest,代码如下。

package com.zwwhnly.mybatisaction.mapper;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.BeforeClass;

import java.io.IOException;
import java.io.Reader;

/**
 * 基础测试类
 */
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 e) {
            e.printStackTrace();
        }
    }

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

将上篇博客中的CountryMapperTest类代码修改为如下。

package com.zwwhnly.mybatisaction.mapper;

import com.zwwhnly.mybatisaction.model.Country;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class CountryMapperTest extends BaseMapperTest {

    @Test
    public void testSelectAll() {
        SqlSession sqlSession = getSqlSession();

        try {
            List<Country> countryList = sqlSession.selectList("com.zwwhnly.mybatisaction.mapper.CountryMapper.selectAll");
            printCountryList(countryList);
        } finally {
            sqlSession.close();
        }
    }

    private void printCountryList(List<Country> countryList) {
        for (Country country : countryList) {
            System.out.printf("%-4d%4s%4s\n", country.getId(), country.getCountryname(), country.getCountrycode());
        }
    }
}

修改点:

1)继承基础测试类BaseMapperTest,调用基类getSqlSession()方法即可获取SqlSession对象,实现代码重用。

2)selectList()方法的参数值由selectAll修改为com.zwwhnly.mybatisaction.mapper.CountryMapper.selectAll,

因为在SysUserMapper中也添加了一个selectAll()方法,selectAll不再唯一,因此调用时必须带上namespace。

参考CountryMapperTest测试类新建SysUserMapperTest测试类,代码如下。

package com.zwwhnly.mybatisaction.mapper;

import com.zwwhnly.mybatisaction.model.SysUser;
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.Test;

import java.util.List;

public class SysUserMapperTest extends BaseMapperTest {
    @Test
    public void testSelectById() {
        SqlSession sqlSession = getSqlSession();

        try {
            SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);

            SysUser sysUser = sysUserMapper.selectById(1L);
            Assert.assertNotNull(sysUser);

            Assert.assertEquals("admin", sysUser.getUserName());
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void testSelectAll() {
        SqlSession sqlSession = getSqlSession();

        try {
            SysUserMapper sysUserMapper = sqlSession.getMapper(SysUserMapper.class);

            List<SysUser> sysUserList = sysUserMapper.selectAll();

            Assert.assertNotNull(sysUserList);
            Assert.assertTrue(sysUserList.size() > 0);
        } finally {
            sqlSession.close();
        }
    }
}

运行测试类代码,测试通过,输出日志如下所示。

DEBUG [main] - ==> Preparing: SELECT id, user_name, user_password, user_email, user_info, head_img, create_time FROM sys_user

DEBUG [main] - ==> Parameters:

TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time

TRACE [main] - <== Row: 1, admin, 123456, [email protected], < >, < >, 2019-06-27 18:21:07.0

TRACE [main] - <== Row: 1001, test, 123456, [email protected], < >, < >, 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 2

DEBUG [main] - ==> Preparing: SELECT * FROM sys_user WHERE id = ?

DEBUG [main] - ==> Parameters: 1(Long)

TRACE [main] - <== Columns: id, user_name, user_password, user_email, user_info, head_img, create_time

TRACE [main] - <== Row: 1, admin, 123456, [email protected], < >, < >, 2019-06-27 18:21:07.0

DEBUG [main] - <== Total: 1

8. 源码

源码地址:https://github.com/zwwhnly/mybatis-action.git,欢迎下载。

9. 参考

刘增辉《MyBatis从入门到精通》

IntelliJ IDEA中创建xml文件

10. 最后

欢迎扫描下方二维码关注微信公众号:「申城异乡人」,博客内容会同步更新。

Guess you like

Origin www.cnblogs.com/zwwhnly/p/11118566.html