网站开发要用cms,爱的网站,网上订餐网站建设的外文文献,邯郸做移动网站多少钱目录
Mybatis
MybatisPlus特性
MybatisPlus的使用
常见注解
TableName
TableId
TableField
MP常见配置
条件查询器Wrapper
QueryWrapper
UpdateWrapper
LambdaQueryWrapper
自定义SQL
Service接口
批量添加数据
MP的代码生成
MP静态工具
MP扩展功能之逻辑删除…
目录
Mybatis
MybatisPlus特性
MybatisPlus的使用
常见注解
TableName
TableId
TableField
MP常见配置
条件查询器Wrapper
QueryWrapper
UpdateWrapper
LambdaQueryWrapper
自定义SQL
Service接口
批量添加数据
MP的代码生成
MP静态工具
MP扩展功能之逻辑删除
MP扩展功能之枚举处理器
MP扩展功能之JSON处理器
MP插件功能 Mybatis
在原始的mybatis中我们编写sql语句十分繁琐 因此我们可以使用MybatisPlus来对原始的Mybatis进行增强。
MybatisPlus特性 MybatisPlus的使用
引入MyBatisPlus后续称为MP的依赖 dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.4.3/version/dependency 引入MP也相当于引入了Mybatis。
接着编写Mapper类并继承MP的接口。需要指定一个泛型用来告诉MP我们需要对哪个实体类进行操作。
这里包扫描一共有两种方式一种是在引导类中添加MapperScan(指定Mapper路径)。另一种是在Mapper类中添加注解Mapper。我采用第二种方式
Mapper
public interface studentMapper extends BaseMapperStudent {
} 创建对应mapper的xml文件 ?xml version1.0 encodingUTF-8 ?
!DOCTYPE mapperPUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtdmapper namespacecom.zmt.mapper.StudentMapper
/mapper 编写测试类 RunWith(SpringJUnit4ClassRunner.class)//让测试运行于Spring测试环境
SpringBootTest
public class TestSql {Resourceprivate StudentMapper studentMapper;Testpublic void test01() throws Exception {Student student studentMapper.selectById(1);System.out.println(student.toString());}
} Student{sno1, sname张三, ssex男, sdeptstudent, sage18} 可以正常使用。
常见注解
MP通过扫描实体类并基于反射获取实体类信息作为数据库表信息。其对应的映射信息
类名驼峰转下划线作为表名名为id的字段作为主键变量名驼峰转下划线作为表的字段名
MP常用注解
TableName用来指定表名TableId用来指定表中主键字段信息TabelField用来指定表中的普通字段信息
TableName
当实体类与表明映射关系不一致时可以使用该注解进行指定。比如说用户表叫做tb_user而实体类叫做User。那么我们可以在类上添加该注解TableName(tb_user)
TableId
除了可以使用它来指定表中主键外还可以使用它来指定id生成策略
TableId(valueid type) type可取值
IdType.AUTO 数据库自增长IdType.INPUT: 通过set方法自行输入IdType.ASSIGN_ID 分配ID接口ldentifierGenerator的方法nextld来生成id。默认实现类为DefaultldentifierGenerator雪花算法默认实现策略
TableField
使用TableField的常见场景 :
成员变量名与数据库字段名不一致成员变量名以is开头且是布尔值成员变量名与数据库关键字冲突。比如说order需要使用TableField(order)成员变量不是数据库字段。需要添加属性值TableField(exist false)
MP常见配置
mybatis-plus:type-aliases-package: com.zmt.pojo # 别名扫描包mapper-locations: classpath*:/mapper/**/*.xml # Mapper.xml文件地址默认值configuration:map-underscore-to-camel-case: true # 是否开启下划线和驼峰的映射cache-enabled: false # 是否开启二级缓存global-config:db-config:id-type: assign_id # id为雪花算法生成update-strategy: not_null # 更新笑略: 只更新非空字段
条件查询器Wrapper
QueryWrapper Testpublic void testQueryWrapper() throws Exception {//查询sno与sname字段。sname字段中要包含“张”字年龄要大于等于10QueryWrapper wrapper new QueryWrapperStudent().select(sno,sname).like(sname,张).ge(sage,10);ListStudent list studentMapper.selectList(wrapper);for (Student student : list) {System.out.println(student.toString());}}
gt为大于ge为大于等于lt为小于le为小于等于
UpdateWrapper Testpublic void testUpdate() throws Exception {UpdateWrapperStudent wrapper new UpdateWrapperStudent().eq(sname, 李四).;Student student new Student();student.setSsex(男);studentMapper.update(student,wrapper);}
需要构造一个对象该对象不为空的值会被set到数据库中
另一种用法就是需要更改多行数据我们可以使用UpdateWrapper的setSql方法。实现一个将所有人的年龄减一。
Test
public void testUpdate() throws Exception {UpdateWrapperStudent sqlWrapper new UpdateWrapperStudent().setSql(sage sage-1);studentMapper.update(null,sqlWrapper);
}
LambdaQueryWrapper
与QueryWrapper的区别是它不采用硬编码的方式来指定字段可以在一定程度上避免书写错误
Test
public void testLambdaQueryWrapper() throws Exception {LambdaQueryWrapperStudent wrapper new LambdaQueryWrapperStudent().select(Student::getSname,Student::getSage)//指定查找名字与年龄字段.eq(Student::getSno, 2);Student student studentMapper.selectOne(wrapper);System.out.println(student.toString());
}
注意
QueryWrapper和LambdaQueryWrapper通常用来构建select、delete、update的where条件部分UpdateWrapper和LambdaUpdateWrapper通常只有在set语句比较特殊才使用尽量使用LambdaQueryWrapper和LambdaUpdateWrapper 避免硬编码
自定义SQL
虽然我们可以通过UpdateWrapper的setSql语句来实现自定义SQL。但是这样并不符合开发规定。而且在存在MP无法帮我们构建SQL的场景比如说在查找语句中给字段起别名或是使用count(*)等方法。这时我们可以在Mapper.xml文件中自定义SQL语句
使用方法如下
在Service类中基于Wrapper构造好where条件在mapper类中创建自定义方法并使用param注解声明wrapper变量参数名必须为ew在xml文件中自定义SQL并使用Wrapper条件
Test
public void testQueryByXML() throws Exception {LambdaQueryWrapperStudent wrapper new LambdaQueryWrapperStudent().eq(Student::getSsex, 男);int count studentMapper.queryNumBySex(wrapper);System.out.println(count);
} Service接口
这个接口是为了将基础的增删改查方法不需要我们去写。
使用方法在Service的接口类继承IService接口并指定实体类Service的实现方法去继承ServiceImpl实现类并指定Mapper与实体类
public interface StudentService extends IServiceStudent {
}
Service
public class StudentServiceImpl extends ServiceImplStudentMapper, Student implements StudentService{
}
Test
public void testService() throws Exception {Student student new Student();student.setSname(王五);student.setSage(16);studentService.save(student);
}
通过Serivce接口我们可以在Controller中直接使用Service对数据库进行操作而不用在Service中编写代码
RestController
RequestMapping(/user)
public class Controller {Autowiredprivate StudentService studentService;/*** 新增学生信息*/PostMappingpublic void getStudentById(RequestBody Student student){studentService.save(student);}/*** 删除学生信息*/DeleteMapping(/{id})public void deleteById(PathVariable(id) Long id){studentService.removeById(id);}/*** 根据id查询学生信息*/GetMapping({id})public Student queryById(PathVariable(id) Long id){return studentService.getById(id);}/*** 批量查询*/GetMapping({ids})public ListStudent queryById(PathVariable(ids) ListLong ids){return studentService.listByIds(ids);}
}
而对于复杂业务我们还是需要在Service中添加业务代码。
这里用一个复杂更新为例。
/*** 查询学生信息如果是男生年龄则-age*/
PutMapping({id}/age/{age})
public void updateById(PathVariable(id) Long id,PathVariable(age) int age){studentService.reduceAge(id,age);
}
Service
public class StudentServiceImpl extends ServiceImplStudentMapper, Student implements StudentService {Overridepublic void reduceAge(Long id, int age) {Student student getById(id);if (女.equals(student.getSsex())) {return;}Integer sage student.getSage();lambdaUpdate().set(Student::getSage, sage - age).eq(Student::getSage, sage)//乐观锁如果更新数据库前学生年龄还等于查找出时的年龄说明没有进行过修改。.update();}
}
批量添加数据
如果有十万条数据需要添加到数据库中执行十万次save()方法效率最慢因为每保存一条数据都是一次网络请求而在IService中提供了批量添加的方法。接下来测试添加1w条数据花费的时间
RunWith(SpringJUnit4ClassRunner.class)
SpringBootTest
public class TestInserte {Autowiredprivate StudentService studentService;Testpublic void test() throws Exception {long start System.currentTimeMillis();for (int i 0; i 10000; i) {studentService.save(buildStudent(i));}long end System.currentTimeMillis();System.out.println(花费时间(end-start));}private Student buildStudent(int i) {Student student new Student();student.setSname(赵六i);return student;}
} 再来测试批量添加由于需要预先创建出对象保存在内存中所以一次创建500个避免占用内存过大 Test
public void test() throws Exception {ListStudent list new ArrayList();long start System.currentTimeMillis();for (int i 0; i 10000; i) {list.add(buildStudent(i));if (i%5000){studentService.saveBatch(list);list.clear();}}long end System.currentTimeMillis();System.out.println(花费时间(end-start));
} 可以看到比单次插入效率提升很多。但是还有提升空间批量插入之所以能提升速度是将要提交的数据先进行编译编译成sql语句后一次性提交到数据库中相当于执行了500次insert语句。如果将500条sql语句变为1条则速度还可以提升。这个功能需要在数据库中配置rewriteBatchedstatementstrue
jdbc:mysql://localhost:3306/school?useSSLfalseserverTimezoneUTCrewriteBatchedstatementstrue 接下来再去执行该测试方法 经过多次测试确实有提升但不多可能是因为我的数据量太少了吧
MP的代码生成
可以引入依赖编写代码生成也可以下载官方插件MyBatisX点击生成不过我采用的是另一个插件MyBatisPlus插件 下载好后在IDEA的顶部出现以一个菜单栏 进行配置数据库 修改数据库名称以及密码就可以使用。 生成结果如下 MP静态工具
静态工具的出现是为了避免循环引入的事情发生。
比如说在StudentController中有一个业务是通过学生id查询到对应的教课老师。这需要查询学生表和老师表。那么就需要在StudentService中引入TeacherService。而在TeacherController中存在一个业务是通过教师id去查询所有的学生信息那么就要在TeacherService引入StudentService。两个Service相互注入就形成了循环依赖。为了解决这种情况可以使用MP提供的静态工具该工具在最新版本才存在我的是3.5.4版本 在StudentServiceImpl中编写如下代码。可以在不注入TeacherService的情况下查找到教师信息 Override
public Teacher getTeacherByStudentId(Long teacherId) {//需要和那个表联合查找就指定对应的反射类Teacher teacher Db.lambdaQuery(Teacher.class).eq(Teacher::getTno, teacherId).one();//如果有多个老师可以调用list()方法}
MP扩展功能之逻辑删除
所谓逻辑删除并不是真正的删除只是在查询时不去查询被逻辑删除的数据。比如说用户删除订单信息这些订单信息并不会真的被删除而是将查询状态从0改为1。这些数据在用户查询时不会被展示。
既然是扩展功能那就不需要修改我们的业务代码。修改配置文件就可以实现。
mybatis-plus:global-config:db-config:logic-delete-field: flag #逻辑删除在数据库中的字段名可以是Integer或Boolean的值logic-delete-value: 1 #逻辑已删除值默认为1logic-not-delete-value: 0 #逻辑未删除值默认为0
逻辑删除存在的问题。比如:
会导致数据库表垃圾数据越来越多影响查询效率SQL中全都需要对逻辑删除字段做判断影响查询效率
因此不太推荐采用逻辑删除功能如果数据不能删除可以采用把数据迁移到其它表的办法
MP扩展功能之枚举处理器
在业务中可能会遇到账号状态问题1表示正常2表示冻结。也有可能会遇到业务处理状态1表示未处理2表示处理中3表示处理结束等。当这些数据较少时能够记住但多了之后可能会频繁查看状态信息。为了避免这种事情我们可以将这些状态设置成一个枚举类来方便我们使用。
随之产生的问题是数据库中仍是存储的int类型数据而数据库中查找出来的数据也无法转为枚举类型。在MP中也有对应的解决方法。 枚举类 Getter
public enum UserStatus {NORMAL(1,正常),FREEZE(2,冻结);EnumValue//值为1是返回NORMAL对象值为2返回FREEZE对象private final int value;JsonValue//返回前端时返回正常,冻结信息而不是返回NORMAL与FREEZE信息private final String desc;UserStatus(int value,String desc){this.valuevalue;this.descdesc;}
} 在配置类中添加如下配置 mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler 在业务代码中要做一定的修改 Testpublic void testEnum() throws Exception {Student student new Student();
// if (student.getStatus()1) {
//
// }if (student.getStatus() UserStatus.NORMAL) {}}
}
第二种的可读性比第一种与数字判断相比较可读性更好
MP扩展功能之JSON处理器
有时我们在数据库中存储的数据为JSON类型的数据那么拿到服务器后需要转化为具体对象在MP中存在JSON处理器来帮我们去做这件事。 与枚举类处理器配置不同的是JSON的处理器并没有全局配置只能在字段上进行配置同时开启自动映射
Data
TableName(autoResultMap true)//开启自动映射
public class Student {TableId(value sno,type IdType.AUTO)private Long sno;private String sname;private String ssex;private String sdept;private Integer sage;private UserStatus status;//对该字段添加一个JSON处理器TableField(typeHandler JacksonTypeHandler.class)private UserInfo info;
}
MP插件功能
MP提供一下几种插件最常用的就是分页插件 接下来展示分页插件的使用方法 Configuration
public class MyBatisConfig {Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor(){MybatisPlusInterceptor interceptor new MybatisPlusInterceptor();//创建分页插件并指定数据库类型PaginationInnerInterceptor pageIntercept new PaginationInnerInterceptor(DbType.MYSQL);//设置一次最多查找1000条pageIntercept.setMaxLimit(1000L);interceptor.addInnerInterceptor(pageIntercept);return interceptor;}
}
RunWith(SpringJUnit4ClassRunner.class)
public class TestPage {Testpublic void test01() throws Exception {int pageNO 1;int pageSize 5;PageStudent page new Page(pageNO, pageSize);//添加排序以ssex字段为准降序排序 true为升序排序page.addOrder(new OrderItem(sage, false));//page中设置好参数后在查询过程中会将结果重新set到page中page studentService.page(page);ListStudent records page.getRecords();for (Student student : records) {System.out.println(student);}}
}