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

32. 删除管理员–Mapper层

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

delete from ams_admin where id=?

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

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

首先,在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;

}

然后,在AdminMapper.java中添加:

/**
 * 根据id删除管理员数据
 *
 * @param id 管理员id
 * @return 受影响的行数
 */
int deleteById(Long id);

/**
 * 查询管理员列表
 *
 * @return 管理员列表
 */
List<AdminListItemVO> list();

AdminMapper.xml中配置:

<!-- int deleteById(Long id); -->
<delete id="deleteById">
    DELETE FROM ams_admin WHERE id=#{id}
</delete>

<!-- AdminStandardVO getStandardById(Long id); -->
<select id="getStandardById" resultMap="StandardResultMap">
    SELECT
        <include refid="StandardQueryFields" />
    FROM
        ams_admin
    WHERE
        id=#{id}
</select>

<!-- List<AdminListItemVO> list(); -->
<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>

完成后,在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);
}

33. 删除管理员–Service层

IAdminService接口中添加抽象方法:

/**
 * 删除管理员
 *
 * @param id 尝试删除的管理员的id
 */
void delete(Long id);

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

AdminServiceTests中编写并执行测试:

@Test
void testDelete() {
    Long id = 9L;

    try {
        service.delete(id);
        System.out.println("删除成功!");
    } catch (ServiceException e) {
        System.out.println(e.getMessage());
    }
}

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();
}

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

35. 删除管理员–前端

36. 完善添加管理员

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

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

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

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;

}

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

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

<mapper namespace="xx.xx.xx.xx.AdminRoleMapper">

    <!-- int insertBatch(List<AdminRole> adminRoleList); -->
    <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>

完成后,在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);
    }

}

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

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

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

@Autowired
AdminRoleMapper adminRoleMapper;

并在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);

完成后,在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());
    }
}

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

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

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

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

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

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

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

  • 业务实现类的方法上
    • 仅作用于当前方法
  • 业务实现类上
    • 将作用于当前类中所有方法
  • 业务接口的抽象方法上
    • 仅作用于当前方法
    • 无论是哪个类重写此方法,都将是事务性的
  • 业务接口上
    • 将作用于当前接口中所有抽象方法
    • 无论是哪个类实现了此接口,重写的所有方法都是将是事务性的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

专注摸鱼的汪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值