在学习mybatis-plus这篇文章时
需要掌握一些知识点
以及
这篇文章的学习知识点汇总主要通过该链接
MyBatis plus实战视频教程-带你快速掌握MyBatis-plus
主要的代码学习
可通过如下进行获取
mybatis_plus学习代码从入门到精通.rar
具体的步骤为
在测试类中或者service注入dao接口,实现动态代理创建dao的实现类对象
调用BaseMapper中的方法,完成数据库的添加操作
先创建数据库文件
创建一个表
记得数据库的主键要设置一个自增的功能
不然会出现这种bug
出现Field ‘id‘ doesn‘t have a default value; nested exception is java.sql.SQLException的解决方法
在代码连接数据库中
代码要设置连接的端口账号密码以及数据库依赖文件等
先创建一个项目
在代码中创建连接数据库的配置文件
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/springdb?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
需要额外引入mybatis-plus的依赖文件
com.baomidou
mybatis-plus-boot-starter
3.0.5
以及数据库的依赖文件
mysql
mysql-connector-java
runtime
5.1.6
此处数据库的相关部分就到这里
接下来是构建一个实体类
实体类的名字要和数据库名字一样
@TableId(
value="id",
type = IdType.AUTO
)
private Integer id;
private String name; // null
private String email;
//实体类属性,推荐使用包装类型, 可以判断是否为 null
private Integer age; // 0
可以通过使用@data注解自动生成实体类get、set等方法
spring中@Data注解详细解析
也可以手动设置
可以看到实体类上面还有注解
大致意思是
mapper类,也就是DAO接口
要实现BaseMapper,指定实体类
public interface UserMapper extends BaseMapper {
}
具体BaseMapper类的定义源码如下
主要是这个框架中的对象,定义17个操作方法(CRUD)
在启动类中还要加一个注解扫描为了扫描这个类@MapperScan
:扫描器,指定Mapper类所在的包
@SpringBootApplication
@MapperScan(value = "com.wkcto.plus.mapper")
public class PlusApplication {
public static void main(String[] args) {
SpringApplication.run(PlusApplication.class, args);
}
}
测试文件
关于@SuppressWarnings
这个注解,主要是为了抑制警告值
具体信息可看我之前的文章
Spring中@SuppressWarnings注解详细解析
而对于@RunWith(SpringRunner.class)
,Test测试类要使用注入的类,比如@Autowired注入的类,才可实例化到spring容器
@SuppressWarnings("all")
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserTest {
//定义StudentMapper
@Autowired
private UserMapper userDao;
@Test
public void testInsertStudent() {
User user = new User();
user.setName("zs");
user.setEmail("zd.com");
user.setAge(20);
int rows = userDao.insert(user);
System.out.println("inserStudent rows:" + rows);
}
}
在控制台打印日志
输出数据库的信息
主要在yml配置
具体信息为
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
完整代码就不书写了,只写核心代码
具体方法都是BaseMapper
这个类由来
//添加数据后,获取主键值
@Test
public void testInsertGetId(){
User user = new User();
user.setName("李四");
user.setAge(20);
user.setEmail("[email protected]");
int rows = userDao.insert(user);
System.out.println("insert user rows:"+rows);
//获取主键id ,刚添加数据库中的数据的id
int id = user.getId();//主键字段对应的get方法
System.out.println("主键id:"+id);
}
在定义实体类的时候,最好使用包装类型,情况如下:
@Test
public void testUpdateUser(){
User user = new User();
user.setName("修改的数据");
user.setAge(22);
user.setEmail("[email protected]");
user.setId(2);
//执行更新,根据主键值更新
/*UPDATE user SET name=?, email=?, age=? WHERE id=?
*更新了所有非null属性值, 条件where id = 主键值
*/
int rows = userDao.updateById(user);
System.out.println("update rows:"+rows);
}
deleteById()
@Test
public void testDeleteById(){
//DELETE FROM user WHERE id=?
int rows = userDao.deleteById(3);
System.out.println("deleteById:"+rows);
}
deleteByMap(map对象);
@Test
public void testDeleteByMap(){
//创建Map对象,保存条件值
Map map = new HashMap<>();
//put("表的字段名",条件值) , 可以封装多个条件
map.put("name","zs");
map.put("age",20);
//调用删除方法
//DELETE FROM user WHERE name = ? AND age = ?
int rows = userDao.deleteByMap(map);
System.out.println("deleteByMap rows:"+rows);
}
deleteBatchIds()
删除的话还可以使用lambda表达式
将其上面列表的代码替换为
//使用lambda创建List集合
List ids = Stream.of(1, 2, 3, 4, 5).collect(Collectors.toList());
selectById
@Test
public void testSelectById(){
/**
* 生成的sql: SELECT id,name,email,age FROM user WHERE id=?
* 如果根据主键没有查找到数据, 得到的返回值是 null
*/
User user = userDao.selectById(6);
System.out.println("selectById:"+user);
//在使用对象之前,需要判断对象是否为null
if(user != null){
//业务方法的调用
}
}
selectBatchIds
@Test
public void testSelectBatchId(){
List ids = new ArrayList<>();
ids.add(6);
ids.add(9);
ids.add(10);
//查询数据
//SELECT id,name,email,age FROM user WHERE id IN ( ? , ? , ? )
List users = userDao.selectBatchIds(ids);
System.out.println("size:"+users.size());
for (User u:users){
System.out.println("查询的用户:"+u);
}
}
也可以使用lambda表达式进行查询
List ids = Stream.of(6, 9, 10, 15).collect(Collectors.toList());
selectByMap()
@Test
public void testSelectMap(){
//创建Map,封装查询条件
Map map = new HashMap<>();
//key是字段名, value:字段值 ,多个key,是and 联接
map.put("name","zhangsan");
map.put("age",20);
//根据Map查询
//SELECT id,name,email,age FROM user WHERE name = ? AND age = ?
List users = userDao.selectByMap(map);
users.forEach(user -> {
System.out.println("selectByMap:"+user);
});
}
以下章节同样也是讲增上改查的用法(就不列举出小标题了)
主要的区别在于
extends Model
,之后调用model中类来实现curd//不需要
//使用自动注入, 注入Mapper对象(Dao)
@Autowired
private UserMapper userDao;
查看model类中的源码
和原先步骤一样
使用AR,要求实体类需要继承MP中的Model,Model中提供了对数据库的CRUD的操作
mapper文件也要书写一下
因为DeptMapper是不需要使用的,MP需要使用DeptMapper获取到数据库的表的信息。
如果不定义DeptMapper, MP会报错, 找不到表的定义信息
public interface DeptMapper extends BaseMapper {
}
测试类记得要加上这个注解
对于@RunWith(SpringRunner.class)
,Test测试类要使用注入的类,比如@Autowired注入的类,才可实例化到spring容器
具体测试类如下
调用的是model中的insert方法
@Test
public void testARInsert(){
//定义dept的实体
Dept dept = new Dept();
dept.setName("行政部");
dept.setMobile("010-66666666");
dept.setManager(5);
//调用实体对象自己的方法,完成对象自身到数据库的添加操作
boolean flag = dept.insert();
System.out.println("ar insert result:"+flag);
}
@Test
public void testARUpdate(){
//定义实体Dept
Dept dept = new Dept();
// dept.setId(2);
dept.setMobile("010-22222222");
dept.setName("改为市场部");
dept.setManager(2);
//根据主键id更新记录
// UPDATE dept SET name=?, mobile=?, manager=? WHERE id=? // id = 1
boolean result = dept.updateById();//使用dept实体主键的值,作为where id = 1
System.out.println("ar updateById result:"+result);
}
书写多少个属性就更新多少个属性(前提属性的定义都是包装类型)
@Test
public void testARUpdate2(){
//定义实体Dept
Dept dept = new Dept();
// dept.setId(1);
dept.setMobile("010-3333333");
//name , manager是没有修改的
//根据主键id更新记录
// UPDATE dept SET name=?, mobile=?, manager=? WHERE id=? // id = 1
// null的属性值不做更新处理,在update中没有null的字段
//UPDATE dept SET mobile=? WHERE id=?
boolean result = dept.updateById();//使用dept实体主键的值,作为where id = 1
System.out.println("ar updateById result:"+result);
}
@Test
public void testARDeleteById(){
Dept dept = new Dept();
//DELETE FROM dept WHERE id=?
boolean result = dept.deleteById(1);
System.out.println("ar deleteById result:"+result);
}
方法selectByID
@Test
public void testARSelectById(){
Dept dept = new Dept();
//设置主键的值
// dept.setId(1);
//调用查询方法
//SELECT id,name,mobile,manager FROM dept WHERE id=?
Dept dept1 = dept.selectById();
System.out.println("ar selectById result:"+dept1);
}
@Test
public void testARSelectById2(){
Dept dept = new Dept();
Dept dept1 = dept.selectById(3);
System.out.println("dept1:"+dept1);
}
主要讲解一些实体类上的属性定义和数据库不一致的话
分别为这三个属性
主键,TableName, Tableld
IdType的枚举类型如下
public enum IdType {
AUTO(0),
NONE(1),
INPUT(2),
ID_WORKER(3),
UUID(4),
ID_WORKER_STR(5);
private int key;
private IdType(int key) {
this.key = key;
}
public int getKey() {
return this.key;
}
}
定义实体类,默认的表名和实体类同名
@TableName(value=“数据库表名”)
主要区别在于
定义实体类的时候使用的类名
如果不符合数据库表名要加上这个注解
数据库表名为user_address
主要通过这个注解
@TableField(value = "数据库属性名")
MyBatis 默认支持这种规则
列名使用下划线,属性名是驼峰命名方式
大致意思就是(举个例子)
和前面的思路一样
主要区别在于方法的定义以及mapper文件的映射等
mapper文件的继承
public interface StudentMapper extends BaseMapper {
//自定义方法
public int insertStudent(Student student);
public Student selectStudentById(Integer id);
public List selectByName(String name);
}
方法的定义在resources文件下
insert into student(name,age,email,status) values(#{name},#{age},#{email},#{status})
文件的具体位置是这个
但是这样定义要让代码识别到
所以要在application.yml
配置文件中加入路径
mapper-locations: classpath*:xml/*Mapper.xml
此处重点讲解一下CURD数据库的编写细节
insertStudent
方法等具体使用Wrapper
条件有:
条件 | 描述 |
---|---|
allEq | 基于map相等 |
eq | 等于 |
ne | 不等于 |
gt | 大于 |
ge | 大于等于 |
lt | 小于 |
le | 小于等于 |
between | 介值中间 |
notBetween | 不在这介值中间 |
like | like ‘%值%’ |
not like | not like ‘%值%’ |
likeLeft | like ‘%值’ |
likeRight | like ‘值%’ |
isNull | 字段 is null |
isNotNull | 字段 is not null |
in | 字段 in(value1,value2,。。) |
notIn | 字段 not in(value1,value2,。。) |
inSql | 字段 in(sql 语句) 例如 insql(“age”,“1,2,3”)–>age in(1,2,3,4,5,6) 或者 insql(“id”,“select id from table where id < 3”)–>id in(select id from table where id < 3) |
notInSql | 字段 not in (sql 语句) |
groupBy | group by 字段 |
orderByAsc | 升序 order by字段,…ASC |
orderByDesc | 降序 order by 字段,…DESC |
orderBy | 自定义字段排序 orderBy (true,true,“id”,“name”)—>order by id ASC,name ASC |
having | 条件分组 |
or | or 语句,拼接+or 字段=值 |
and | and 语句,拼接+and 字段=值 |
apply | 拼接sql |
last | 在sql语句后拼接自定义条件 |
exists | 拼接exists(sql 语句) 例:exists(“select id from table where age=1”)—>exists(select id from table where age=1) |
notExists | 拼接not exists (sql 语句) |
nested | 正常嵌套 不带and 或者or |
主要展示上面条件配合代码该如何实现
allEq
查询全部
@Test
public void testAllEq() {
QueryWrapper qw = new QueryWrapper<>();
//组装条件
Map param = new HashMap<>();
//map key列名 , value:查询的值
param.put("name", "张三");
param.put("age", 22);
param.put("status", 1);
qw.allEq(param);
//调用MP自己的查询方法
//SELECT id,name,age,email,status FROM student WHERE name = ? AND age = ?
//WHERE name = ? AND age = ? AND status = ?
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println(stu));
}
如果有null的情况
qw.allEq(param,true);
,结果:WHERE name = ? AND age IS NULLqw.allEq(param,false);
结果:WHERE name = ?结论: allEq(map,boolean)
符号判断
//eq("列名",值) 等于
@Test
public void testEq() {
QueryWrapper qw = new QueryWrapper<>();
//组成条件
qw.eq("name", "李四");
//WHERE name = ?
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println("查询eq:" + stu));
}
//ne不等于
@Test
public void testNe() {
QueryWrapper qw = new QueryWrapper<>();
//组成条件
qw.ne("name", "张三");
// WHERE name <> ?
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println("查询ne:" + stu));
}
//gt 大于
@Test
public void testGt() {
QueryWrapper qw = new QueryWrapper<>();
qw.gt("age", 30); //age > 30
// WHERE age > ?
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println("stu:" + stu));
}
//ge 大于等于
@Test
public void testGe() {
QueryWrapper qw = new QueryWrapper<>();
qw.ge("age", 31);// >=31
//WHERE age >= ?
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println("student:" + stu));
}
//lt 小于
@Test
public void testLt() {
QueryWrapper qw = new QueryWrapper<>();
qw.lt("age", 32);
// WHERE age < ?
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println("student:" + stu));
}
//le 小于等于
@Test
public void testLe() {
QueryWrapper qw = new QueryWrapper<>();
qw.le("age", 32);
// WHERE age <= ?
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println("student:" + stu));
}
区间范围内
//介值
@Test
public void testBetween() {
QueryWrapper qw = new QueryWrapper<>();
//between("列名",开始值,结束值)
qw.between("age", 22, 28);
// where age >= 12 and age < 28
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println(stu));
}
//不在介值
@Test
public void testNotBetween() {
QueryWrapper qw = new QueryWrapper<>();
qw.notBetween("age", 18, 28);
//WHERE age NOT BETWEEN ? AND ?
// where age < 18 or age > 28
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println(stu));
}
匹配字段
/**
* like 匹配某个值
*/
@Test
public void testLike() {
QueryWrapper qw = new QueryWrapper<>();
qw.like("name", "张");
// WHERE name LIKE %张%
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println(stu));
}
/**
* notLike 不匹配某个值
*/
@Test
public void testNotLike() {
QueryWrapper qw = new QueryWrapper<>();
qw.notLike("name", "张");
// WHERE name NOT LIKE ? %张%
List students = studentDao.selectList(qw);
students.forEach(stu -> System.out.println(stu));
}
/**
* likeLeft "%值"
*/
@Test
public void testLikeLeft() {
QueryWrapper qw = new QueryWrapper<>();
qw.likeLeft("name", "张");
//WHERE name LIKE %张
List students = studentDao.selectList(qw);
students.forEach(student -> System.out.println(student));
}
/**
* likeRight "%值"
*/
@Test
public void testLikeRight() {
QueryWrapper qw = new QueryWrapper<>();
qw.likeRight("name", "李");
//WHERE name LIKE 李%
List students = studentDao.selectList(qw);
students.forEach(student -> System.out.println(student));
}
/**
* isNull , 判断字段是 null
*/
@Test
public void testIsNull(){
QueryWrapper qw = new QueryWrapper<>();
//判断email is null
//WHERE email IS NULL
qw.isNull("email");
print(qw);
}
/**
* isNotNull , 判断字段是 is not null
*/
@Test
public void testIsNotNull(){
QueryWrapper qw = new QueryWrapper<>();
// WHERE email IS NOT NULL
qw.isNotNull("email");
print(qw);
}
private void print(QueryWrapper qw){
List students = studentDao.selectList(qw);
students.forEach(student -> System.out.println(student));
}
in 或者子查询
/**
* isNull , 判断字段是 null
*/
@Test
public void testIsNull(){
QueryWrapper qw = new QueryWrapper<>();
//判断email is null
//WHERE email IS NULL
qw.isNull("email");
print(qw);
}
/**
* isNotNull , 判断字段是 is not null
*/
@Test
public void testIsNotNull(){
QueryWrapper qw = new QueryWrapper<>();
// WHERE email IS NOT NULL
qw.isNotNull("email");
print(qw);
}
/**
* in 值列表
*/
@Test
public void testIn(){
QueryWrapper qw = new QueryWrapper<>();
//in(列名,多个值的列表)
//WHERE name IN (?,?,?)
qw.in("name","张三","李四","周丽");
print(qw);
}
/**
* notIn 不在值列表
*/
@Test
public void testNoIn(){
QueryWrapper qw = new QueryWrapper<>();
//in(列名,多个值的列表)
//WHERE name NOT IN (?,?,?)
qw.notIn("name","张三","李四","周丽");
print(qw);
}
/**
* in 值列表
*/
@Test
public void testIn2(){
QueryWrapper qw = new QueryWrapper<>();
List
分组
/**
* groupBy:分组
*/
@Test
public void testGroupby(){
QueryWrapper qw = new QueryWrapper<>();
qw.select("name,count(*) personNumbers");//select name,count(*) personNumbers
qw.groupBy("name");
// SELECT name,count(*) personNumbers FROM student GROUP BY name
print(qw);
}
字段升序降序
/**
* orderbyAsc : 按字段升序
*/
@Test
public void testOrderByAsc(){
QueryWrapper qw= new QueryWrapper<>();
//FROM student ORDER BY name ASC , age ASC
qw.orderByAsc("name","age");
print(qw);
}
/**
* orderbyDesc : 按字段降序
*/
@Test
public void testOrderByDesc(){
QueryWrapper qw= new QueryWrapper<>();
// ORDER BY name DESC , id DESC
qw.orderByDesc("name","id");
print(qw);
}
/**
* order :指定字段和排序方向
*
* boolean condition : 条件内容是否加入到 sql语句的后面。
* true:条件加入到sql语句
* FROM student ORDER BY name ASC
*
* false:条件不加入到sql语句
* FROM student
*/
@Test
public void testOrder(){
QueryWrapper qw = new QueryWrapper<>();
qw.orderBy(true,true,"name")
.orderBy(true,false,"age")
.orderBy(true,false,"email");
// name asc, age desc , email desc
//FROM student ORDER BY name ASC , age DESC , email DESC
print(qw);
}
拼接以及存在与否
/**
* and ,or方法
*/
@Test
public void testOr(){
QueryWrapper qw= new QueryWrapper<>();
//WHERE name = ? OR age = ?
qw.eq("name","张三")
.or()
.eq("age",22);
print(qw);
}
/**
* last : 拼接sql语句到MP的sql语句的最后
*/
@Test
public void testLast(){
QueryWrapper qw = new QueryWrapper<>();
//SELECT id,name,age,email,status FROM student WHERE name = ? OR age = ? limit 1
qw.eq("name","张三")
.or()
.eq("age",22)
.last("limit 1");
print(qw);
}
/**
* exists : 判断条件
*
* notExists
*/
@Test
public void testExists(){
QueryWrapper qw= new QueryWrapper<>();
//SELECT id,name,age,email,status FROM student
// WHERE EXISTS (select id from student where age > 20)
//qw.exists("select id from student where age > 90");
//SELECT id,name,age,email,status FROM student WHERE
// NOT EXISTS (select id from student where age > 90)
qw.notExists("select id from student where age > 90");
print(qw);
}
/**
* 分页:
* 1.统计记录数,使用count(1)
* SELECT COUNT(1) FROM student WHERE age > ?
* 2.实现分页,在sql语句的末尾加入 limit 0,3
* SELECT id,name,age,email,status FROM student WHERE age > ? LIMIT 0,3
*/
@Test
public void testPage(){
QueryWrapper qw = new QueryWrapper<>();
qw.gt("age",22);
IPage page = new Page<>();
//设置分页的数据
page.setCurrent(1);//第一页
page.setSize(3);// 每页的记录数
IPage result = studentDao.selectPage(page,qw);
//获取分页后的记录
List students = result.getRecords();
System.out.println("students.size()="+students.size());
//分页的信息
long pages = result.getPages();
System.out.println("页数:"+pages);
System.out.println("总记录数:"+result.getTotal());
System.out.println("当前页码:"+result.getCurrent());
System.out.println("每页的记录数:"+result.getSize());
}
这个有点像mybatis的逆向工程
详情可看我之前的文章
mybatis逆向工程详细配置讲解(全)
结合创建数据库的表,自动生成代码
添加依赖包
org.apache.velocity
velocity-engine-core
2.0
创建一个生成类
public class AutoMapper {
public static void main(String[] args) {
//创建AutoGenerator ,MP中对象
AutoGenerator ag = new AutoGenerator();
//设置全局配置
GlobalConfig gc = new GlobalConfig();
//设置代码的生成位置, 磁盘的目录
String path = System.getProperty("user.dir");
gc.setOutputDir(path+"/src/main/java");
//设置生成的类的名称(命名规则)
gc.setMapperName("%sMapper");//所有的Dao类都是Mapper结尾的,例如DeptMapper
//设置Service接口的命名
gc.setServiceName("%sService");//DeptService
//设置Service实现类的名称
gc.setServiceImplName("%sServiceImpl");//DeptServiceImpl
//设置Controller类的命名
gc.setControllerName("%sController");//DeptController
//设置作者
gc.setAuthor("码农研究僧");
//设置主键id的配置
gc.setIdType(IdType.ID_WORKER);
ag.setGlobalConfig(gc);
//设置数据源DataSource
DataSourceConfig ds = new DataSourceConfig();
//驱动
ds.setDriverName("com.mysql.jdbc.Driver");
//设置url
ds.setUrl("jdbc:mysql://localhost:3306/springdb");
//设置数据库的用户名
ds.setUsername("root");
//设置密码
ds.setPassword("123456");
//把DataSourceConfig赋值给AutoGenerator
ag.setDataSource(ds);
//设置Package信息
PackageConfig pc = new PackageConfig();
//设置模块名称, 相当于包名, 在这个包的下面有 mapper, service, controller。
pc.setModuleName("order");
//设置父包名,order就在父包的下面生成
pc.setParent("com.wkcto"); //com.wkcto.order
ag.setPackageInfo(pc);
//设置策略
StrategyConfig sc = new StrategyConfig();
sc.setNaming(NamingStrategy.underline_to_camel);
//设置支持驼峰的命名规则
sc.setColumnNaming(NamingStrategy.underline_to_camel);
ag.setStrategy(sc);
//执行代码的生成
ag.execute();
}
}
还要配置一个配置类
@Configuration
public class Config {
/***
* 定义方法,返回的返回值是java 对象,这个对象是放入到spring容器中
* 使用@Bean修饰方法
* @Bean等同于
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
点击运行就会生成代码文件
执行测试类
@SuppressWarnings("all")
@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentMapperTest {
//注入生成的StudentMapper
@Autowired
StudentMapper studentMapper;
@Test
public void testInsertStudent(){
Student student = new Student();
student.setName("john");
student.setAge(28);
student.setEmail("[email protected]");
student.setStatus(2);
int rows = studentMapper.insert(student);
System.out.println("insert Student rows:"+rows);
}
@Test
public void testSelect(){
Student student = studentMapper.selectById(1);
System.out.println("testSelect:"+student);
}
@Test
public void testSelect1(){
QueryWrapper qw = new QueryWrapper<>();
qw.gt("age",35);
//selectOne:查询结果只能是一条记录或没有没有记录,多条记录是报错的
Student student = studentMapper.selectOne(qw);
System.out.println("testSelect:"+student);
}
}