CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
mysql
mysql-connector-java
com.baomidou
mybatis-plus-boot-starter
3.0.5
org.projectlombok
lombok
true
说明,使用 mybatis-plus 可以省略大量的代码,尽量不要同时导入 mybatis 和 mybatis-plus
spring:
datasource:
username: root
password: mima
url: jdbc:mysql://192.168.2.136:3306/mybatis-plus?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
driver-class-name: com.mysql.cj.jdbc.Driver
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
@Repository // 代表持久层
public interface UserMapper extends BaseMapper<User> {
}
@MapperScan("com.ybs.mybatisplus.mapper")
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
// 参数是一个Wrapper条件构造器
//查询心全部用户
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
User(id=1, name=Jone, age=18, [email protected])
User(id=2, name=Jack, age=20, [email protected])
User(id=3, name=Tom, age=28, [email protected])
User(id=4, name=Sandy, age=21, [email protected])
User(id=5, name=Billie, age=24, [email protected])
问题
1、sql mybatis-plus 生成
2、方法 mybatis-plus 生成
我们所有的sql都是不可见,我们希望知道是怎么执行的,配置日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
结果
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4a8a0099] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1157484092 wrapping com.mysql.cj.jdbc.ConnectionImpl@712c5463] will not be managed by Spring
==> Preparing: SELECT id,name,age,email FROM user
==> Parameters:
<== Columns: id, name, age, email
<== Row: 1, Jone, 18, [email protected]
<== Row: 2, Jack, 20, [email protected]
<== Row: 3, Tom, 28, [email protected]
<== Row: 4, Sandy, 21, [email protected]
<== Row: 5, Billie, 24, [email protected]
<== Total: 5
@Test
public void testInsert(){
User user = new User();
user.setName("Paulson 的测试");
user.setAge(44);
user.setEmail("[email protected]");
int result = userMapper.insert(user); // 自动生成ID
System.out.println(user);
System.out.println(result);
}
结果
User(id=1241297892581425154, name=Paulson 的测试, age=44, [email protected])
数据库中插入的id的默认值是全局的默认id
分布式系统唯一ID生成(uuid, 自增id, 雪花算法, redis)
雪花算法: snowflake ,结果是一个Long类型的ID。核心思想:毫秒数,机器id,毫秒内的流水号,0
@Test
public void testUpdate(){
User user = new User();
// 通过条件自动拼接动态sql
user.setId(6L);
user.setAge(55);
user.setName("Paulson 的更新");
userMapper.updateById(user);
}
所有的sql都是自动动态配置的
创建时间、修改时间 自动完成这些操作,不希望手动更新
阿里巴巴开发手册:所有数据库表:gmt_create, gmt_modified. 几乎所有的表都要配置,而且需要自动化实现
方式一、数据库级别(工作中不允许修改数据库)
1、在表中新增字段 create_time, update_time,修改默认值 CURRENT_TIMESAMP
2、再次测试插入方法。先同步实体类
private Date createTime;private Date updateTime;
方式二、代码级别
1、删除数据的默认值
2、实体类时间字段属性增加主键
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
3、编写处理器来处理这个注解
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* 插入时的填充策略
* @param metaObject
*/
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill....");
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
/**
* 更新时的填充策略
* @param metaObject
*/
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill....");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
4、测试插入、测试更新。观察时间变化
原子引用
乐观锁:顾名思义,十分乐观,认为不会出现问题,无论干什么都不去上锁! 如果出现了问题,再次更新值测试。version, new version。
悲观锁:顾名思义,十分悲观,总是认为会出现问题,无论干什么都上上锁,再去操作!
乐观锁机制
乐观锁实现方式:
- 取出记录时,获取当前的version
- 更新时,带上version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version 不对,就更新失败
--- A
update user set name = 'ybs', version = version +1 where id =2 and version = 1
--- B 线程抢先完成,这个时候version=2,会导致A修改失败
update user set name = 'ybs', version = version +1 where id =2 and version = 1
测试一下MP的乐观锁插件
1、给数据库中增加version字段
2、给实体类加对应的字段
@Version // 乐观锁private Integer version;
3、注册组件
@MapperScan("com.ybs.mybatisplus.mapper")
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
4、测试乐观锁
```java
// 测试乐观锁,成功
@Test
public void testOptimisticLocker(){
// 1、查询用户信息
User user = userMapper.selectById(1L);
// 2、修改用户信息
user.setName("ybs");
user.setEmail("[email protected]");
// 3、执行更新操作
userMapper.updateById(user);
}
// 测试乐观锁,失败,多线程
@Test
public void testOptimisticLocker2(){
// 线程1
User user = userMapper.selectById(1L);
user.setName("ybs111");
user.setEmail("[email protected]");
// 线程2 模拟另一个线程进行插队操作
User user2 = userMapper.selectById(1L);
user2.setName("ybs222");
user2.setEmail("[email protected]");
userMapper.updateById(user2);
// 自旋锁多次尝试操作。多线程下一定要加锁
// 3、执行更新操作
userMapper.updateById(user); // 如果没有乐观锁,就会覆盖插队线程的值
}
##### **查询**
```java
// 测试查询
@Test
public void testSelectById(){
User user = userMapper.selectById(1L);
System.out.println(user);
List users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
// 条件查询 使用Map操作
@Test
public void testSelectByBatchIds(){
HashMap map = new HashMap<>();
// 自定义查询条件
map.put("name", "Paulson 的测试");
map.put("age", 43);
List users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
1、原始的limit 进行分页
2、使用第三方插件 pageHelper
3、mybatis 也内置了分页插件
如何使用
1、 配置拦截器组件
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
2、直接使用Page对象
// 测试分页插件
@Test
public void testPage(){
// 参数一:当前页
// 参数二:页面大小
Page<User> page = new Page<>(2, 5);
userMapper.selectPage(page, null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal());
}
// 测试删除
@Test
public void testDeleteById(){
userMapper.deleteById(2L);
userMapper.deleteBatchIds(Arrays.asList(2, 3));
}
@Test
public void testDeleteMap(){
HashMap<String, Object> map = new HashMap<>();
map.put("name", "Paulson 的测试");
userMapper.deleteByMap(map);
}
物理删除: 从数据库中直接移除
逻辑删除:在数据库中没有被删除。通过一个变量让他失效。 deleted=0 =》 deleted=1
管理员可以查看删除的记录! 防止数据的丢失,类似于回收站
1、数据增加deleted
2、实体类中增加属性
@TableLogic
private Integer deleted;
3、配置
@Bean public LogicSqlInjector logicSqlInjector(){ return new LogicSqlInjector(); }
# 逻辑删除
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
平时开发中,会遇到一些慢sql druid
mp 提供性能分析插件,如果超过设置的时间就会停止运行
1、导入插件
@Bean
@Profile({"dev","test"}) //设置 dev test 环境开启
public PerformanceInterceptor performanceInterceptor(){
PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
performanceInterceptor.setMaxTime(100); //设置SQL执行的最大时间,如果超过了则不实行
performanceInterceptor.setFormat(true); // 是否格式化
return performanceInterceptor;
}
2、修改配置 配置环境为dev或test
spring:
profiles:
active: dev
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
- 结果 (只要超过了设置的时间就会抛出异常)
Time:20 ms - ID:com.ybs.mybatisplus.mapper.UserMapper.selectList
Execute SQL:
SELECT
id,
name,
age,
email,
version,
deleted,
create_time,
update_time
FROM
user
WHERE
deleted=0
Wrapper 十分重要
写一些复杂的sql可以使用它来替代
1、// 查询 name 不为空,邮箱不为空,年龄大于22
@Test
public void testWrapper1(){
// 查询 name 不为空,邮箱不为空,年龄大于22
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.isNotNull("email")
.ge("age", 12);
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}
2、查询一个数据 selectOne 出现多个结果使用 selectList
```java
@Test
void test2(){
// 查询 name 为 Sandy
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "Sandy");
User user = userMapper.selectOne(wrapper);
System.out.println(user);
}
3、年龄在20-30之间
void test3(){
// 年龄在20-30之间
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age", 20, 30);
Integer count = userMapper.selectCount(wrapper);// 查询结果数目
System.out.println(count);
}
4、 模糊查询:name 不包含 E 的, email t开头
@Test
void test4(){
// 模糊查询:name 不包含 E 的, email t开头
QueryWrapper wrapper = new QueryWrapper<>();
// 左和右 t%
wrapper.notLike("name", "P")
.likeRight("email", "t");
List
5、内查询 IN
@Test
void test5(){
// 内查询 IN
QueryWrapper<User> wrapper = new QueryWrapper<>();
// id 在子查询中查出来
wrapper.inSql("id", "select id from user where id < 3");
List<Object> objects = userMapper.selectObjs(wrapper);
objects.forEach(System.out::println);
}
public class YbsCode {
public static void main(String[] args) {
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gc = new GlobalConfig();
String project_path = System.getProperty("user.dir");
gc.setOutputDir(project_path + "/src/main/java");
gc.setAuthor("YBS");
gc.setOpen(false);
gc.setFileOverride(false);
gc.setServiceName("%sService"); // 去service的I
gc.setIdType(IdType.ID_WORKER);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
// 2、设置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("");
dsc.setDriverName("");
dsc.setUsername("");
dsc.setPassword("");
dsc.setDbType(DbType.MYSQL);
// 2、包的配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("blog");
pc.setParent("com.ybs");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
// 4、测试配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user");
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
strategy.setLogicDeleteFieldName("deleted");
// 自动填充
TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
mpg.setStrategy(strategy);
mpg.execute(); // 执行
//
}
}