mybatis
一、开始使用
就创好一个表,使用easycode,一键生成代码。。。
二、配置
大部分的配置,都可以写在application.yml里面的啦。有些配置要单独拿出来
<resultMap>
这个东西,写起来很复杂的,直接代码一键生成好了
比如
<resultMap type="com.qiang.springbootvue.entity.Book" id="BookMap">
<result property="id" column="id" jdbcType="INTEGER"/>
<result property="name" column="name" jdbcType="VARCHAR"/>
<result property="author" column="author" jdbcType="VARCHAR"/>
</resultMap>
网上搜索,说这是一个映射关系,resultMap是一个很重要的东西。
三、动态SQL
没有什么文档比官方文档还好的了
每一个sql,输出的话,就是resultMap="类型"
,还有一个传入参数,parameterType="xx"
四、SQL公共代码(复用片段)
复用片段,老传统艺能了
<!-- 这是复用代码-->
<sql id="if-name-author">
<if test="name!=null">
name=#{name}
</if>
<if test="author!=null">
and author =#{author}
</if>
</sql>
<select id="queryIf" resultMap="BookMap">
select * from library.book
<where>
<!-- 调用复用代码-->
<include refid="if-name-author"></include>
</where>
</select>
五、foreach
这个尤其用于in
比如我们想查询SELECT * FROM book where id in (1,2);
,结果为
<select id="queryForeach" parameterType="map" resultMap="BookMap">
select * from library.book
where id in
<foreach collection="ids" item="id" index="index" open="(" close=")" separator=",">
#{id}
</foreach>
</select>
- open开始的符号
- close结束的符号
- separator间接符号
@Override
public List<Book> queryForeach() {
HashMap map=new HashMap();
ArrayList<Integer> ids=new ArrayList<>();
// List集合里面放1,2
ids.add(1);
ids.add(2);
// map里面,下标为ids,这样Dao.xml就能识别了,然后值就是List
map.put("ids",ids);
return bookDao.queryForeach(map);
}
当然这里的java代码是service层的,还要在dao层定义方法名
mybatis plus
mybatis plus的maven包含了mybatis与mybatis plus,所以导入的时候可以不选mybatis
一、使用步骤
1、导包
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
在官网的没有boot-starter,记得+
2、写数据库和配置数据库
写数据库就自己写了,或者在下面的GitHub连接中有
spring:
datasource:
url: jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
initialization-mode: always
3、实体类,mapper接口
@Data
public class Book {
private Integer id;
private String name;
private String author;
}
@Mapper
public interface BookMapper extends BaseMapper<Book> {
}
这个接口,就继承就OK了,记得用泛型,BaseMapper里面有很多方法都写好的了
还有,记得@Mapper
或者在主程序@MapperScan
注解扫描mapper层
4、就OK了
随便拿个测试类
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
BookMapper bookMapper;
@Test
void contextLoads() {
List<Book> books = bookMapper.selectList(null);
for (Book book :books) {
System.out.println(book);
}
}
}
Book(id=1, name=五体, author=wo )
Book(id=2, name=西游记, author=吴承恩)
Book(id=3, name=三国演义, author=罗贯中)
Book(id=4, name=红楼梦, author=曹雪芹)
Book(id=5, name= 水浒传, author=施耐庵)
Book(id=12, name=123321, author=321)
Book(id=13, name=快乐JAVA, author=小强)
Book(id=23, name=444444, author=55555)
Book(id=24, name=1111, author=222)
Book(id=25, name=1111, author=222)
Book(id=26, name=123, author=321)
Book(id=27, name=33333, author=33333333)
这接口有很多已经写好的方法了
5、或者把SQL语句日志打开
yml
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
这个StdOutImpl专门用来打印的
二、常用注解
SELECT id,name AS name2,author FROM book
@TableName(value = “book”)
用于实体类之前,映射数据库的表名
@Data
@TableName(value = "book")
public class Book {
private Integer id;
private String name;
private String author;
}
如果实体类名与表名不一致,可以用该注解映射表名。如果没有该注解,映射名默认为类名
@TableId
用于实体类主键前
属性:
value = "xx"
:和上面一样,映射字段名,默认值为属性名type
:设置主键类型,主键的生成策略,默认为IdType.AUTO
,其有以下几个值IdType.AUTO
:数据库自增,强烈推荐(数据库也是自增长的情况下),不写这个的话,生成ID随机IdType.NONE
:MP set 主键,雪花算法实现,反正就是当插入的时候,随机生成一个ID给你IdType.INPUT
:需要开发者手动赋值,如果开发者没有手动赋值,则数据库通过自增的方式给主键赋值,如果开发者手动赋值,则存入该值。也推荐这个IdType.ASSIGN_ID
:自动赋值,雪花算法。生成随机数,但一定比当前最大值还大IdType.ASSIGN_UUID
:主键的数据类型必须是 String,数据库必须为字符串类型,自动生成 UUID (随机数字字母)进行赋值
@Data
@TableName(value = "book")
public class Book {
@TableId(value = "id",type = IdType.AUTO)
private Integer id;
@TableField(value = "name")
private String name2;
private String author;
}
@TableField
映射非主键字段,用于实体类的属性前
value
映射字段名select
:表示是否查询该字段,默认为trueexist
:表示是否为数据库字段,如果实体类中的成员变量在数据库中没有对应的字段,则可以使用 exist。用于某些情况下,没有这个列但前端传过来了,可以用来忽略
@Data
@TableName(value = "book")
public class Book {
@TableId(value = "id",type = IdType.AUTO)
private Integer id;
@TableField(value = "name")
private String name2;
@TableField(select = false)
private String author;
@TableField(exist = false)//数据库忽略该字段,默认为true,如果实体类中的成员变量在数据库中没有对应的字段,则可以使用 exist,
private String test;//数据库不存在的列
}
查询全部
@Test
void contextLoads() {
List<Book> books = bookMapper.selectList(null);
for (Book book :books) {
System.out.println(book);
}
}
只查询id和name,然后test不存在的,所以为null。没有查询author,也为null
fill是@TableField的属性
fill
:这个属性展开比较多。表示是否自动填充,将对象存入数据库的时候,由 MyBatis Plus 自动给某些字段赋值,一般用于创建该行时记录这个事件点,或者修改的时候记录这个时间点。
其值有 FieldFill.INSERT_UPDATE,FieldFill.DEFAULT,FieldFill.INSERT,FieldFill.UPDATE
使用步骤
- 给表添加 create_time、update_time 字段
- 实体类中添加成员变量
@Data
@TableName(value = "book")
public class Book {
@TableId(value = "id",type = IdType.AUTO)
private Integer id;
@TableField(value = "name")
private String name2;
@TableField(select = false)
private String author;
@TableField(exist = false)//数据库忽略该字段,默认为true,如果实体类中的成员变量在数据库中没有对应的字段,则可以使用 exist,
private String test;//数据库不存在的列
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
- 创建自动填充处理器类
添加的:
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("update_time",new Date(),metaObject);
}
}
测试类
@Test
void save(){
Book book=new Book();
book.setName2("这是一本书");
book.setAuthor("我是作者");
bookMapper.insert(book);
System.out.println(book);
}
修改:
@Test
void update(){
Book book=bookMapper.selectById(31);
book.setName2("这是另外一本书的名字");
bookMapper.updateById(book);
}
这个可以看到啊,数据库列名为create_time,但属性名为createTime。但是,mybatis plus会自动开启驼峰命名法的,不慌
@Version
一般用于version属性标记前面,标记乐观锁,通过 version 字段来保证数据的安全性,当修改数据的时候,会以 version 作为条件,当条件成立的时候才会修改成功。
使用情况:就当多个语句重复执行的时候,产生冲突
使用步骤
-
数据库表添加 version 字段,默认值为 1
-
实体类添加 version 成员变量,并且添加 @Version 。
@Data
public class Book {
//xxxxx
@Version
private Integer version;
}
- 注册配置类
@Configuration
public class MyBatisPlusConfig {
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
- 测试
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
BookMapper bookMapper;
@Test
void contextLoads() {
Book book1 =bookMapper.selectById(31);
book1.setName2("一号");
Book book2 =bookMapper.selectById(31);
book2.setName2("二号");
bookMapper.updateById(book1);
bookMapper.updateById(book2);
}
}
- 可以看到,两个都是修改ID31,然后发生冲突,那么结果是什么?
可以看到,version从1变成2。要是再改,就变成3了。这个version只是个工具人
@EnumValue
用于自己写的一个枚举类的属性前,就比如男是0女是1,然后查出来还要匹配定义好麻烦,这个注解就帮我们做了。
使用步骤
-
数据库添加status
-
创建Status枚举类
public enum StatusEnum {
GOOD(1,"好书"),
BAD(0,"坏书");
StatusEnum(Integer code,String msg) {
this.code=code;
this.msg=msg;
}
@EnumValue
private Integer code;
private String msg;
}
- msg就只是注解而已啦,最重要还是code和枚举的名字
- 在实体类添加status属性
@Data
@TableName(value = "book")
public class Book {
//xxxxxx
private StatusEnum status;
}
- yml扫描枚举包
mybatis-plus:
type-enums-package: com.qiang.mybatisplus.Enum
- 查询
@Test
void select(){
List<Book> books = bookMapper.selectList(null);
for (Book book:books ) {
System.out.println(book);
}
}
查出来的status不再是数字了,而是直接变成字了
或者用接口来实现
就不要那个创建Status枚举类,改成继承接口
public enum StatusEnumImp implements IEnum<Integer> {
GOOD(1,"好书"),
BAD(0,"坏书");
private Integer code;
private String msg;
StatusEnumImp(Integer code,String msg) {
this.code=code;
this.msg=msg;
}
@Override
public Integer getValue() {
return this.code;
}
}
改属性
@Data
@TableName(value = "book")
public class Book {
//xxx
private StatusEnumImp status;
}
@TableLogic
用于实体类属性(deleted)前,表示逻辑删除,就是删除的时候,不会真的只是把他删除了。逻辑上删除,数据库物理上没删除。其其实就是设置deleted=0就没删除,deleted=1就表示逻辑删除,但物理数据还在数据库
- 数据库添加deleted字段
- 实体类添加注解
@Data
@TableName(value = "book")
public class Book {
//xxxxx
@TableLogic
private Integer deleted;
}
- yml添加配置
mybatis-plus:
global-config:
db-config:
logic-not-delete-value: 0
logic-delete-value: 1
- 当
deleted
为0时,没有被逻辑删除 - 当
deleted
为1时,逻辑被删除
- 测试
@Test
void delete(){
bookMapper.deleteById(1);
}
删除:
逻辑删除后,查询也查不到这个了
三、CRUD
查询
之前的bookMapper.selectList(null);
是查询所有。
其实,参数还可以是Wrapper<T> queryWrapper
(看源码),Wrapper是个接口,应该用QueryWrapper
类
QueryWrapper
类可以用来做条件构造器,就是各种where ,order by,having语句
@Test
void select(){
QueryWrapper wrapper = new QueryWrapper();
Map<String,Object> map = new HashMap<>();
// wrapper.xxxx
List<Book> books = bookMapper.selectList(wrapper);
for (Book book:books) {
System.out.println(book);
}
}
wrapper.eq("name","五体");
where name=‘五体’
map.put("name","五体");
map.put("author","wo");
wrapper.allEq(map);
// where (author = 'wo' AND name = '五体')
-------------------
wrapper.lt("id",5);
//where id < 5
---------------
wrapper.gt("id",5);
//where id > 5
--------------
wrapper.ne("id",5);
//where id <>5 不等于5
-----------
wrapper.like("name","三");
//where name like '%三%'
-----------
wrapper.likeLeft("name","三");
//where name like '%三'
-------------
wrapper.inSql("id","select id from book where id <5");
wrapper.inSql("version","select version from book where version < 2");
//select ... where id IN (select id from book where id <5) AND version IN (select version from book where version < 2)
--------------
wrapper.orderByDesc("id");
wrapper.having("id<5");
// HAVING id<5 ORDER BY id DESC
---------------------
map.put("id",1);
bookMapper.selectByMap(map);
//WHERE id = 1
------------------
bookMapper.selectMaps(wrapper);
//返回map集合
----------
分页查询
- 配置类设置分页查询拦截器
@Configuration
public class MyBatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
}
- 测试类
@Test
void select(){
QueryWrapper wrapper = new QueryWrapper();
//查询第三页,每页2条数据
Page<Book> page = new Page<>(3,2);
//把page传进来,第二个参数可写wrapper
Page<Book> result = bookMapper.selectPage(page, null);
//查询每页行数
System.out.println(result.getSize());
//查询总数
System.out.println(result.getTotal());
//getRecords才是返回 List<Book> 集合
List<Book> books = result.getRecords();
for (Book book:books) {
System.out.println(book);
}
}
自定义SQL(多表关联查询)
想一起多表关联查询,返回结果都不会是一个类的类型对吧。所以还得先创建一个实体类(好麻烦…)
比如我想执行SQL语句select s.*,b.name book_name FROM book b ,shop s where b.id=s.book_id and b.id = 1
,结果为
但是这个结果的类没有嘛,就要创建这么一个类
@Data
public class ShopVO {
private Integer shopId;
private String shopName;
private Integer bookId;
private String bookName;
}
mapper中添加
@Mapper
public interface BookMapper extends BaseMapper<Book> {
@Select("select s.*,b.name book_name FROM book b ,shop s where b.id=s.book_id and b.id = #{id}")
List<ShopVO> shopList(Integer id);
}
测试类中
@Test
public void myQuery(){
System.out.println(bookMapper.shopList(1));
}
增加
@Test
void insert(){
Book book=new Book();
book.setAuthor("作者");
book.setName("名字");
bookMapper.insert(book);
}
删除
@Test
void delete(){
bookMapper.deleteById(1);
}
更新
@Test
void update(){
Book book=bookMapper.selectById(31);
book.setName("这是另外一本书的名字");
bookMapper.updateById(book);
}
目前为止的代码
sql在文件里面
https://github.com/E-10000/mybatis_plus/tree/master
四、MyBatisPlus 自动生成
根据数据表自动生成实体类、Mapper、Service、ServiceImpl、Controller
使用步骤
1、pom.xml 导入 MyBatis Plus Generator
新建个项目吧
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity</artifactId>
<version>1.7</version>
</dependency>
2、创建自动生成类
package com.qiang.mybatisplusauto;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
public class Main {
public static void main(String[] args) {
//创建Generator对象
AutoGenerator autoGenerator =new AutoGenerator();
//数据源
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL);//MYSQL
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8");//连接URL
dataSourceConfig.setUsername("root");//账号
dataSourceConfig.setPassword("root");//密码
dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");//设置driver-class-name
autoGenerator.setDataSource(dataSourceConfig);//数据源装在Generator类中
//全局配置
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");//这个是设置哪个Java项目的
globalConfig.setOpen(false);//创建好后不要自动打开这个文件夹
globalConfig.setAuthor("小强");//作者是谁,自己写就OK
globalConfig.setServiceName("%sService");//不写这个,生成的service层就会是IxxxService的
autoGenerator.setGlobalConfig(globalConfig);//装载进Generator类
//包信息
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.qiang.mybatisplusauto");//包放在哪里之下
// packageConfig.setModuleName("generator");//还可以更进一步设置放在哪里之下
packageConfig.setController("controller");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.imp");
packageConfig.setMapper("mapper");
packageConfig.setEntity("entity");
autoGenerator.setPackageInfo(packageConfig);
//配置策略
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setEntityLombokModel(true);//实体类添加Lombok注解
strategyConfig.setNaming(NamingStrategy.underline_to_camel);//与下面的注解一起用的
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);//开启驼峰命名法大写转_+小写
autoGenerator.setStrategy(strategyConfig);//装载进去
autoGenerator.execute();
}
}
3、主程序类加@MapperScan
@SpringBootApplication
@MapperScan("com.qiang.mybatisplusauto.mapper")
public class MybatisPlusAutoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusAutoApplication.class, args);
}
}
4、配置YML
spring:
datasource:
url: jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
initialization-mode: always
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-not-delete-value: 0
logic-delete-value: 1
5、把controller层的@Controller换成@RestController
这个没有换,导致我显示不出东西。。。
6、自动生成的东西
红框里面全是自动生成的东西
然后再自己补全Mapper层的@Mapper注解,每个实体类的@TableId,每个表的@TableName
mybatis plus auto 代码:
https://github.com/E-10000/mybatis_plus/tree/auto