增删改查最终总结—2.1.1(单表-增删改查)

一个 Mybatis 开发神器:Fast MyBatis 超好用

————————Fast Mybatis开发文档

每一个增删改查前都要先看这个--增删改查操作 都需要注意:

1、在控制层最后一行代码return给用户,正确的响应

return SysResult.success(有的需要传参数给用户[比如需要回显的东西:商品分类列表、用户之前填的邮箱密码等]就直接把之前控制层接收到的参数写进来);

2、事务控制
1、事务控制- 以后操作数据库时 ,只要是 新增/删除/修改操作 就必须需要事务控制.
1、现象:业务逻辑在执行的过程中,如果中间发生了异常,应该保证事务的一致性.事务应该回滚.但是经过测试,发现执行报异常,但是数据可以正常的入库. 说明方法没有事务的控制.

2、解决方法:

@Transactional //事务的注解
特点:
1.Spring中默认对事务进行支持——加@Transactional //事务的注解
2.Spring中默认控制的是运行时异常. 如果是检查异常 Spring不负责处理.如果想让Spring处理检查异常就需要加@Transactional(rollbackFor = Exception.class) 只要有异常,则全部回滚.

        核心原理: AOP

        问题: 但如果采用上述2.的代码,则AOP拦截所有的异常,运行效率低. 所以一般只拦截运行时异常.检查异常由程序员手动控制.@Transactional(rollbackFor = Exception.class)根本不用

3、如何正式操作2、  :
在service层 实现类中的每个 增删改查方法 上加上@Transactional(readOnly=true)

//或者直接在service层实现类上加一个@Transactional(readOnly=true)即可

注意:

写个@Transactional默认事务处理方式@Transactional(readOnly=false),相当于是添加了一个排他锁/同步锁,我查询的时候别人只能等待

所以我们可以加上@Transactional(readOnly=true),这样就会成了一个只读事务

一、增insert(数据新增/入库)

1、新增的数据无 密码 这一项的情况


       1、规律


都是 用户在浏览器整个提交的form表单数据 封装为js对象进行参数传递,在controller层接用(user)对象接
注意:1、sql语句没有where条件(新数据无id,新增完成才有id可用)
           2、无返回值,service层不用return


        2、不同框架写法

多个where条件:controller层将其封装成对象(user)传过来



               1)mybatis框架


service层接口

void saveUser(User user);

service层接口实现类

 @Override
    public void saveUser(User user) { 
            user.setStatus(true)
                .setCreated(date)
                .setUpdated(date);
        userMapper.saveUser(user);
    }

               1>映射文件写法

mapper层接口

    void saveUser(User user);

......Mapper.xml映射文件

<insert id="saveUser" >
//1、insert into demo_user(id,name,age,sex) values (null,#{name},#{age},#{sex})
		
2、insert into user(id,username,phone,email,status,created,updated) value (null,#{username},#{password},#{phone},#{email},#{status},#{created},#{updated})				            
    </insert>
新增此处用 value ;但是values好像也行


普通增 sql语句写的不是values,是value
   相比于数据库中插入数据 要加字段名,且后面不是values,是value

待研究

待研究————values还是value 还有下面的注解写法也一样
          2>注解方式写法
mapper层接口

    @insert(insert into 表名 value (null,#{deptName})")  //新增此处用value,values好像也行
     void saveUser(User user);

2)mybatis-plus框架

 注意: MP中

新增/入库操作提供了:insert方法;如果指定了条件就按指定的条件。

——如下

 service层接口

void saveUser(User user);

service层接口实现类

 @Override
    public void updateUserById(Integer id) {
        user.setUsername("admin888")
                .setEmail("11@qq.com")
                .setPhone("15534495677")
                .setStatus(true)
                .setCreated(new Date())
                .setUpdated(user.getCreated());
        //返回的是影响的行数,可接可不接
        int rows = userMapper.insert(user);//把user当数据传进去
        System.out.println("影响的行数:"+rows);
    }

2、新增的数据有 密码 这一项的情况

用户的密码在业务层加密后才能往数据库存

将用户输入的明文密码转变为密文才能存入数据库;

                新增操作必须在业务层实现类用对象.set().set().set()……入库

 1)mybatis框架

service层接口

void saveUser(User user);

service层接口实现类

    @Override
    public void saveUser(User user) {
        //将密码加密处理
        String password = user.getPassword();//获取密码
        String md5Pass = DigestUtils.md5DigestAsHex(password.getBytes());//加密处理
 
        Date date = new Date();
        user.setPassword(md5Pass)
                .setStatus(true)
                .setCreated(date)
                .setUpdated(date);
        userMapper.saveUser(user);
    }

               1>映射文件写法

mapper层接口

    void saveUser(User user);

......Mapper.xml映射文件

<insert id="saveUser" >
//1、insert into demo_user(id,name,age,sex) values (null,#{name},#{age},#{sex})
		
2、insert into user(id,username,phone,email,status,created,updated) value (null,#{username},#{password},#{phone},#{email},#{status},#{created},#{updated})				            
    </insert>
新增此处用 value ;但是values好像也行


普通增 sql语句写的不是values,是value
   相比于数据库中插入数据 要加字段名,且后面不是values,是value

待研究

待研究————values还是value 还有下面的注解写法也一样
          2>注解方式写法
mapper层接口

    @insert(insert into 表名 value (null,#{deptName})")  //新增此处用value,values好像也行
     void saveUser(User user);

2)mybatis-plus框架

 注意: MP中

新增/入库操作提供了:insert方法;如果指定了条件就按指定的条件。

——如下

 service层接口

void saveUser(User user);

service层接口实现类

 @Override
    public void updateUserById(Integer id) {
      //将密码加密处理
        String password = user.getPassword();//获取密码
        String md5Pass = DigestUtils.md5DigestAsHex(password.getBytes());//加密处理

        user.setUsername("admin888")
             .setPassword(md5Pass)
                .setEmail("11@qq.com")
                .setPhone("15534495677")
                .setStatus(true)
                .setCreated(new Date())
                .setUpdated(user.getCreated());
        //返回的是影响的行数,可接可不接
        int rows = userMapper.insert(user);//把user当数据传进去
        System.out.println("影响的行数:"+rows);
    }

mybatis中如何执行批量插入

如何获取自动生成的(主)键值

**********************************************************************************


 二、删delete(数据删除)

正常的删

        1、规律

注意:1、sql语句有where条件——根据 id或者其他条件 删除

           2、无返回值,service层不用return

        2、不同框架写法

多个where条件:controller层将其封装成对象(user)传过来

单个where条件:controller层将其直接传过来


1)mybatis框架

 service层接口

void deleteUserById(Integer id);

service层接口实现类

 @Override
    public void deleteUserById(Integer id) {
         userMapper.deleteUserById(id);
    }

           1>映射文件写法

mapper层接口

     void deleteUserById(Integer id);

......Mapper.xml映射文件

    <delete id="deleteUserById" >
        delete from 表名 where id = #{id}
    </delete>

            2>注解方式写法

mapper层接口

   @Delete("delete from 表名 where id=#{id}")
    void deleteUserById(Integer id);

2)mybatis-plus框架

 注意: MP中

删除/修改(更新)默认根据主键进行操作 :deleteById方法;如果指定了条件就按指定的条件。

如果控制层只接收了一个数据 id 来进行 删除/修改(更新)操作,那就直接把id进行传递

如果控制层接收了多个数据 id、status... 来进行 更新/删除/修改操作,用(user)对象接收,直接用对象在service层实现类传递,MP会默认根据主键更新/删除/修改——如下

 service层接口

 void daleteUserById(Integer id);

service层接口实现类

 @Override
    public void updateUserById(Integer id) {
        //userMapper.deleteUserById(id); mybatis框架写法
         userMapper.deleteById(id);  MP写法,同时就不需要mapper层(mapper和映射文件都不需要了)了
    }

特殊的删:当用户删除商品分类的时候,应该将它的子级数据全部删除.否则子级就永远在数据库中,没人调用

项目整体做法_fhefhffg的博客-CSDN博客

**********************************************************************************

三、改update(数据修改/更新)

1、普通修改:比如修改状态status的开启关闭,如下

        根据id/主键修改

        1、规律

 都是 用户在浏览器整个提交的form表单数据 封装为js对象进行参数传递,在controller层接用(user)对象接

注意:1、sql语句是有where条件——根据 id或者其他条件 删除

           2、无返回值,service层不用return

        2、不同框架写法

controller层将其封装成对象(user)传过来


1)mybatis框架

 service层接口

void updateUserById(User user);

service层接口实现类

 @Override
    public void updateUserById(User user) {
        userMapper.updateUserById(user);
    }

            1>映射文件写法

mapper层接口

 void updateUserById(User user);

......Mapper.xml映射文件

<update id="updateUserById" >
        update 表名 set status=#{status} where id=#{id}
    </update>

            2>注解方式写法

mapper层接口

    @update("update 表名 set status=#{status} where id=#{id}")
    void updateUserById(User user);

2)mybatis-plus框架

注意: MP中

删除/修改(更新)默认根据主键进行操作 :updateById方法;如果指定了就按指定的条件。

如果控制层只接收了一个数据 id 来进行 删除/修改(更新)操作,那就直接把id进行传递

如果控制层接收了多个数据 id、status... 来进行 更新/删除/修改操作,用(user)对象接收,直接用对象在service层实现类传递,MP会默认根据主键更新/删除/修改——如下

 service层接口

void updateUserById(User user);

service层接口实现类

 @Override
    public void updateUserById(User user) {
        //userMapper.updateUserById(user);  mybatis框架写法
         userMapper.updateById(user);  MP写法,同时就不需要mapper层(mapper和映射文件都不需要了)了
    }

根据 其他条件 修改

需求:用户的修改操作
     *     要求将password=123456的phone改为10086,email改为10086@qq.com

1)mybatis框架

同 根据id修改

2)mybatis-plus框架

 service层接口

void updateUserByOther(User user);

service层接口实现类

     * 参数说明:
     *      1.entity: 主要的目的封装set条件
     *      2.wrapper: 封装修改条件的条件构造器
 @Override
    public void updateUserByOther(User user) {
        user.setPhone("10086").setEmail("10086@qq.com");//entity
       //条件构造器————修改专用和查询不同
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("password","123456");//wrapper
        userMapper.update(user,updateWrapper);
    }

2、特殊修改:比如用户之前的昵称、密码等,之前就设置了一次,这次要改新的,则需要将之前的回显给用户

1、数据回显 ——即根据ID查询用户信息,并要将查到的数据user返回 让用户看到

按根据id查询信息操作即可

需要注意的是在 控制层controller层  需要把查询到的结果用user对象接一下 再 return SysResult.success(user);//将查到的数据返回 让用户看到

必须把user当作参数传进去给用户,这样用户才能看到 ——如下

用户修改-数据回显
    @GetMapping("/{id}")
    public SysResult findUserById(@PathVariable Integer id){
        User user = userService.findUserById(id);
        return SysResult.success(user);
    }

2、用户修改-根据用户ID更新数据

同上:根据 根据id/主键修改

**********************************************************************************

四、查select(数据查询)

注意:1、仅仅查询操作有返回值,只要写映射文件就要记得加 resultType="pojo类的别名包(如User)

           2、有返回值,service层要return

           3、以下例子中的“*”在正式工作中不能写,要用具体的字段代替

**当表中的字段与POJO中的属性名称一致时,映射文件中使用resultType="pojo类的别名包(如User)进行映射

**当表中的字段与POJO中的属性名称不一致时(pojo中属性的名字不能出现—、_),如下图,不能直接使用resultType="pojo类的别名包(如User)进行映射


解决方式一(繁琐):需要使用resultMap的方式进行映射.
resultType : 只能支持字段名称与属性的名称一致时才能自动映射.
resultMap: 可以支持 任意类型的映射 万能的结构

 解决方式二:继续使用resultType,但要在yml文件中开启驼峰映射规则

解决方式三:通过在查询的 sql 语句中定义字段名的别名,让字段名的别名和实体pojo类的属性名一致。

**********************************************************************************

        1、单条件查询

单条件 单值查询——接收到前端单个条件且单个参数

controller层将其直接传过来


根据id查询

1)mybatis框架

 service层接口

User findUserById(Integer id);

service层接口实现类

 @Override
    public User findUserById(Integer id) {
        return userMapper.findUserById(id);
    }

            1>映射文件写法

mapper层接口

     User findUserById(Integer id);

......Mapper.xml映射文件

<select id="findUserById" resultType="pojo类的别名包(User)">
        select * from 表名 where id = #{id}
    </select>

            2>注解方式写法

mapper层接口

    @Select("select * from 表名 where id=#{id}")
    User findUserById(Integer id);

2)mybatis-plus框架

MP提供了单独的根据ID进行查询的selectById()方法

 service层接口

User findUserById(Integer id);

service层接口实现类

​@Override
    public User findUserById(Integer id) {
        //return userMapper.findUserById(id);  mybatis框架
       return userMapper.selectById(id);//MP框架,无mapper层和映射文件了
    }

                模糊查询

例:

模糊查询——此处是单值查询
//查询name字段中包含“君”的用户
//返回值类型:用List<User>当返回值类型
//参数列表类型:String name(要传进去的参数)
 //String name = "%" + "君" + "%";//这种方法写,映射文件里就不用写%了 like #{name}
        String name = "君";//%一般写在映射文件里

service层接口

List<User> findUserByLike(String name);

service层接口实现类

 @Override
    public List<User>  findUserByLike(String name) {
        return userMapper.findUserByLike(name);
    }

1)mybatis框架

            1>映射文件写法

mapper层接口

List<User> findUserByLike(String name);

......Mapper.xml映射文件

   <!--Sql标签: 抽取公共的Sql语句 -->
    <sql id="tableColumn">
        id,name,age,sex
    </sql>
    
<select id="findUserByLike" resultType="User">
        SELECT <include refid="tableColumn"/> FROM demo_user WHERE NAME LIKE "%"#{name}"%"
    </select>

            2>注解方式写法

mapper层接口


2)mybatis-plus框架

查询username 中包含admin的数据,并按照id降序排列——模糊查询+多条件查询
  SQL:select * from user where username like "%admin%" order by id desc
        知识:1、like  表示"%admin%"    左右都有%
                   2、likeLeft  表示"%admin"    左有%
                   3、likeRight  表示"admin%"    右有%

 service层接口

List<User> findUserByLike(User user);

service层接口实现类

 @Override
    public List<User>  findUserByLike(User user) {
       //条件构造器    会根据对象中不为null的元素动态拼接sql
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // queryWrapper.gt("字段名", 5);
        queryWrapper.like("username", "admin")
                    .orderByDesc("id");

/*        
//I、如果可保证查询的结果很确定只有一个用selectOne(),用对象接
//User user = userMapper.selectOne(queryWrapper);
//II、如果不能保证查询的结果只有一个用selectList(),则使用list集合接收
//List<User> userList = userMapper.selectList(queryWrapper);
        List<User> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);
*/
        return userMapper.selectList(queryWrapper);
    }

 1-2、1单/多条件 单值(=  < >  ≥ ≤  !=)查询

多个条件 单值常会在控制层封装成对象传递,如果没有被封装,传多个参数,看1-2、3

查询ID>5的用户——利用逻辑运算符/转义字符方式  实现sql操作
  SQL:select * from user where id>5

1)mybatis框架

 service层接口

User findUserById(Integer id);

service层接口实现类

 @Override
    public User findUserById(Integer id) {
        return userMapper.findUserById(id);
    }

            1>映射文件写法

mapper层接口

     User findUserById(Integer id);

......Mapper.xml映射文件

<select id="findUserById" resultType="pojo类的别名包(User)">
     <![CDATA[ select * from 表名 where id > #{id}  ]]>
    </select>

            2>注解方式写法

mapper层接口

    @Select("select * from 表名 where id>#{id}")
    User findUserById(Integer id);

2)mybatis-plus框架

 service层接口

User findUserById(Integer id);

service层接口实现类

​@Override
    public User findUserById(Integer id) {
      //条件构造器    会根据对象中不为null的元素动态拼接sql
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
     // queryWrapper.gt("字段名", 5);
        queryWrapper.gt("id", 5);

/*
//I、如果可保证查询的结果很确定只有一个用selectOne(),用对象接
//User user = userMapper.selectOne(queryWrapper);
//II、如果不能保证查询的结果只有一个用selectList(),则使用list集合接收
//List<User> userList = userMapper.selectList(queryWrapper);
        List<User> userList = userMapper.selectList(queryWrapper);
        System.out.println(userList);
*/
        return userMapper.selectList(queryWrapper);
    }

1-2、2单条件 多值(=)查询/前端同名提交问题——接收到前端单个条件多个参数,映射文件需要遍历   面试foreach

情况:单值查询的参数/条件是一个集合参数,且各个参数之间用,分隔(前端接收参数时同名提交问题)

方法:映射文件需要遍历

例:
//查询id=1,2,3,5,7的数据    
select * from demo_user  where id in (1,2,3,5,7........)
    //前端: URL?id=1,2,3,4,5 获取之后一般采用数组接收并传给service层
        integer[] array = {1,2,3,5,7};  最好用包装类,如下

controller层将其封装成数组(Integer[]  封装成的数组名如ids ///String[]  数组名hobby)传过来

service层接口

List<User> findUserByIN(Integer[] array);

service层接口实现类

 @Override
    public List<User>  findUserByIN(Integer[] array) {
        return userMapper.findUserByIN(array);
    }

1)mybatis框架

            1>映射文件写法

mapper层接口

     List<User> findUserByIN(Integer[] array);

......Mapper.xml映射文件

        <!--关于Mybatis的遍历的写法
        foreach标签:
            1. collection 需要遍历的集合/数组
                   1.1 是数组      关键字写: array(list也对)——写成collection="array"
                   1.2 list集合    关键字写: list(array也对)
                   1.3 Map<key,array/list>集合  关键字:key
            2. open/close  循环体的开始和结束 可以写到循环之外简化标签——就是  							foreach标签外的俩括号
            3. item  当前遍历数据的变量名
            4. separator 分割符    -->
    <select id="findListByIn" resultType="User">
        select * from demo_user  where id in (
            <foreach collection="array" item="id" separator=",">
                #{id}/*把变量拿出来*/
            </foreach>
        )
    </select><!--动态获取数组里的数,不能写死,所以要遍历数组中每个数-->




collection:指定输入对象中集合属性名(也就是上面pojo中定义的属性名)
item:定义每次遍历后生成的对象的对象名
open:开始遍历时要拼接的字符串
close:结束遍历时要拼接的字符串
separator:定义遍历后产生的每个对象之间的字符串
<foreach></foreach>之间的内容:表示每次遍历需要拼接的字符串

例:
<update id="deleteHealthCheckSetInfos" parameterType="java.lang.String">
    update healthcheck_set_info
    set status = '0'
    where set_id in
    <foreach collection="array" item="setId" open="(" separator="," close=")">
        #{setId}
    </foreach>
</update>

2)mybatis-plus框架

使用in关键字查询(将这许多id封装成一个数组,使用时最好使用包装类型)
   Sql: select * from user where id in (1,2,3,5,7)

 service层接口

List<User> findUserByIN(Integer[] ids);

service层接口实现类

 @Override
    public List<User>  findUserByIN(Integer[] ids) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id",ids);



        //方式1: 利用条件构造器查询
//I、如果可保证查询的结果很确定只有一个用selectOne(),用对象接
//User user = userMapper.selectOne(queryWrapper);
//II、如果不能保证查询的结果只有一个用selectList(),则使用list集合接收
//List<User> userList = userMapper.selectList(queryWrapper);
        List<User> userList = userMapper.selectList(queryWrapper);
        return userlist;*/
        return userMapper.selectList(queryWrapper);
        
        //方式2: 利用API查询
        List list = Arrays.asList(ids);//将数组转化为集合,因为下面那行需要传一个集合
        /*List<User> userList2 = userMapper.selectBatchIds(list);
        System.out.println(userList2);
        return userList2;*/
        return  userMapper.selectBatchIds(list);
    }

1-2、3单条件多值(> < ≥ ≤)查询——接收到前端单个条件多个值 且不能封装成数组(同一个条件有<、>等多个关系)

因为Mybatis只支持(参数列表/参数类型)单值传参,所以要将多值的参数类型封装为单值:封装为对象或万能Map集合。

例:查询age>18并且age<100的数据库中的内容
前端传过来多个参数,却是同名,但不能使用同名提交,
不能封装成对象,但在mapper层封装成万能map集合


1)mybatis框架

方法:将多个参数封装成一个Map

方式一:在mapper层 封装——@Param   前端传过来单个参数也可以用此注解在service接,向前兼容问题

 service层接口

List<User> findUserByIn(Integer minAge, Integer maxAge);

service层接口实现类

    @Override
    public List<User> findUserByIn(Integer minAge, Integer maxAge) {
        return userMapper.findUserByIn(minAge,maxAge);      
    }

mapper层接口

   List<User> findUserByIn(@Param("minAge") Integer minAge, 					              
                           @Param("maxAge")Integer maxAge);

......Mapper.xml映射文件

	<select id="findUserByAge/findUserByAge2" resultType="User">
        <![CDATA[
             select * from demo_user
                where age  > #{minAge} and   age  < #{maxAge}
           ]]>
    </select>

          

方式二:在service层实现类 封装

 service层接口

List<User> findUserByIn(Integer minAge, Integer maxAge);

service层接口实现类

    @Override
    public List<User> findUserByIn(Integer minAge, Integer maxAge) {
        map<String Integer> map = new HashMap<>();
        map.put("MinAge",minAge);
        map.put("MaxAge",maxAge);
        return userMapper.findUserByIn(map);      
    }

mapper层接口

 List<User> findUserByAge(Map<String, Integer> map);

......Mapper.xml映射文件

	<select id="findUserByAge/findUserByAge2" resultType="User">
        <![CDATA[
             select * from demo_user
                where age  > #{minAge} and   age  < #{maxAge}
           ]]>
    </select>

          2)mybatis-plus框架

**********************************************************************************

        2、多条件查询

多条件 正常查询——接收到前端多个条件且每个条件都是单个参数

controller层将其封装成对象(user)传过来


1)mybatis框架

 service层接口

List<User> findUserByMore(User user);

service层接口实现类

 @Override
    public List<User>  findUserByMore(User user) {
        return userMapper.findUserByMore(user);
    }

            1>映射文件写法

mapper层接口

     User findUserByMore(User user);

......Mapper.xml映射文件

    
<select id="findUserByMore" resultType="com.jt.pojo.User">
        select * from 表名 where id = #{id} and name = #{name}
    </select>

            2>注解方式写法

mapper层接口

@Select("select * from 表名 where id = #{id} and name = #{name}")
User findUserByMore(User user);

2)mybatis-plus框架

        3、无条件查询

只查询主键的信息—— 进行多表关联查询操作时用

service层接口实现类

只查询主键的信息
     * API: selectObjs: 用来获取主键信息(只获取主键信息,其他的字段信息不会获取)
     * 实际用途:
     *      进行多表关联查询操作时用
    @Test
    public void test07(){
        List ids = userMapper.selectObjs(null);//
       ()里写条件;(此处写null是没有条件,即查询所有的主键信息)
        System.out.println(ids);
    }


    4、mybatis-plus分页查询(mybatise-plus 分页的规则  固定API)

1、业务层固定API

https://blog.csdn.net/fhefhffg/article/details/122324051#t86

2、编辑MP分页查询使用需要的插件(分页配置类)

https://blog.csdn.net/fhefhffg/article/details/122324051#t87

五、动态sql查询(查询条件可能为null时使用)

1.1、动态查询——mybatis

1)where+if标签动态查询——在对象中的数据不为空的前提下进行查询,将对象中的数据不为空当作where条件 

2)where+choose、when、otherwise标签分支结构动态查询——如果不想使用所有的条件,只需要满足其中一个条件时   

1.2、动态查询——mybatis-plus

利用mybatis-plus(MP) jar包简化动态sql查询操作/以后都用这个
(有的数据有时候有值,有时候没有值为null;我们不知道用户有没有传进来值,是不是null)

使用例子

2、动态修改

set+if标签动态修改——在对象中的数据不为空的前提下进行修改,将对象中的数据不为空当作set条件  


版权声明:本文为fhefhffg原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。