【Mybatis实战】02——XML方式的基本用法

一、一个简单的权限控制需求配置

设定了一个简单的权限控制需求,采用RBAC(Role-Based Access Control ,基于角色的访问控制)方式。

步骤1:配置环境

步骤1:

  1. 创建数据库表
  2. 创建实体类
  3. 创建接口类(eq:UserMapper.class)
  4. 创建接口类的mapper XML(eq:UserMapper.xml)
  5. 配置MybatisUtils 配置类
  6. 编写select、insert、update、delete等CRUD语句



1. 创建数据库表


-- 用户表
create table `sys_user`(
	id bigint not null auto_increment primary key 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 '创建时间'
)engine = innodb  charset=utf8


insert into `sys_user` values('1','admin','123456','admin@mybatis','管理员',null,'2022-08-11 15:00:00');
insert into `sys_user` values('1001','test','123456','test@mybatis','测试用户',null,'2022-08-11 15:04:00');


-- 角色表
create table sys_role (
	id bigint not null auto_increment primary key comment '角色ID',
	role_name varchar(50) comment '用户名',
	enabled int comment '有效标志',
	create_by bigint comment '创建人',
	create_time datetime comment '创建时间'
)engine = innodb  charset=utf8




insert into `sys_role` values('1','管理员','1','1','2022-08-11 15:10:00');
insert into `sys_role` values('2','普通用户','1','1','2022-08-11 15:14:00');


-- 权限表
create table sys_privilege (

	id bigint not null auto_increment primary key comment '权限ID',
	privilege_name varchar(50) comment '权限名称',
	privilege_url varchar(200) comment '权限URL'
)engine = innodb  charset=utf8






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');




-- 用户角色关联表
create table sys_user_role(
	user_id bigint comment '用户ID',
	role_id bigint comment '角色ID'
)


insert into `sys_user_role` values('1','1');
insert into `sys_user_role` values('1','2');
insert into `sys_user_role` values('1001','2');



-- 角色权限关联表

create table sys_role_privilege (
	role_id bigint comment '角色ID',
	privilege_id bigint comment '权限ID'
)


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




2. 创建实体类

因为Mybatis 默认是遵循 下划线转驼峰命名方式的,所以在创建实体类时一般都按照这种方式进行创建

共有5个实体表

  • 用户表:SysUser.class
  • 角色表:SysRole.class
  • 权限表:SysPrivilege.class
  • 用户角色表:SysUserRole.class
  • 角色权限表:SysRolePrivilege.class

用户表:SysUser.class

public class SysUser {

    private Long id;

    private String userName;

    private String userPassword;

    private String userEmail;

    private String userInfo;

    private byte[] headImg;

    private Date createTime;


   // 省略get()set() toString()方法
}

角色表:SysRole.class

public class SysRole {

    private Long id;

    private String roleName;

    private Long createBy;

    private Date createTime;

    private SysUser user;

   // 省略get()set() toString()方法
}

权限表:SysPrivilege.class

public class SysPrivilege {

    private Long id;

    private String privilegeName;

    private String privilegeUrl;
 // 省略get()set() toString()方法

}

用户角色表:SysUserRole.class

public class SysUserRole {

    private Long userId;

    private Long roleId;
 // 省略get()set() toString()方法

}

角色权限表:SysRolePrivilege.class

public class SysRolePrivilege {

    private Long roleId;

    private Long privilegeId;
 // 省略get()set() toString()方法
}




3. 创建接口类

创建五个接口类

public interface UserMapper {
}

public interface RoleMapper {
}

public interface PrivilegeMapper {
}

public interface UserRoleMapper {
}

public interface RolePrivilegeMapper {
}




4. 创建对应mapper

创建对应mapper.xml

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


<mapper namespace="com.lyf.dao.UserMapper">

</mapper>

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

<mapper namespace="com.lyf.dao.RoleMapper">


</mapper>

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


<mapper namespace="com.lyf.dao.PrivilegeMapper">


</mapper>

<?xml version="1.0" encoding="UTF8" ?>
        <!DOCTYPE mapper
                PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lyf.dao.UserRoleMapper">


</mapper>

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


<mapper namespace="com.lyf.dao.RolePrivilegeMapper">

</mapper>




5. 配置MybatisUtils

MybatisUtils.class

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {

        try {
            //使用mybatis第一步获取SessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    // 你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。

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




步骤2:编写业务流程

步骤2-业务流程:

  1. 接口添加方法(在UserMapper.class接口中,添加selectById方法)
  2. mapper配置映射(在UserMapper.xml中,添加resultMap和select)
  3. 测试类:测试

XML字段映射主要有三种方式:

  • SQL别名
  • 配置驼峰命名mapUnderscoreToCamelCase(常用)
  • 使用ResultMap

1. 接口添加方法

public interface UserMapper {

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

2. mapper配置映射

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


<mapper namespace="com.lyf.dao.UserMapper">

    <resultMap id="userMap" type="com.lyf.entity.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>

    <!--#{id} 不能出现空格,否则报SQL语法错误-->
    <select id="selectById" resultMap="userMap">
        select * from sys_user where id = #{id}
    </select>
</mapper>

3. 测试

  @Test
    public void testSelectById(){
        // 获取SqlSession
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            //获取 UserMapper接口
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            //调用 selectById 方法 ,查询Id 为 1 的用户
            SysUser user = mapper.selectById(1l);
            // user不为空
            Assert.assertNotNull(user);

            // userName = admin
            Assert.assertEquals("admin",user.getUserName());

            System.out.println(user);
        }finally {
            sqlSession.close();
        }
    }

测试结果:查询成功!!!
在这里插入图片描述

二、编写CRUD方法

1. Select

业务需求:查询所有用户

业务需求:查询所有用户
业务过程还是那三步:

  1. 接口添加方法
  2. mapper配置映射(以下Mapper都是在UserMapper.xml 添加)
  3. 测试类:测试
  /**
     * 查询全部用户
     * @return
     */
    List<SysUser> selectAll();
    <select id="selectAll" resultType="com.lyf.entity.SysUser">
        select id,
            user_name,
            user_password,
            user_email,
            user_info,
            head_img,
            create_time
        from sys_user
    </select>
  @Test
    public void testSelectAll(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            // 调用selectALL 方法查询所有用户
            List<SysUser> userList = mapper.selectAll();
            // 结果不为空
            Assert.assertNotNull(userList);
            // 用户数量大于0个
            Assert.assertTrue(userList.size() > 0);
            // 打印输出
            System.out.println(userList);

        }finally {
            sqlSession.close();
        }
    }

测试结果:总量:6条
在这里插入图片描述

业务需求:根据用户id 获取角色信息

业务需求:根据用户id 获取角色信息

    /**
     * 根据用户id 获取角色信息
     * @param userId
     * @return
     */
    List<SysRole> selectRolesByUserId(Long userId);
  <select id="selectRolesByUserId" resultType="com.lyf.entity.SysRole">
        select
            r.id,
            r.role_name roleName,
            r.enabled,
            r.create_by createBy,
            r.create_time createTime,
            u.user_name as "user.userName",
            u.user_email as "user.userEmail"
        from sys_user u
        inner join sys_user_role ur on u.id = ur.user_id
        inner join sys_role r on ur.role_id = r.id
        where u.id = #{userId}
    </select>
 @Test
    public void testSelectRolesByUserId(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);

            List<SysRole> roleList = mapper.selectRolesByUserId(1L);

            Assert.assertNotNull(roleList);

            Assert.assertTrue(roleList.size()>0);

            System.out.println(roleList);
        }finally {
            sqlSession.close();
        }
    }

测试结果:
在这里插入图片描述

2. Insert

业务需求:新增用户

业务需求:新增用户

   /**
     * 新增用户
     * @param sysUser
     * @return
     * @TODO: insert attempted to return null from a method with a primitive return type (int).
     */
    int insert(SysUser sysUser);
    <insert id="insert">
        insert into sys_user(
            id,user_name,user_password,
            user_email,user_info,head_img,create_time
        )
        values(
            #{id},#{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg ,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP}
        )
    </insert>

    @Test
    public void testInsert(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);

            // 创建一个对象
            SysUser user = new SysUser();
            user.setUserName("test1");
            user.setUserPassword("123456");
            user.setUserEmail("test@mybatis");
            user.setUserInfo("test info");
            user.setHeadImg(new byte[]{1,2,3});
            user.setCreateTime(new Date());
            // 将新建的对象插入数据库中, 特别注意这里的返回值result是执行的SQL影响的行数
            int result = mapper.insert(user);
            // 只插入一条数据
            Assert.assertEquals(1,result);

            //id 为null , 没有给id 赋值, 并且没有配置回写id的值
            Assert.assertNull(user.getId());
            System.out.println(result);

        }finally {
            sqlSession.commit();
            sqlSession.close();
        }
        }

测试结果:添加成功
在这里插入图片描述

业务需求:新增用户-使用 useGenerateKeys 方式

业务需求:新增用户-使用 useGenerateKeys 方式

 int insert2(SysUser sysUser);
  <insert id="insert2" useGeneratedKeys="true" keyProperty="id">
        insert into sys_user(
            user_name,user_password,
            user_email,user_info,head_img,create_time
        )
        values(
            #{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg ,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP}
        )
    </insert>
    @Test
    public void testInsert2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);

            // 创建一个对象
            SysUser user = new SysUser();
            user.setUserName("test1");
            user.setUserPassword("123456");
            user.setUserEmail("test@mybatis");
            user.setUserInfo("test info");
            user.setHeadImg(new byte[]{1,2,3});
            user.setCreateTime(new Date());
            // 将新建的对象插入数据库中, 特别注意这里的返回值result是执行的SQL影响的行数
            int result = mapper.insert2(user);
            // 只插入一条数据
            Assert.assertEquals(1,result);

            //因为id 会写, 所以id 不为null
            Assert.assertNotNull(user.getId());
            if (result>0){
                System.out.println("添加成功:"+user);
            }

        }finally {
            sqlSession.commit();
            sqlSession.close();
        }
    }

测试结果:
在这里插入图片描述

业务需求:新增用户 -使用 selectKey 方式

业务需求:新增用户 -使用 selectKey 方式

    /**
     * 新增用户 -使用 selectKey 方式
     */
    int insert3(SysUser sysUser);
    <insert id="insert3" >
        insert into sys_user(
            user_name,user_password,
            user_email,user_info,head_img,create_time
        )
        values(
            #{userName},#{userPassword},#{userEmail},#{userInfo},#{headImg ,jdbcType=BLOB},#{createTime,jdbcType=TIMESTAMP}
        )
        <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
    </insert>

    @Test
    public void testInsert3(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);

            // 创建一个对象
            SysUser user = new SysUser();
            user.setUserName("test1");
            user.setUserPassword("123456");
            user.setUserEmail("test@mybatis");
            user.setUserInfo("test info");
            user.setHeadImg(new byte[]{1,2,3});
            user.setCreateTime(new Date());
            // 将新建的对象插入数据库中, 特别注意这里的返回值result是执行的SQL影响的行数
            int result = mapper.insert3(user);
            // 只插入一条数据
            Assert.assertEquals(1,result);

            //因为id 会写, 所以id 不为null
            Assert.assertNotNull(user.getId());
            if (result>0){
                System.out.println("添加成功:"+user);
            }

        }finally {
            sqlSession.commit();
            sqlSession.close();
        }
    }

测试结果:三种方式都可以添加成功,根据业务不同选择不同方式。
在这里插入图片描述

3. Update

业务需求:根据主键更新

业务需求:根据主键更新

    /**
     * 根据主键更新
     * @param sysUser
     * @return
     */
    int updateById(SysUser sysUser);

    <update id="updateById">
        update sys_user
        set user_name = #{userName},
            user_password = #{userPassword},
            user_email = #{userEmail},
            user_info = #{userInfo},
            head_img = #{headImg,jdbcType=BLOB},
            create_time = #{createTime,jdbcType=TIMESTAMP}
        where id = #{id}
    </update>
   @Test
    public void testUpdateById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            SysUser user = mapper.selectById(1L);
            user.setUserName("admin_test2");
            user.setUserEmail("admin@mybatis2");
            int result = mapper.updateById(user);
            if (result>0){
                System.out.println("更新成功:"+user);
            }



        }finally {
            // 提交,存储在数据库
            sqlSession.commit();
            // 回滚,存储在缓存
//            sqlSession.rollback();
            sqlSession.close();
        }
    }

测试:
在这里插入图片描述

4. Delete

业务需求:通过主键删除

业务需求:通过主键删除

    /**
     * 通过主键删除
     * @param id
     * @return
     */
    int deleteById(Long id);
  <delete id="deleteById">
        delete from sys_user where id = #{id}
    </delete>
    @Test
    public void testDeleteById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int result = mapper.deleteById(1019L);
            if (result >0){
                System.out.println("删除成功");
            }

        }finally {
//            sqlSession.rollback();
            // 造成数据变动,都要commit提交
            sqlSession.commit();
            sqlSession.close();
        }
    }

测试成功:
在这里插入图片描述

三、多个接口参数

1. 接口参数为基本类型

在实际应用中经常会遇到使用多个参数的情况,我们通常将多个参数合并到一个JavaBean中,例如:User类、Role类。这种方法用起来很方便,适合参数较多的情况,并不适合全部的情况。
对于参数比较少的情况,还有两种方式可以采用:

  • 使用Map类型作为参数
  • 使用@Param注解

Map类型不太简洁,所以主要使用@Param
步骤:

  • 接口:@Param(“userId”) Long userId
  • sql传入:#{userId}

先来看下不使用@Param 注解会发生什么错误:

业务需求:根据用户ID 和角色的enabled 状态来查询用户的所有角色。

   /**
     * 根据用户id 和角色的enabled状态获取用户的角色
     * @param userId
     * @param enabled
     * @return
     */
    List<SysRole> selectRolesByUserIdAndRoleEnabled( Long userId, Integer enabled);

 <select id="selectRolesByUserIdAndRoleEnabled"
            resultType="com.lyf.entity.SysRole">
        select
            r.id,
            r.role_name roleName,
            r.enabled,
            r.create_by createBy,
            r.create_time createTime
        from sys_user u
        inner join sys_user_role ur on u.id = ur.user_id
        inner join sys_role r on ur.role_id = r.id
        where u.id = #{userId} and r.enabled = #{enabled}
    </select>
 @Test
    public void testSelectRolesByUserIdAndRoleEnabled(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<SysRole> userList = mapper.selectRolesByUserIdAndRoleEnabled(1L, 1);
            System.out.println(userList);

        }finally {
//            sqlSession.rollback();
            // 造成数据变动,都要commit提交
            sqlSession.close();
            // Parameter 'userId' not found. Available parameters are [arg1, arg0, param1, param2]
        }
    }

测试结果:

报错:Parameter 'userId' not found. Available parameters are [arg1, arg0, param1, param2]

这个错误表示,XML可用的参数只有arg1, arg0, param1, param2, param1, param2 都是Mybatis根据参数位置自定义的名字,如果将XML中的#{userId} 改为#{arg0} 或 #{param1} ,将 # {enabled} 改为 #{1} 或 #{param2} ,这个方法便可使用,但实际上不建议这么做。

使用@param 目的:指明:SQL查询#{userId}的具体参数值在哪

添加@param注解

    /**
     * 根据用户id 和角色的enabled状态获取用户的角色
     * @param userId
     * @param enabled
     * @return
     */
    List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId,@Param("enabled") Integer enabled);

测试:测试成功
在这里插入图片描述

这种情况一般出现在两个参数以上,因为一个参数的时候,Mybatis不关心这个参数叫什么名字,就会直接把这个唯一的参数值拿来使用。

2. 接口参数为对象类型

步骤:

  • 接口:@Param(“user”) SysUser user,
  • sql传入:#{user.id}
    /**
     * 根据用户id 和角色的enabled状态获取用户的角色
     * 参数类型:实体类对象
     * @param user
     * @param role
     * @return
     */
    List<SysRole> selectRolesByUserIdAndRoleEnabled2(@Param("user") SysUser user,@Param("role") SysRole role );
 <select id="selectRolesByUserIdAndRoleEnabled2"
            resultType="com.lyf.entity.SysRole">
        select
            r.id,
            r.role_name roleName,
            r.enabled,
            r.create_by createBy,
            r.create_time createTime
        from sys_user u
        inner join sys_user_role ur on u.id = ur.user_id
        inner join sys_role r on ur.role_id = r.id
        where u.id = #{user.id} and r.enabled = #{role.enabled}
    </select>
 @Test
    public void testSelectRolesByUserIdAndRoleEnabled2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            SysUser user = new SysUser();
            user.setId(1L);
            SysRole sysRole = new SysRole();
            sysRole.setEnabled(1L);
            List<SysRole> userList = mapper.selectRolesByUserIdAndRoleEnabled2(user,sysRole );
            System.out.println(userList);

        }finally {
//            sqlSession.rollback();
            // 造成数据变动,都要commit提交
            sqlSession.close();
            // Parameter 'userId' not found. Available parameters are [arg1, arg0, param1, param2]
        }
    }

测试成功:
在这里插入图片描述

四、Mapper接口动态代理实现原理

待续

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值