• 项目实战(SpringJDBC框架事务管理)


    32. 删除管理员–Mapper层

    删除管理员需要执行的SQL大致是:

    delete from ams_admin where id=?
    
    • 1

    在删除之前,还应该检查数据是否存在,可以通过以下SQL查询来实现检查:

    select count(*) from ams_admin where id=?
    
    • 1
    select * from ams_admin where id=?
    
    • 1

    首先,在pojo.vo包下创建AdminStandardVO类:

    package cn.tedu.csmall.passport.pojo.vo;
    
    import lombok.Data;
    
    import java.io.Serializable;
    import java.time.LocalDateTime;
    
    /**
     * 管理员的标准VO类
     *
     * @author java@tedu.cn
     * @version 0.0.1
     */
    @Data
    public class AdminStandardVO implements Serializable {
    
        /**
         * 数据id
         */
        private Long id;
    
        /**
         * 用户名
         */
        private String username;
    
        /**
         * 昵称
         */
        private String nickname;
    
        /**
         * 头像URL
         */
        private String avatar;
    
        /**
         * 手机号码
         */
        private String phone;
    
        /**
         * 电子邮箱
         */
        private String email;
    
        /**
         * 描述
         */
        private String description;
    
        /**
         * 是否启用,1=启用,0=未启用
         */
        private Integer enable;
    
        /**
         * 最后登录IP地址(冗余)
         */
        private String lastLoginIp;
    
        /**
         * 累计登录次数(冗余)
         */
        private Integer loginCount;
    
        /**
         * 最后登录时间(冗余)
         */
        private LocalDateTime gmtLastLogin;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    然后,在AdminMapper.java中添加:

    /**
     * 根据id删除管理员数据
     *
     * @param id 管理员id
     * @return 受影响的行数
     */
    int deleteById(Long id);
    
    /**
     * 查询管理员列表
     *
     * @return 管理员列表
     */
    List<AdminListItemVO> list();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    AdminMapper.xml中配置:

    
    <delete id="deleteById">
        DELETE FROM ams_admin WHERE id=#{id}
    delete>
    
    
    <select id="getStandardById" resultMap="StandardResultMap">
        SELECT
            <include refid="StandardQueryFields" />
        FROM
            ams_admin
        WHERE
            id=#{id}
    select>
    
    
    <select id="list" resultMap="ListResultMap">
        SELECT
            <include refid="ListQueryFields" />
        FROM
            ams_admin
        ORDER BY
            enable DESC, id
    select>
    
    <sql id="StandardQueryFields">
        <if test="true">
            id, username, nickname, avatar, phone,
            email, description, enable, last_login_ip, login_count,
            gmt_last_login
        if>
    sql>
    
    <sql id="ListQueryFields">
        <if test="true">
            id, username, nickname, avatar, phone,
            email, description, enable, last_login_ip, login_count,
            gmt_last_login
        if>
    sql>
    
    <resultMap id="StandardResultMap" type="cn.tedu.csmall.passport.pojo.vo.AdminStandardVO">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="nickname" property="nickname"/>
        <result column="avatar" property="avatar"/>
        <result column="phone" property="phone"/>
        <result column="email" property="email"/>
        <result column="description" property="description"/>
        <result column="enable" property="enable"/>
        <result column="last_login_ip" property="lastLoginIp"/>
        <result column="login_count" property="loginCount"/>
        <result column="gmt_last_login" property="gmtLastLogin"/>
    resultMap>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    完成后,在AdminMapperTests中编写并执行测试:

    @Test
    void testDeleteById() {
        Long id = 11L;
        int rows = mapper.deleteById(id);
        System.out.println("删除数据完成,受影响的行数=" + rows);
    }
    
    @Test
    void testGetStandardById() {
        Long id = 1L;
        Object result = mapper.getStandardById(id);
        System.out.println("根据id=" + id + "查询标准信息完成,结果=" + result);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    33. 删除管理员–Service层

    IAdminService接口中添加抽象方法:

    /**
     * 删除管理员
     *
     * @param id 尝试删除的管理员的id
     */
    void delete(Long id);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    AdminServiceImpl中实现:

    @Override
    public void delete(Long id) {
        log.debug("开始处理【删除管理员】的业务,参数:{}", id);
        // 根据参数id查询管理员数据
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        // 判断管理员数据是否不存在
        if (queryResult == null) {
            String message = "删除管理员失败,尝试访问的数据不存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
    
        // 执行删除管理员
        adminMapper.deleteById(id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    AdminServiceTests中编写并执行测试:

    @Test
    void testDelete() {
        Long id = 9L;
    
        try {
            service.delete(id);
            System.out.println("删除成功!");
        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    34. 删除管理员–Controller层

    AdminController中添加处理请求的方法:

    // http://localhost:8080/admins/9527/delete
    @ApiOperation("删除管理员")
    @ApiOperationSupport(order = 200)
    @ApiImplicitParam(name = "id", value = "管理员id", required = true, dataType = "long")
    @PostMapping("/{id:[0-9]+}/delete")
    public JsonResult<Void> delete(@PathVariable Long id) {
        log.debug("开始处理【删除管理员】的请求,参数:{}", id);
        adminService.delete(id);
        return JsonResult.ok();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    完成后,重启项目,通过Knife4j在线API文档进行测试访问。

    35. 删除管理员–前端

    36. 完善添加管理员

    添加管理员时,还需要为管理员分配某些(某种)角色,进而使得该管理员具备某些操作权限!

    为管理分配角色的本质是向ams_admin_role这张表中插入数据!同时,需要注意,每个管理员账号可能对应多种角色,所以,需要执行的SQL语句大致是:

    insert into ams_admin_role (admin_id, role_id) values (?, ?), (?, ?) ... (?, ?);
    
    • 1

    pojo.entity包下创建AdminRole实体类:

    package cn.tedu.csmall.passport.pojo.entity;
    
    import lombok.Data;
    
    import java.io.Serializable;
    import java.time.LocalDateTime;
    
    /**
     * 管理员与角色的关联数据的实体类
     *
     * @author java@tedu.cn
     * @version 0.0.1
     */
    @Data
    public class AdminRole implements Serializable {
    
        /**
         * 数据id
         */
        private Long id;
    
        /**
         * 管理员id
         */
        private Long adminId;
    
        /**
         * 角色id
         */
        private Long roleId;
    
        /**
         * 数据创建时间
         */
        private LocalDateTime gmtCreate;
    
        /**
         * 数据最后修改时间
         */
        private LocalDateTime gmtModified;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    mapper包下创建AdminRoleMapper接口,并在接口中添加抽象方法:

    package cn.tedu.csmall.passport.mapper;
    
    import cn.tedu.csmall.passport.pojo.entity.AdminRole;
    import org.springframework.stereotype.Repository;
    
    import java.util.List;
    
    /**
     * 处理管理员与角色的关联数据的Mapper接口
     *
     * @author java@tedu.cn
     * @version 0.0.1
     */
    @Repository
    public interface AdminRoleMapper {
    
        /**
         * 批量插入管理员与角色的关联数据
         *
         * @param adminRoleList 管理员与角色的关联数据的列表
         * @return 受影响的行数
         */
        int insertBatch(List<AdminRole> adminRoleList);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    src/main/resources/mapper文件夹下通过复制粘贴得到AdminRoleMapper.xml文件,在此文件中配置以上抽象方法映射的SQL语句:

    <mapper namespace="xx.xx.xx.xx.AdminRoleMapper">
    
        
        <insert id="insertBatch" useGeneratedKeys="true" keyProperty="id">
            INSERT INTO ams_admin_role (admin_id, role_id) VALUES 
            <foreach collection="list" item="adminRole" separator=",">
                (#{adminRole.adminId}, #{adminRole.roleId})
            foreach>
        insert>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    完成后,在src/test/java下的根包下创建mapper.AdminRoleMapperTests测试类,编写并执行测试:

    package cn.tedu.csmall.passport.mapper;
    
    import cn.tedu.csmall.passport.pojo.entity.AdminRole;
    import lombok.extern.slf4j.Slf4j;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Slf4j
    @SpringBootTest
    public class AdminRoleMapperTests {
    
        @Autowired
        AdminRoleMapper mapper;
    
        @Test
        void testInsertBatch() {
            List<AdminRole> adminRoleList = new ArrayList<>();
            for (int i = 1; i <= 3; i++) {
                AdminRole adminRole = new AdminRole();
                adminRole.setAdminId(100L);
                adminRole.setRoleId(i + 0L);
                adminRoleList.add(adminRole);
            }
    
            int rows = mapper.insertBatch(adminRoleList);
            log.debug("批量插入数据完成!受影响的行数={}", rows);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    完成Mapper层的补充后,先在AdminAddNewDTO中添加新的属性,表示“客户端将提交到服务器端的,添加管理员时选择的若干个角色id”:

    /**
     * 尝试添加的管理员的角色id列表
     */
    private Long[] roleIds;
    
    • 1
    • 2
    • 3
    • 4

    然后,在AdminServiceImpl类中,补充声明:

    @Autowired
    AdminRoleMapper adminRoleMapper;
    
    • 1
    • 2

    并在addNew()方法的最后补充:

    // 调用adminRoleMapper的insertBatch()方法插入关联数据
    Long[] roleIds = adminAddNewDTO.getRoleIds();
    List<AdminRole> adminRoleList = new ArrayList<>();
    for (int i = 0; i < roleIds.length; i++) {
        AdminRole adminRole = new AdminRole();
        adminRole.setAdminId(admin.getId());
        adminRole.setRoleId(roleIds[i]);
        adminRoleList.add(adminRole);
    }
    adminRoleMapper.insertBatch(adminRoleList);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    完成后,在AdminServiceTests中原有的测试中,在测试数据上添加封装roleIds属性的值,并进行测试:

    @Test
    void testAddNew() {
        AdminAddNewDTO adminAddNewDTO = new AdminAddNewDTO();
        adminAddNewDTO.setUsername("wangkejing6");
        adminAddNewDTO.setPassword("123456");
        adminAddNewDTO.setPhone("13800138006");
        adminAddNewDTO.setEmail("wangkejing6@baidu.com");
        adminAddNewDTO.setRoleIds(new Long[]{3L, 4L, 5L}); // ===== 新增 =====
    
        try {
            service.addNew(adminAddNewDTO);
            log.debug("添加管理员成功!");
        } catch (ServiceException e) {
            log.debug("{}", e.getMessage());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    37. 基于Spring JDBC框架的事务管理

    事务:Transaction,是数据库中的一种能够保证多个写操作要么全部成功,要么全部失败的机制!

    在基于Spring JDBC的数据库编程中,在业务方法上添加@Transactional注解,即可使得这个业务方法是“事务性”的!

    假设,存在某银行转账的操作,转账时需要执行的SQL语句大致是:

    UPDATE 存款表 SET 余额=余额-50000 WHERE 账号='国斌老师';
    
    • 1
    UPDATE 存款表 SET 余额=余额+50000 WHERE 账号='苍松老师';
    
    • 1

    以上的转账操作就涉及多次数据库的写操作,如果由于某些意外原因(例如停电、服务器死机等),导致第1条SQL语句成功执行,但是第2条SQL语句未能成功执行,就会出现数据不完整的问题!使用事务就可以解决此问题!

    关于@Transationcal注解,可以添加在:

    • 业务实现类的方法上
      • 仅作用于当前方法
    • 业务实现类上
      • 将作用于当前类中所有方法
    • 业务接口的抽象方法上
      • 仅作用于当前方法
      • 无论是哪个类重写此方法,都将是事务性的
    • 业务接口上
      • 将作用于当前接口中所有抽象方法
      • 无论是哪个类实现了此接口,重写的所有方法都是将是事务性的
  • 相关阅读:
    小编推荐几款好用的MySQL开源客户端,建议收藏哦
    【C语言刷LeetCode】687. 最长同值路径(M)
    摆动序列【贪心4】
    No valid crumb was included in the request
    WuThreat身份安全云-TVD每日漏洞情报-2023-10-16
    6.5黄金行情分析
    9月前三大海外“债主”分别减持美债,”美债还完全吗?
    【linux】【platform[1]】简述device和driver几种匹配方式(包括测试用demo)
    Spring----IOC、注解
    java计算机毕业设计校园共享单车管理系统源码+系统+数据库+lw文档+mybatis+运行部署
  • 原文地址:https://blog.csdn.net/weixin_43121885/article/details/127602560