@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
/*
测试添加
*/
@Test
public void testInsert(){
User user = new User();
user.setAge(18);
user.setEmail("[email protected]");
user.setName("张三");
//返回的result是受影响的⾏数,并不是⾃增后的id
int result = userMapper.insert(user);
System.out.println(result);
System.out.println(user.getId());
}
}
/**
* 根据 ID 修改
*
* @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);
测试:
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testUpdateById() {
User user = new User();
user.setId(5L); //主键
user.setAge(21); //更新的字段
//根据id更新,更新不为null的字段
this.userMapper.updateById(user);
}
}
3.2.2 根据条件更新
⽅法定义:
/**
* 根据 whereEntity 条件,更新记录
*
*正常的更新sql语句为:update 表名 set 字段=值 where 条件语句;
*
* @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,⾥⾯的 entity ⽤于⽣成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper
updateWrapper);
测试⽤例:
package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import net.minidev.json.writer.UpdaterMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
/*
根据条件进行更新:将姓名为“张三”的年龄修改为30岁。
*/
@Test
public void testUpdate() {
User user = new User();
//更新的字段
user.setAge(30);
//更新的条件
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq("name", "张三");
//执⾏更新操作
int result = this.userMapper.update(user, wrapper);
System.out.println("result = " + result);
}
}
或者,通过UpdateWrapper进⾏更新:
@Test
public void testUpdate(){
//更新的条件以及字段
UpdateWrapper wrapper=new UpdateWrapper<>();
wrapper.eq("name","张三").set("age",30);
//执⾏更新操作
int result=this.userMapper.update(null,wrapper);
System.out.println("result = "+result);
}
均可达到更新的效果。
3.3 删除操作
3.3.1 deleteById(根据 ID 删除)
⽅法定义:
/**
* 根据 ID 删除
*
* @param id 主键ID
*/
int deleteById(Serializable id);
测试⽤例:
package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testDeleteById() {
//执⾏删除操作
int result = this.userMapper.deleteById(5L);
System.out.println("result = " + result);
}
}
package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testWrapper() {
QueryWrapper wrapper = new QueryWrapper<>();
//设置条件
Map params = new HashMap<>();
params.put("name", "jack");
params.put("age", null);
/*
无 filter过滤器
*/
// sql语句--> SELECT * FROM user WHERE name = ? AND age IS NULL
wrapper.allEq(params);
// sql语句--> SELECT * FROM user WHERE name = ?
wrapper.allEq(params,false);
/*
有 filter过滤器
*/
// sql语句--> SELECT * FROM user WHERE name = ? AND age IS NULL
wrapper.allEq((k, v) -> (k.equals("name") || k.equals("age")),params);
// sql语句--> SELECT * FROM user WHERE name = ?
wrapper.allEq((k, v) -> (k.equals("name")),params);
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
}
5.2、基本⽐较操作
eq -- 等于 =
ne -- 不等于 <>
gt -- ⼤于 >
ge -- ⼤于等于 >=
lt -- ⼩于 <
le -- ⼩于等于 <=
between -- BETWEEN 值1 AND 值2
notBetween -- NOT BETWEEN 值1 AND 值2
in -- 字段 IN (value.get(0), value.get(1), ...)
notIn -- 字段 NOT IN (v0, v1, ...)
测试⽤例:
package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testWrapper() {
QueryWrapper wrapper = new QueryWrapper<>();
//SELECT * FROM user WHERE password = ? AND age >= ? AND name IN (?,?,?)
wrapper.eq("email", "[email protected]")
.ge("age", 20)
.in("name", "jack", "jone", "tom");
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
}
5.3、模糊查询
like -- LIKE '%值%' -- 例: like("name", "王") ---> name like '%王%'
notLike -- NOT LIKE '%值%' -- 例: notLike("name", "王") ---> name not like '%王%'
likeLeft -- LIKE '%值' 例: likeLeft("name", "王") ---> name like '%王'
likeRight -- LIKE '值%' -- 例: likeRight("name", "王") ---> name like '王%'
测试⽤例:
package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testWrapper() {
QueryWrapper wrapper = new QueryWrapper<>();
//SELECT * FROM user WHERE name LIKE ?
// 即:查询姓名中 包含'子' 的这条数据
//Parameters: %⼦%(String)
wrapper.like("name", "⼦");
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
}
5.4、排序
orderBy -- 排序:ORDER BY 字段, ... -- 例: orderBy(true, true, "id", "name") ---> order by id ASC,name ASC
orderByAsc(正序或升序) -- 排序:ORDER BY 字段, ... ASC --- 例: orderByAsc("id", "name") ---> order by id ASC,name ASC
orderByDesc(倒序或降序) -- 排序:ORDER BY 字段, ... DESC -- 例: orderByDesc("id", "name") ---> order by id DESC,name DESC
测试⽤例:
package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testWrapper() {
QueryWrapper wrapper = new QueryWrapper<>();
// SELECT * FROM user ORDER BY age DESC
// 根据年龄倒序排序查找
wrapper.orderByDesc("age");
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
}
5.5、逻辑查询
or -- 拼接 OR -- 主动调⽤ or 表示紧接着下⼀个⽅法不是⽤ and 连接!(不调⽤ or 则默认为使⽤ and 连接)
and -- AND 嵌套 -- 例: and(i -> i.eq("name", "李⽩").ne("status", "活着")) ---> and (name = '李⽩' and status <> '活着')
测试⽤例:
package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testWrapper() {
QueryWrapper wrapper = new QueryWrapper<>();
//SELECT * FROM user WHERE name = ? OR age = ?
wrapper.eq("name", "jack").or().eq("age", 24);
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
}
5.6、select
在MP查询中,默认查询所有的字段。如果有需要也可以通过select⽅法进⾏指定字段查询。
package com.zm.mp;
import com.zm.mp.mapper.UserMapper;
import com.zm.mp.pojo.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
public void testWrapper() {
QueryWrapper wrapper = new QueryWrapper<>();
//SELECT id,name FROM user WHERE name = ? OR age = ?
wrapper.eq("name", "jack")
.or()
.eq("age", 24)
.select("id", "name");
List users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}
}
6. ActiveRecord
ActiveRecord(简称AR)⼀直⼴受动态语⾔( PHP 、 Ruby 等)的喜爱,⽽ Java 作为准静态语⾔,对于ActiveRecord 往往只能感叹其优雅,所以我们也在 AR 道路上进⾏了⼀定的探索,希望⼤家能够喜欢(来自官网)。
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
/*
AR模式下根据ID查询操作
*/
@Test
public void testAR() {
User user = new User();
user.setId(2L);
User user2 = user.selectById();
System.out.println(user2);
}
}
6.3、新增数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
/*
AR模式下插入操作
*/
@Test
public void testARInsert() {
User user = new User();
user.setName("李四");
user.setAge(30);
user.setEmail("[email protected]");
boolean insert = user.insert();
System.out.println(insert);
}
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
/*
AR模式下更新操作
*/
@Test
public void testARUpdate() {
User user = new User();
user.setId(8L);
user.setAge(35);
boolean update = user.updateById();
System.out.println(update);
}
}
日志结果:
[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] ==> Preparing: UPDATE
user SET age=? WHERE id=?
[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] ==> Parameters: 35(Integer),
8(Long)
[main] [com.zm.mp.mapper.UserMapper.updateById]-[DEBUG] <== Updates: 1
6.5、删除操作
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
/*
AR模式下删除记录
*/
@Test
public void testARDelete() {
User user = new User();
user.setId(7L);
boolean delete = user.deleteById();
System.out.println(delete);
}
}
6.6、根据条件查询
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserMapperTest {
@Autowired
private UserMapper userMapper;
/*
AR模式下根据条件查询:查询年龄大于等于20 的记录
*/
@Test
public void testARFindById() {
User user = new User();
QueryWrapper userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.ge("age", "20");
List users = user.selectList(userQueryWrapper);
for (User user1 : users) {
System.out.println(user1);
}
}
}
package com.zm.plugins;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import java.util.Properties;
@Intercepts({@Signature(
type = Executor.class,
method = "update",
args = {MappedStatement.class, Object.class})})
public class MyInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
//拦截⽅法,具体业务逻辑编写的位置
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
//创建target对象的代理对象,⽬的是将当前拦截器加⼊到该对象中
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
//属性设置
}
}
注⼊到Spring容器:
/**
* ⾃定义拦截器
*/
@Bean
public MyInterceptor myInterceptor(){
return new MyInterceptor();
}
或者通过xml配置,mybatis-config.xml:
7.2、执⾏分析插件
在MP中提供了对SQL执⾏的分析的插件,可⽤作阻断全表更新、删除的操作。
注意:该插件仅适⽤于开发环境,不适⽤于⽣产环境。
SpringBoot配置:
@Bean
public SqlExplainInterceptor sqlExplainInterceptor(){
SqlExplainInterceptor sqlExplainInterceptor=new SqlExplainInterceptor();
List sqlParserList=new ArrayList<>();
// 攻击 SQL 阻断解析器、加⼊解析链
sqlParserList.add(new BlockAttackSqlParser());
sqlExplainInterceptor.setSqlParserList(sqlParserList);
return sqlExplainInterceptor;
}
测试:
@Test
public void testUpdate(){
User user=new User();
user.setAge(20);
int result=this.userMapper.update(user,null);
System.out.println("result = "+result);
}
结果:
Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition
of table update operation
at com.baomidou.mybatisplus.core.toolkit.ExceptionUtils.mpe(ExceptionUtils.java:49)
at com.baomidou.mybatisplus.core.toolkit.Assert.isTrue(Assert.java:38)
at com.baomidou.mybatisplus.core.toolkit.Assert.notNull(Assert.java:72)
at
com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser.processUpdate(BlockAtta
ckSqlParser.java:45)
at
com.baomidou.mybatisplus.core.parser.AbstractJsqlParser.processParser(AbstractJsqlParse
r.java:92)
at
com.baomidou.mybatisplus.core.parser.AbstractJsqlParser.parser(AbstractJsqlParser.java:
67)
at
com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler.sqlParser(Abstract
SqlParserHandler.java:76)
at
com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor.intercept(SqlExplainIn
terceptor.java:63)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61)
at com.sun.proxy.$Proxy70.update(Unknown Source)
at
org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:197)
... 41 more
执⾏更新时, set version = newVersion where version = oldVersion;
如果version不对,就更新失败。
7.4.2、插件配置
spring xml(xml方式):
spring boot(javaconfig方式):
@Configuration
@MapperScan("com.zm.mapper")
public class MybatisPlusConfig {
/*
旧版。 这里就以旧版进行演示
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
/*
// 新版。 注意:使用新版时mybatis-plus版本要求在3.4.0 版本以上
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
*/
}
7.4.3、注解实体字段
需要为实体字段添加@Version注解。 第⼀步,为表添加version字段,并且设置初始值为1:
ALTER TABLE `user`
ADD COLUMN `version` int(10) NULL AFTER `email`;
UPDATE `user` SET `version`='1';
第⼆步,为User实体对象添加version字段,并且添加@Version注解:
@Version
private Integer version;
7.4.4、测试更新
测试⽤例:
@Test
public void testUpdate03(){
//第一步:查询id为6的用户
User user = userMapper.selectById(6L);
//第二步:对该用户信息进行修改
user.setName("张三_update");
//第三步:执行更新操作
int i = userMapper.updateById(user);
System.out.println(i);
}
执⾏结果:
通过日志记录可以看到,更新的条件中有version条件,并且更新的version为2。
模拟一下并发过程 事务一修改数据未提交、事务二执行插入(乐观锁插件本质)。
@Test
void testUpdate04(){
// 线程1 查询id为6的用户
User user1 = userMapper.selectById(6L);
// 线程1 对用户信息进行修改
user1.setName("change By user1");
// 线程2 查询id为6的用户
User user2 = userMapper.selectById(6L);
// 线程B 对用户信息进行修改
user2.setName("chang By user2");
// 执行更新操作
int i2 = userMapper.updateById(user2);
int i1 = userMapper.updateById(user1);
System.out.println("user2修改结果:"+i2 );
System.out.println("user1修改结果:"+i1 );
}
4.0.0org.springframework.bootspring-boot-starter-parent2.3.4.RELEASEcom.zmzm-mp-generator0.0.1-SNAPSHOTzm-mp-generatorDemo project for Spring Boot11org.springframework.bootspring-boot-starter-testtestcom.baomidoumybatis-plus-boot-starter3.1.1com.baomidoumybatis-plus-generator3.1.1org.springframework.bootspring-boot-starter-freemarkermysqlmysql-connector-java5.1.47org.slf4jslf4j-log4j12org.springframework.bootspring-boot-starter-weborg.projectlomboklomboktrueorg.springframework.bootspring-boot-maven-plugin
项目需要当某事件触发时,执行http请求任务,失败时需要有重试机制,并根据失败次数的增加,重试间隔也相应增加,任务可能并发。
由于是耗时任务,首先考虑的就是用线程来实现,并且为了节约资源,因而选择线程池。
为了解决不定间隔的重试,选择Timer和TimerTask来完成
package threadpool;
public class ThreadPoolTest {
首先要说的是,不同版本数据库提供的系统表会有不同,你可以根据数据字典查看该版本数据库所提供的表。
select * from dict where table_name like '%SESSION%';
就可以查出一些表,然后根据这些表就可以获得会话信息
select sid,serial#,status,username,schemaname,osuser,terminal,ma
Admin类的主要方法注释:
1. 创建表
/**
* Creates a new table. Synchronous operation.
*
* @param desc table descriptor for table
* @throws IllegalArgumentException if the table name is res
public class LinkListTest {
/**
* we deal with two main missions:
*
* A.
* 1.we create two joined-List(both have no loop)
* 2.whether list1 and list2 join
* 3.print the join
事件回顾:由于需要修改同一个模板,里面包含2个不同的内容,第一个里面使用的时间差和第二个里面名称不一样,其他过滤器,内容都大同小异。希望杜绝If这样比较傻的来判断if-show or not,继续追究其源码。
var b = "{{",
a = "}}";
this.startSymbol = function(a) {