《MyBaits操作经验》

MyBatis-------批量插入

一、在MySQL数据库中

在mysql数据库中,使用的是foreach标签。 foreach元素的属性主要有 collection,item,index,open,separator,close。
常用的有
1.item ,是临时的元素的代表。迭代的时候要用上它,很容易被忽略从而报错。
2.collection标签是集合的代表。如果传入的值是List集合,那么collection的值是list。如果传入的是数组,那么collection的值是array。如果在接口上定义了传递进来的参数,那么collection的值就是那么定义好的参数,比如下面的tags。

public interface ArticleMapper ... 
        int insertArticleTag(@Param("tags")List tags);

index表示迭代的位置。
open表示从什么地方开始,close表示什么地方结束
separator表示在每次进行迭代之间以什么符号作为分隔符。MySQL中通常是",",Oracle中有时写union。

插入实例。

INSERT INTO t_tag(name,articleId) 
VALUES('good','22') , ('nice','22'),('perfect','22')

        INSERT INTO t_tag(name,articleId)
        VALUES
        
            (#{tag.name},#{tag.articleId})
        
    

注意:这里需要使用tag.name,我第一次写的时候,忘记了加上item中定义的临时属性,导致出错。

二、Oracle数据库

MySQL写法,转成Oracle。


        INSERT INTO T_REGION
        (
        ID,
        GRADE,
        COLLEGE_CODE,
        TYPE,
        MAX,
        GMT_CREATE
        )
        SELECT 序列.NEXTVAL ID, A.*
        FROM(
        
            SELECT
            #{entity.grade} GRADE,
            #{entity.collegeCode} COLLEGE_CODE,
            1 TYPE,
            #{entity.maxProjectCredit} MAX,
            sysdate GMT_CREATE
            FROM dual
        
        )A
    
 
 
 
        INSERT INTO t_region (
        grade,
        college_code,
        type,
        max,
        gmt_create
        )
        VALUES
        
        
            (
            #{entity.grade},
            #{entity.collegeCode},
            2,
            #{entity.max},
            now()
            )
        
    

MyBatis--------模糊查询

一、使用${ }

不能够防止SQL注入。MySQL与Oracle通用


二、把模糊查询的 %加上引号

就像这样子, "%"#{param}"%"

  

多个匹配条件可以像这样写

    

三、使用函数进行拼


MyBatis--------生成主键

一、在MySQL数据库中的写法

在mysql数据库中,写法比较简单。在Mybatis配置文件中添加 userGeneratedKeys="true" keyProperty="id"

这样就能把我们插入的实体的主键id赋值。下次使用的时候,再调用 对象.getId()就能获取到刚才生成的主键。

注意点:
1.实体的id属性需要有setId()方法。
2.数据库中的表主键设置为 auto_increment

示例

   
        INSERT INTO t_account(nickname,loginName,password)
        VALUE (#{nickname},#{loginName},#{password},#{idCard})
    

在这个例子里面,被插入的Account对象在构造的时候Long id 属性为null。在插入数据库完成后,作为参数的account对象的Long id属性被赋予为数据库中的记录的主键的值。

二、在Oracle数据库中的写法

我们知道,mysql优化里面有一条:为每一张表都设置一个int类型的主键,它能够自增,方便分页和排序。

Oracle数据库中,它不支持主键自增,所以需要我们从序列中取得最新的序列值。

在Mybatis中,可以使用 selectKey标签,在执行SQL语句之前,为实体的ID属性赋值,然后再执行SQL。


        
            select SEQ_EXAMINEE.nextval from dual    
        
        insert into T_Register(id,idCard,cellPhone,password,name)
        values(#{id},#{idCard},#{cellPhone},#{password},#{name})

MyBatis--------查询参数携带集合

一、携带参数

Java的查询参数里携带了一个集合。

@Data
public class TeacherParam {
 
    private List teacherIds;
}

这个参数作为查询Mapper的参数。

@Repository
@Mapper
public interface ClassRoomMapper {
 
    List queryTeacher(TeacherParam teacherParam);
}

以下是调用这个内部集合的例子。

    

MyBatis-------时间函数处理

一、MySQL解决方案

MySQL使用date_format函数来解决。


image.png

image.png
SELECT * FROM `t_log`
WHERE 
# 比19号多,但是不到21号,就是查询20号
date_format(operation_time,'%Y-%m-%d') > '2020-03-19'
AND 
date_format(operation_time,'%Y-%m-%d') < '2020-03-21'

查询结果:


image.png

在MyBatis中写法实例。startDate是字符串类型,operation_time是SQL的时间类型

    
        = #{startDate}
        ]]>
    
    
        
    

二、Oracle解决方案

Oracle使用to_date函数来解决。
startDate与endDate是字符串类型
从实际解决方案上来看,是利用Oracle的to_date函数,将参数转为时间与表中的记录进行对比。
【t.CREATE_DATE】 ,这个字段是Oracle的DATE类型。
【 #{startDate}】 ,传入的参数为字符串为类型

    
        and
        = 
                     to_date(concat(#{startDate},'00:00:00'),'YYYY-MM-DD HH24:MI:SS')
        ]]>
    
 
    
        and 
    

MyBatis-------使用IN语句

一、使用foreach

注意点:Java的List需要传 List


解析后效果:

SELECT * from t_article WHERE id in ( 21 , 22 ,23 )

删除实例与插入实例大同小异。比如

delete from t_tag where id in ( 58 , 59 ) 

二、字符串情况

如果希望达到的效果是 in ( '2019-2020-1' , '2019-2020-2' '2020-2021-1' )
集合需要传 List



    #{termCode}

MyBatis-------级联查询(一对一、一对多)

一、持有其它对象

package com.tyzhou.stu.model;
 
import lombok.Data;
 
@Data
public class ClassRoom {
    /**
     * 班级编号
     */
    private Long id;
    private String name;
    /**
     * 一个班级有一个班主任
     */
    private Teacher teacher;
}
 
@Data
public class Teacher {
 
    private Long id;
    private String name;
}

核心:映射到某个对象的某个属性中

    
image.png

二、持有其它对象集合

一个老师会管多个班级。


image.png

image.png
@Data
public class Teacher {
 
    private Long id;
    private String name;
    /**
     * 一个老师管理多个班级
     */
    List classRoomList;
}
 
@Data
public class ClassRoom {
    /**
     * 班级编号
     */
    private Long id;
    private String name;
}

拨云见日:

(1) 最先查询出老师的相关数据,并使用resultMap进行映射

(2) 在resultMap映射完老师实体后,将老师实体的主键ID作为参数传递

(3) 最后一个查询,它接收老师主键ID作为条件,查询出老师管理的多个班级集合

    
    
 
    
    
        
        
        
        
        
    
 
    
    
image.png

MyBatis--------格式化性别等字段

通用写法

SELECT 
USER_ACCOUNT,
(CASE 
  WHEN SEX = 1 THEN '男' 
  WHEN SEX = 2 THEN '女' 
  ELSE '未知'
END )sex
FROM m_user u 

Oracle特有写法

SELECT 
   USER_ACCOUNT,
   decode(sex,1,'男',2,'女','未知') "sex"
FROM m_user u 

再提供一个判断个数的示例

SELECT DECODE(COUNT(1),0,'','有调课') from 表

MyBatis-------特殊符号处理(CDATA标签)

二、CDATA标签


MyBatis--------占位符${}与#{}

一、基本区别

简单的说就是#{}传过来的参数带引号,而${}传过来的参数不带单引号。
涉及到这个问题,最初是在毕业设计项目中,进行动态排序发现的问题。看下面的SQL语句

    

我的目的是在文章表't_article'中,根据文章的点击量'click'来排序。但是传过来的参数带上了引号,因此排序无效
执行出来的SQL语句的效果是: SELETE * FROM t_article order by 'click'。
修改后的SQL语句如下,


很简单,就是把#{}修改成了${},这样的话,传递过来的值就不会带上引号了。
现在执行出来的SQL语句的效果是: SELETE * FROM t_article order by click。达到了预期的效果

二、#{}对SQL语句的影响

用#{}传过来的参数可以防止SQL注入,而用${}就不行了。
如何防止SQL注入:
1.对用户的输入进行校验,可以通过正则表达式,或限制长度
2.不要使用动态拼装sql,使用预编译的带占位符的SQL语句。比如使用preparedStatement

MyBatis-------获取系统当前时间

一、MySQL

insert into t_user(id,idcard,operation_time) values( #{id} , #{idCard} , now() )

二、Oracle

insert into t_user(id,idcard,operation_time) values( #{id} , #{idCard} , sysdate)

MyBatis-------返回值是对象类型需要显示指明

    /**
     * 获取表里所有记录的数量
     *
     * @param statement 要执行的SQL语句的标记,对应的是Mybatis中的id的值
     * @return          表里所有记录的数量
     */
    Integer getCount(String statement);

正确的Mybatis配置,要加上 resultType = 'integer'。


image.png

MyBatis-------内查询

select  stuId ,teacherId  from T_Table

比如上述的SQL语句中,查询出来的数据是stuId和teacherId 。stuId对应的那条数据在 T_SYS_PARAM 中,teacherId也在T_SYS_PARAM 表中,但是它们对应的是不同的记录,采用LEFT JOIN T_SYS_PARAM 的方法并不奏效。为了查询出学生的名字和老师的名字,必须分别查询。

        select  
 
        t.stuId , 
 
        t.teacherId  ,
 
        (select p.stuName from T_SYS_PARAM  p  where p.id= t.stuId) stuName ,
 
        (select p.tecName from T_SYS_PARAM  p  where p.id= t.teacherId) tecName 
 
        from T_Table t

所以说,怪不得项目里面有那么多像 " ( ) "这样的查询

MyBatis-------批量更新

Oracle

如果操作成功,返回值为 Integer 类型的 -1


        
            UPDATE T_TABLE SET
            A= #{item.a},
            B= #{item.b},
            C= #{item.c},
            D= sysdate
            where ID = #{item.id}
        
    

二、MySQL

UPDATE m_classroom
SET name = 3,
 teacherId = 3
WHERE id = 1;
 
UPDATE m_classroom
SET name = 3,
 teacherId = 3
WHERE id = 2;

Mybatis-----Oracle关于0开头的小数,开头的0消失的问题

SELECT TO_CHAR(51,'fm99999990.099') from dual; --51.0
SELECT TO_CHAR(0.42,'fm99999990.099') from dual; --0.42

MyBatis-------解决Mysql LIMIT分页关键字offset偏移量过大

SELECT * FROM T_TABLE LIMIT 【START, SIZE 】

LIMIT 使用上述两个参数,一个是从第多少条记录开始START,另外一个是希望要查询出来得个数SIZE

随着START值的增加,那么此查询条件的速度会越来越慢。

解决方案的前提是该表的主键是自增的。那么就能先确定到从第多少条记录开始

-定位主键方法

SELECT * FROM t_user LIMIT 20883005,10
修改成
SELECT * FROM t_user WHERE id>(SELECT ID FROM t_user LIMIT 20883005,1) LIMIT 10

MyBatis--------解决Oracle的to_number函数不支持有字母的情况

需求:某表的某列是varchar类型,此列里存放的不全是数字,如何使用to_number函数呢?
解决:使用translate函数

        SELECT ${primaryKey} FROM ${sourceTable}
        WHERE
        1=1
        -- 匹配全数字类型
        AND regexp_like(${sourceField}, '(^[0-9]+.[0-9]+$)|(^[0-9]$)')
        
            = #{minValue}
             ]]>
        
        
            

MyBatis-------if test标签处理相等的情况

 
            SELECT ${primaryKey} FROM ${sourceTable}
            WHERE
            1=1
            AND ${sourceField} REGEXP "[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+"
    

Oracle

    

身份证

MySQL

  

Oracle

    

电话号码

MySQL

  

Oracle

    

MyBatis--------查询7天内的记录

MySQL
        SELECT count(1) FROM ${sourceTable}
        WHERE
        1=1
        AND ${createTime} >= DATE_SUB(NOW(),INTERVAL 7 DAY)

Oracle
        SELECT count(1) FROM ${sourceTable}
        WHERE
        1=1
        AND ${createTime} >= sysdate - 7

MyBatis--------MybatisPlus继承体系小记录

@Data
public class BaseDO {

    @TableField(fill = INSERT)
    @TableLogic
    protected Integer isDeleted;

    @TableField(fill = INSERT_UPDATE)
    protected Date gmtCreate;
    @TableField(fill = INSERT_UPDATE)
    protected Date gmtModified;
    @TableField(fill = INSERT)
    protected String createId;
}

@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@TableName(value = "t_xxx")
@Accessors(chain = true)
public class RuleDO extends BaseDO {

    private String id;
    private String ruleName;
    private Integer type;
    private String calculateTypeId;
}
在这里插入图片描述
@Configuration
public class MybatisPlusConfig {


    @Component
    static class XXX implements MetaObjectHandler {

        @Override
        public void insertFill(MetaObject metaObject) {
            // 对应实体需要标注@TableField(fill = FieldFill.INSERT) 或
            //                @TableField(fill = FieldFill.INSERT_UPDATE)
            this.strictInsertFill(metaObject, "createId", String.class,
                    "1");
            this.strictInsertFill(metaObject, "gmtCreate", Date.class, new Date());
          
            this.strictInsertFill(metaObject, "gmtModified", Date.class, new Date());
            this.strictInsertFill(metaObject, "isDeleted", Integer.class, 0);
        }

        @Override
        public void updateFill(MetaObject metaObject) {
            // 对应实体需要标注@TableField(fill = FieldFill.UPDATE) 或
            //                @TableField(fill = FieldFill.INSERT_UPDATE)
            setFieldValByName("gmtModified", new Date(), metaObject);
        }
    }
}

MyBatis--------Oracle超过1000条的问题

select * from test_table
where 1 = 1 
 
 
    AND PK_ID IN
    
     
        
            
                
                    ) OR PK_ID IN (
                    ,
                
            
            #{Id}
        
    
 

MyBatis Plus Service CRUD接口测试

Service如何集成MP

@Mapper
public interface RoleMapper extends BaseMapper {
}
 
 
public interface RoleService extends IService{
}
 
 
@Service
@RequiredArgsConstructor
public class RoleServiceImpl extends ServiceImpl implements RoleService{
}

插入

boolean save(T entity) 
boolean saveBatch(Collection entityList)
boolean saveBatch(Collection entityList, int batchSize);

更新

根据ID更新,null值的属性不参与更新

Employee employee = new Employee();
        employee.setId(7);
        employee.setLastName("a");
        employee.setAge(23);
        employee.setEmail(null);
        employee.setGender(null);
 
        service.updateById(employee);
 
 UPDATE tb_employee SET last_name='a', age=23
 WHERE id=7;

根据条件进行更新,并置空其他属性(项目库的我那个头疼的置空功能就能用这个解决)。

        RoleDO roleDO = new RoleDO(roleDto);
 
        roleService.update(roleDO, new UpdateWrapper().lambda().
                eq(RoleDO::getId, roleDO.getId())
                //如果要置空其他的属性
                .set(RoleDO::getUpdateId, null)
                .set(RoleDO::getUpdateTime, null)
        );

查询

T getById(Serializable id)

获取一个(如果出现多个,则报错,传统的Excepted One , Actual Two 异常)

roleService.getOne(new QueryWrapper().lambda()
                .eq(RoleDO::getIsManager, role.getIsManager())
);

删除

根据主键ID

boolean removeById(Serializable id)

根据条件进行删除

        RoleDO roleDO = new RoleDO(roleDto);
        roleService.remove(new QueryWrapper().lambda().
                eq(RoleDO::getId, roleDO.getId())
        );

通过Map拼接条件删除

        Map map = new HashMap<>();
        map.put("id", roleDO.getId());
        map.put("role_name", roleDO.getRoleName());
        roleService.removeByMap(map);
 
where id = #{id} AND role_name = #{roleName}

批量查询

查询所有

 List list()

根据ID批量查询

List listByIds(Collection idList)

根据条件批量查询

        RoleDO roleDO = new RoleDO(dto);
        return roleService.list(new QueryWrapper().lambda()
                .eq(RoleDO::getIsManager, roleDO.getIsManager())
        );

分页查询

pageIndex第几页,pageSize每页几条数据

        Page page = new Page(pageIndex,pageSize);
        return roleService.page(page);

根据条件分页查询

    @GetMapping(value = "/pageByWrap")
    @SuppressWarnings(value = "unchecked")
    public Object pageByWrap() {
        return roleService.page(PageContext.getPage(), new QueryWrapper().lambda()
                .eq(RoleDO::getIsManager, "0")
        );
    }

查个数数量

int count()

根据条件,查询总记录数

        return roleService.count(new QueryWrapper().lambda()
                .eq(RoleDO::getIsManager, "0")
        );

MyBatis Plus Mapper CRUD接口测试

插入

int insert(T entity);

删除

int deleteById(Serializable id);
int deleteBatchIds(Collection idList);

根据条件进行删除。原理为SQL语句拼接,因此Map中需要传输数据库字段列
实质为 delete from 表 where 【key1 = value1】 AND 【key2 = value2】
【key1-value1】【key2-value2】为Map的键值对

int deleteByMap(Map columnMap);

更新

根据ID更新。null值忽略。

        Employee employee = new Employee();
        employee.setId(7);
        employee.setLastName("a");
        employee.setAge(23);
        employee.setEmail(null);
        employee.setGender(null);
        mapper.updateById(employee);
 
 UPDATE tb_employee SET last_name='a', age=23
 WHERE id=7;

根据条件更新,null值忽略。

        Employee employee = new Employee();
        employee.setId(7L);
        employee.setLastName("c");
        //这里设置的null,就是说不操作email字段
        employee.setEmail(null);
        employee.setGender(null);
        employee.setAge(23);
        mapper.update(employee, new UpdateWrapper().lambda()
                .eq(Employee::getId, 7)
        );
 
 UPDATE tb_employee SET last_name='c', age=23
 WHERE (id = 7);

定制置空。

        Employee employee = new Employee();
        employee.setId(7L);
        employee.setLastName("c");
        //这里设置的null,就是说不操作email字段
        employee.setEmail(null);
        employee.setGender(null);
        employee.setAge(23);
        mapper.update(employee, new UpdateWrapper().lambda()
                .eq(Employee::getId, 7)
                //这里可以定制置空SQL
                .set(Employee::getEmail,null)
                .set(Employee::getGender,"")
        );
 
 UPDATE tb_employee SET last_name='c', age=23, email=null,gender=''
 WHERE (id = 7);

你可能感兴趣的:(《MyBaits操作经验》)