Mybatis-plus的便捷增删改查【部分】【代码】
作者:互联网
Mybatis-plus官方文档
本文联合 lombok 插件使用,用到链式写法,需要 lombok 依赖
示例数据库文件
-- 建表语句
create table emp
(
EMPNO int, -- 员工号
ENAME varchar(10), -- 员工姓名
JOB varchar(9), -- 工作岗位
MGR int, -- 经理的员工号,外键
HIREDATE date, -- 入职时间
SAL double, -- 底薪
COMM double, -- 提成
DEPTNO int, -- 部门编号
primary key(EMPNO)
);
CREATE TABLE dept
(
DEPTNO int, -- 部门编号
DNAME varchar(13), -- 部门名称
LOC VARCHAR(13), -- 部门地点
primary key(DEPTNO)
);
-- 建表语句
commit;
-- 插入数据
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7369,'SMITH','CLERK',7902,'2003-12-17',800,null,20);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7499,'ALLEN','SALESMAN',7698,'2007-9-3',1600,300,30);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7521,'WARD','SALESMAN',7698,'2005-3-8',1250,500,30);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7566,'JONES','MANAGER',7839,'2007-7-7',2975,null,20);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7654,'MARTIN','SALESMAN',7698,'2005-5-6',1250,1400,30);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7698,'BLAKE','MANAGER',7839,'2005-5-6',2850,null,30);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7782,'CLARK','MANAGER',7839,'2010-3-1',2450,null,10);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7788,'SCOTT','ANALYST',7566,'2005-5-6',3000,null,20);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7839,'KING','PRESIDENT',null,'2001-5-6',5000,null,10);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7844,'TURNER','SALESMAN',7698,'2008-8-8',1500,0,30);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7876,'ADAMS','CLERK',7788,'2005-5-6',1100,null,20);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7900,'JAMES','CLERK',7698,'2005-5-6',950,null,30);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7902,'FORD','ANALYST',7566,'2005-5-6',3000,null,20);
Insert into EMP (EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO) values (7934,'MILLER','CLERK',7782,'2005-5-6',1300,null,10);
Insert into DEPT (DEPTNO,DNAME,LOC) values (10,'ACCOUNTING','NEW YORK');
Insert into DEPT (DEPTNO,DNAME,LOC) values (20,'RESEARCH','DALLAS');
Insert into DEPT (DEPTNO,DNAME,LOC) values (30,'SALES','CHICAGO');
Insert into DEPT (DEPTNO,DNAME,LOC) values (40,'OPERATIONS','BOSTON');
commit;
基本增删改查【测试类先试一下awa】
package com.muhuai.mybatis_plus;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.muhuai.mybatis_plus.mapper.DeptMapper;
import com.muhuai.mybatis_plus.model.domain.Dept;
import com.muhuai.mybatis_plus.service.DeptService;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
// 这个测试会能够十分明显地看出lombok的精妙之处【反正很牛逼这个玩意】
// 应该说链式写法被lombok支持?
@SpringBootTest
@MapperScan(basePackages = "com.muhuai.mybatis_plus.mapper")
public class MybatisplusApplicationTests
{
@Autowired
// 这个报错不影响运行 想要这个不报错的话,在接口上注释Repository
private DeptMapper deptMapper;
@Autowired
private DeptService deptService;
@Test
// 插入测试
public void insert_dept()
{
// 添加一个dept
// 这个写法应该是lpmbok支持的【咱就是说真的精妙】
// 注意一个小细节:Java中的字符串用""括起来,如果用''括起来,编译器认为这是一个字符
Dept dept = new Dept().setDeptno(3).setDname("Muhuai").setLoc("Beijing");
deptMapper.insert(dept);
// Service的方法
// save(Entity)
// deptMapper.insert(dept); == deptService.save(dept);
deptService.save(dept);
// saveBatch(Entity) 批量添加
// saveOrUpdate(Entity) 如果Entity的主键已经在数据库存在,则update,否则insert
// saveOrUpdateBatch 同理
}
@Test
// 删除数据测试
public void delete_dept()
{
// deleteById() 根据id删除实体
// deleteBatchIds(Collection) 删除一堆id对应的实体
// deleteByMap(Map) 删除Map键值对对应的实体
// 如 : 删除dept表中deptno = 3 && dname = Muhuai 的实体
Map<String,Object> map = new HashMap<>();
map.put("deptno",3);
map.put("dname","Muhuai");
deptMapper.deleteByMap(map);
// delete(Wrapper<> wrapper) 条件构造器
// 注意!!!这个Wrapper是baomidou里面的
// Wrapper是接口,它有几个实现类,详情见wiki.suncaper.net
// QueryWrapper - 这个缺点是硬编码,里面的条件是写死的
QueryWrapper<Dept> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deptno",11).eq("dname","Muhuai");
deptMapper.delete(queryWrapper);
// LambdaQueryWrapper
LambdaQueryWrapper<Dept> lambdaQueryWrapper = new LambdaQueryWrapper<>();
// 这个Dept::getXXX 的方法就是在Dept类的 @Data注解实现的
lambdaQueryWrapper.eq(Dept::getDeptno,1).eq(Dept::getDname,"Muhuai");
deptMapper.delete(lambdaQueryWrapper);
}
@Test
// 修改测试
public void update_ddept()
{
// updateById()
// update(Entity,wrapper) 执行语句的结果是 符合wrapper条件的实体被替换成Entity的值?
// 不过这个主键应该是不能改的【就是说即便在这里写了setdeptno,deptno也不会被改变awa】
Dept updated_dept = new Dept().setDeptno(23).setDname("MH").setLoc("Beijing");
LambdaQueryWrapper<Dept> query_wrapper = new LambdaQueryWrapper<>();
query_wrapper.eq(Dept::getDeptno,2).eq(Dept::getDname,"Muhuai");
deptMapper.update(updated_dept,query_wrapper);
}
@Test
// 查询测试
public void select_dept()
{
// Mapper层提供的接口
// selectById() 根据一个id查询
// selectBatchIds() 根据一堆id查询
// selectList(wrapper) 根据条件构造器查询,结果是一个List
// selectCount() 查询个数
// selectMaps()
// selectOne 一定要保证只能查询到一个结果,不然就要报错
// Service层提供的接口
}
}
自定义SQL
// 自定义SQL 一定是写在 mapper ,这边调用 mapper 层的方法
// mapper 层的方法对应 mapper.xml,【alt + enter 真的好用啊!!!】
// 如果 mapper 的方法名为 get 之类的,alt + enter 会直接生成 sql 到 mapper.xml
// 自定义sql获取参数的类型 mapper.xml如何写
// 单个基本数据类型 -- 直接 #{} 获取参数就行 如:where id = #{id}
// 多个基本数据类型 -- 参数必须取别名,然后 ${} 获取别名
// 用 @Param 注解在参数前面取一个名字
// 这样不容易出错awa
// 单个对象 -- 对象形式的参数也最好取别名,对象传参传送的是一堆键值对
// ${对象.属性名}
// 多个对象同理
// 反正取别名nice
练习题
一对一的关联查询
理解为:通过查询 A,然后通过 A,查询到 B。如:查询员工的姓名及其直接上级的姓名【这里将一张表当成两张表看待】
一般表现为类似于这样的 SQL
select emp.ename,emp_t.ename from emp as emp,emp as emp_t where emp.mgr = emp_t.empno;
select ename,dname from emp,dept where job = 'CLERK' and dept.deptno = emp.deptno;
- 先去 A 的实体类里面添加字段,字段类型为 B
注意!!!
添加的这个字段不是数据表的字段,但是Mybatis默认实体类的字段对应数据表结构,为解决这个问题,需要在这个字段上面加注解
@TableField(exist = false)
- 去mapper.xml里面创建返回类型【直接上代码】
注意!!!
标签中的 column 对应查询返回的字段名【或者说对应数据库字段名】
为了避免 association 标签中返回这个字段名和其他的重复,需要更改查询语句【用 as 给别名】
select emp.ename,emp_t.ename as mgr_ENAME
<!-- 查询员工的直接上级 -->
<!-- type对应实体类的位置 -->
<resultMap id="MgrResultMap" type="com.muhuai.mybatis_plus.model.domain.Emp">
<result column="ENAME" property="ename" />
<association property="mgrid" javaType="com.muhuai.mybatis_plus.model.domain.Emp">
<result column="mgr_ENAME" property="ename"/>
</association>
</resultMap>
<!-- resultMap是刚刚创建的那个 -->
<select id="getemp3" resultMap="MgrResultMap">
select emp.ename,emp_t.ename as mgr_ENAME from muhuaifeature.emp as emp,muhuaifeature.emp as emp_t
where emp.mgr = emp_t.empno;
</select>
- 测试使用
// -- 3.列出所有员工的姓名及其直接上级的姓名。
@Test
public void s_emp_3()
{
// 这个是一对一的查询,去Emp里面加一个字段
List<Emp> emp_3 = new ArrayList<>();
emp_3 = empMapper.getemp3();
for(Emp emp:emp_3)
System.out.println(emp.getEname() + ":" + emp.getmgr_name());
}
一对多的关联查询
和一对一类似,不过这个是 通过查询 A,通过 A 查询到一堆 B
如:查询部门名称和这些部门的员工信息 | 查询和 'Muhuai' 年龄一样的人的选课一般表现为这样的 SQL
select dept.deptno,dname,emp.* from dept left outer join emp on emp.deptno = dept.deptno;
- 同理,在 A 中添加字段【列表类型】
注意!!!
添加的这个字段不是数据表的字段,但是Mybatis默认实体类的字段对应数据表结构,为解决这个问题,需要在这个字段上面加注解
@TableField(exist = false)
- 同理,在 mapper.xml 创建返回类型【还是直接上代码】
注意!!!
标签中的 column 对应查询返回的字段名【或者说对应数据库字段名】
为了避免 association 标签中返回这个字段名和其他的重复,需要更改查询语句【用 as 给别名】
select emp.ename,emp_t.ename as mgr_ENAME
注意!!!
<!-- 部门的成员信息 -->
<resultMap id="DeptEmpMap" type="com.muhuai.mybatis_plus.model.domain.Dept">
<id column="D_DEPTNO" property="deptno" />
<result column="DNAME" property="dname" />
<result column="LOC" property="loc" />
<collection property="dept_emp" ofType="com.muhuai.mybatis_plus.model.domain.Emp">
<id column="EMPNO" property="empno" />
<result column="ENAME" property="ename" />
<result column="JOB" property="job" />
<result column="MGR" property="mgr" />
<result column="HIREDATE" property="hiredate" />
<result column="SAL" property="sal" />
<result column="COMM" property="comm" />
<result column="DEPTNO" property="deptno" />
</collection>
</resultMap>
<select id="getdept5" resultMap="DeptEmpMap">
select dept.deptno as D_DEPTNO,dname,emp.* from
muhuaifeature.dept left outer join muhuaifeature.emp on emp.deptno = dept.deptno;
</select>
- 测试使用
// -- 5.列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门
@Test
public void s_dept_5()
{
List<Dept> dept_5 = new ArrayList<>();
dept_5 = deptMapper.getdept5();
for(Dept dept:dept_5)
{
System.out.println("部门名称: " + dept.getDname());
List<Emp> temp_emp = dept.getDept_emp();
for(Emp emp:temp_emp)
{
System.out.println(dept.getDept_emp().toString());
}
}
}
示例代码
Mapper.java 文件里的接口函数自动生成,这里就不放了
另外一些重复的函数我也就不放了,放一点典型的就好
实体类中的注解
// 声明这个字段不是数据表中的
// 员工的直接上级
@TableField(exist = false)
private Emp mgrid;
// 员工所属的部门
@TableField(exist = false)
private Dept emp_dept;
// 员工总工资
@TableField(exist = false)
private Double total_sal;
// 每种工作的最低工资
@TableField(exist = false)
private Double lest_sal;
// 年薪
@TableField(exist = false)
private Double year_sal;
// 返回直接上级Emp的名字
// 其实这一个方法可以不写的,返回的类型是Emp,里面的getename方法就可以直接实现
public String getmgr_name()
{
return mgrid.ename;
}
另外,经过测试,新加的字段因为 @Data 注解的原因,也是自动生成 get | set 方法
EmpMapper.xml
查询的返回值可以表示成 引用对象A | 引用对象B | 基础类型C
<!-- 查询员工部门及总工资 -->
<resultMap id="TotalsalResultMap" type="com.muhuai.mybatis_plus.model.domain.Emp">
<result column="ENAME" property="ename" />
<association property="emp_dept" javaType="com.muhuai.mybatis_plus.model.domain.Dept">
<result column="DNAME" property="dname"/>
</association>
<association property="total_sal" javaType="java.lang.Double">
<result column="total_sal" property="total_sal"/>
</association>
</resultMap>
<select id="getemp14" resultMap="TotalsalResultMap">
select ename,dname,(ifnull(sal,0) + ifnull(comm,0)) as total_sal from
emp,dept where emp.deptno = dept.deptno;
</select>
引申问题
$ 和 # 的区别
- 是占位符,防止SQL注入,调用PreparedStatement
- 以拼接的方式写进SQL,有SQL注入风险,调用Statement
举例来说 查询 name 中带有 "mu" 的数据
SQL语句:
select * from user where name like '%mu%';
那么这个语句在 mapper.xml 中应该怎么写?
select * from user where name like '%#{name}%'
select * from user where name like '%'#{name}'%'
select * from user where name like '%${name}%'
因为 name 作为 String 类型的数据,自带 '' ,那么第二句的 SQL
select * from user where name like '%'mu'%';
$ 直接进行字符串拼接 -- 对应正确的 SQL 语句
SQL中字段名和主键名不匹配怎么办
标签:Insert,--,改查,dept,plus,emp,Mybatis,values,DEPTNO 来源: https://www.cnblogs.com/Muhuai/p/16319691.html