
//用于扫描mapper接口所在的包
//或者所用于扫描指定包下的mapper接口
@MapperScan("com.atguigu.mapper") @Repository public interface UserMapper extends BaseMapper{// 根据id查询用户信息,返回map集合Map selectMapById(Long id); }
@Test
public void selectMapById(){Map map = userMapper.selectMapById(1L);System.out.println(map);
} public interface UserMapper extends BaseMapper{ }
public interface UserService extends IService{ }
/*** ServiceImpl实现了IService,提供了IService中基础功能的实现* 若ServiceImpl无法满足业务需求,则可以使用自定的UserService定义方法,并在实现类中实现*/ @Service public class UserServiceImpl extends ServiceImplimplements UserService {}


@Test
public void test01(){//查询用户名包含a,年龄在20到30之间,并且邮箱不为null的用户信息SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (username LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)QueryWrapper queryWrapper = new QueryWrapper<>();queryWrapper.like("name", "a").between("age", 20, 30).isNotNull("email");//注意1:username、ageemail为数据库表的字段名//注意2:链式结构的调用//注意3:between也可以用gt和lt//注意4:逻辑删除is_deleted=0List list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);
} //按年龄降序查询用户,如果年龄相同则按id升序排列
//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,id ASC
queryWrapper.orderByDesc("age").orderByAsc("id"); public void test03(){//删除email为空的用户//DELETE FROM t_user WHERE (email IS NULL)QueryWrapper queryWrapper = new QueryWrapper<>();queryWrapper.isNull("email");//条件构造器也可以构建删除语句的条件int result = userMapper.delete(queryWrapper);//注意:如果加上了逻辑删除,那么得到的sql语句是update语句System.out.println("受影响的行数:" + result);
} @Test
public void test04() {QueryWrapper queryWrapper = new QueryWrapper<>();//将(年龄大于20并且用户名中包含有a)或邮箱为null的用户信息修改//UPDATE t_user SET age=?, email=? WHERE (username LIKE ? AND age > ? OR email IS NULL)queryWrapper.like("username", "a").gt("age", 20).or().isNull("email");User user = new User();user.setAge(18);user.setEmail("user@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("受影响的行数:" + result);
} @Test
public void test042() {QueryWrapper queryWrapper = new QueryWrapper<>();//将用户名中包含有a并且(年龄大于20或邮箱为null)的用户信息修改//UPDATE t_user SET age=?, email=? WHERE (username LIKE ? AND (age > ? OR email IS NULL))//lambda表达式内的逻辑优先运算//从源码中可以看出:这里的" i(Consumer consumer 》Wrapper) "其实就是Wraapper(条件构造器)queryWrapper.like("username", "a").and(i -> i.gt("age", 20).or().isNull("email"));User user = new User();user.setAge(18);user.setEmail("user@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("受影响的行数:" + result);
} @Test
public void test05() {//查询用户信息的username和age字段//SELECT username,age FROM t_userQueryWrapper queryWrapper = new QueryWrapper<>();queryWrapper.select("username", "age");//selectMaps()返回Map集合列表,通常配合select()使用,避免User对象中没有被查询到的列值为nullList @Test
public void test06() {//查询id小于等于3的用户信息//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (id IN (select id from t_user where id <= 3))QueryWrapper queryWrapper = new QueryWrapper<>();queryWrapper.inSql("id", "select id from user where id <= 3");List list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);
} @Test
public void test07() {//将(年龄大于20或邮箱为null)并且用户名中包含有a的用户信息修改//组装set子句以及修改条件UpdateWrapper updateWrapper = new UpdateWrapper<>();//lambda表达式内的逻辑优先运算updateWrapper.set("age", 18).set("email", "user@atguigu.com").like("username", "a").and(i -> i.gt("age", 20).or().isNull("email"));//这里必须要创建User对象,否则无法应用自动填充。如果没有自动填充,可以设置为null//UPDATE t_user SET username=?, age=?,email=? WHERE (username LIKE ? AND (age > ? OR email IS NULL))//User user = new User();//user.setName("张三");//int result = userMapper.update(user, updateWrapper);//UPDATE t_user SET age=?,email=? WHERE (username LIKE ? AND (age > ? OR email IS NULL))int result = userMapper.update(null, updateWrapper);System.out.println(result);
} @Test
public void test08() {//定义查询条件,有可能为null(用户未输入或未选择(如下拉框、复选框))String username = null;Integer ageBegin = 10;Integer ageEnd = 24;QueryWrapper queryWrapper = new QueryWrapper<>();//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace)构成if(StringUtils.isNotBlank(username)){queryWrapper.like("username","a");}if(ageBegin != null){queryWrapper.ge("age", ageBegin);}if(ageEnd != null){queryWrapper.le("age", ageEnd);}//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age >=? AND age <= ?)List users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);
} @Test
public void test08UseCondition() {//定义查询条件,有可能为null(用户未输入或未选择)String username = null;Integer ageBegin = 10;Integer ageEnd = 24;QueryWrapper queryWrapper = new QueryWrapper<>();//StringUtils.isNotBlank()判断某字符串是否不为空且长度不为0且不由空白符(whitespace)构成queryWrapper .like(StringUtils.isNotBlank(username), "username", "a").ge(ageBegin != null, "age", ageBegin).le(ageEnd != null, "age", ageEnd);//SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE (age >=? AND age <= ?)List users = userMapper.selectList(queryWrapper);users.forEach(System.out::println);
} @Test
public void test09() {//定义查询条件,有可能为null(用户未输入)String username = "a";Integer ageBegin = 10;Integer ageEnd = 24;LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();//避免使用字符串表示字段,防止运行时错误//函数式接口。 这里通过函数直接访问到实体类属性对应的表字段名。//其中:getName是属性,getAge是属性lambdaQueryWrapper.like(StringUtils.isNotBlank(username), User::getName, username).ge(ageBegin != null, User::getAge, ageBegin).le(ageEnd != null, User::getAge, ageEnd);List users = userMapper.selectList(lambdaQueryWrapper);users.forEach(System.out::println);
} @Test
public void test10() {//组装set子句LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>();lambdaUpdateWrapper.set(User::getAge, 18).set(User::getEmail, "user@atguigu.com").like(User::getName, "a").and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail)); //lambda表达式内的逻辑优先运算User user = new User();int result = userMapper.update(user, lambdaUpdateWrapper);System.out.println("受影响的行数:" + result);
} @Getter // lombok自动生成get方法(不需要设置set方法)
public enum SexEnum {MALE(1, "男"), // 值1FEMALE(2, "女"); // 值2@EnumValue // 要把枚举的哪个属性的值插入到数据中,就在这个属性上加上@EnumValue注解private Integer sex; // 属性1private String sexName; // 属性2SexEnum(Integer sex, String sexName) { // 构造器this.sex = sex;this.sexName = sexName;}
} @Test
public void test(){User user = new User();user.setName("Enum");user.setAge(20);//设置性别信息为枚举项,会将@EnumValue注解所标识的属性值存储到数据库user.setSex(SexEnum.MALE);//INSERT INTO t_user ( username, age, sex ) VALUES ( ?, ?, ? )//Parameters: Enum(String), 20(Integer), 1(Integer)int result = userMapper.insert(user);System.out.println("resutl="+result);
} spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://10.203.5.185:3306/fLearn?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=falseusername: rootpassword: MySQL#567890 mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#配置mybatis类型别名所对应的包#此配置后,默认把类名当做此类型的别名,且不区分大小写(resultType="User"和resultType="user"都是指向User.java类型)type-aliases-package: com.guigu.pojo # 配置扫描通用枚举所在的包type-enums-package: com.guigu.enums
@Configuration
@MapperScan("com.guigu.mapper") //可以将启动类中的注解移到此处
public class MybatisPlusConfig {/**** 1 怎么来配置mybatis-plus中的插件?* 这里所需要的类型是MybatisPlusInterceptor,这是mybatis-plus的一个拦截器,用于配置mybatis-plus中的插件的。* 2 为什么要使用拦截器MybatisPlusInterceptor呢?* 这里边的原理和mybatis分页插件的功能是一样的,工作流程如下 :* (1)第一步:执行查询功能。* (2)第二步:拦截器对查询功能进行拦截。* (3)第三步:拦截器对查询功能的基础上做了额外的处理,达到分页的效果(功能)。* 3 对比配置mybatis中的插件* 用的也是拦截器的方式,如配置mybatis分页插件。** @return MybatisPlusInterceptor*/@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//参数:要配置的具体插件:new PaginationInnerInterceptor(DbType.MYSQL)是专门为mysql定制实现的内部的分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;}
} @Test
public void testPage(){ //设置分页参数:页码、显示的条数Page page = new Page<>(2, 3);
//第1个参数:分页对象//第2个参数:条件构造器,如果设置为null,即查询所有//返回值就是一个Page对象,即返回上面所new出来的page对象,数据都在其中//对应的sql语句:SELECT id,name,age,email FROM user LIMIT ?userMapper.selectPage(page, null); //获取当前页数据List list = page.getRecords();list.forEach(System.out::println);System.out.println("当前页:"+page.getCurrent());System.out.println("每页显示的条数:"+page.getSize());System.out.println("总记录数:"+page.getTotal());System.out.println("总页数:"+page.getPages());System.out.println("是否有上一页:"+page.hasPrevious());System.out.println("是否有下一页:"+page.hasNext());
} @Repository public interface UserMapper extends BaseMapper{/*** 需求:根据年龄查询用户列表,分页显示** 第一步:xml自定义分页,Mapper接口方法* 第1步:如果想要mybatis-plus的分页插件来作用于我们自定义的sql语句的话,第一个参数必须得是一个分页对象:Page page。* 第二步:因为Mapper接口方法有2个参数的话* 方案1:使用mybatis提供的访问方式* 方案2:也可以使用@param来设置命名参数,来规定参数的访问规则** @param page mybatis-plus提供的分页对象,xml中可以从里面进行取值,传递参数 Page 即自动分页,必须放在第一位。虽然在自定义的sql语句中不会用到Page page,但是如果想在自定义的sql语句中使用mybatis-plus的分页插件使用分页功能,那么第一个参数必须得是Page。* @param age 年龄* @return Page */Page selectPageVo(@Param("page") Page page, @Param("age") Integer age); }
id,username,age,email
spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://10.203.5.185:3306/fLearn?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=falseusername: rootpassword: MySQL#567890 mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl#配置mybatis类型别名所对应的包#此配置后,默认把类名当做此类型的别名,且不区分大小写(resultType="User"和resultType="user"都是指向User.java类型)type-aliases-package: com.guigu.pojo
@Test
public void testSelectPageVo(){//设置分页参数Page page = new Page<>(1, 5);//sql语句:SELECT id,name,age,email FROM user WHERE age > ? LIMIT ?userMapper.selectPageVo(page, 20);//获取分页数据List list = page.getRecords();list.forEach(System.out::println);System.out.println("当前页:"+page.getCurrent());System.out.println("每页显示的条数:"+page.getSize());System.out.println("总记录数:"+page.getTotal());System.out.println("总页数:"+page.getPages());System.out.println("是否有上一页:"+page.hasPrevious());System.out.println("是否有下一页:"+page.hasNext());
} @SpringBootTest
public class LeguanTest {@Autowiredprivate ProductMapper productMapper;@Testpublic void testConcurrentUpdate() {//0、商品成本价80//1、小李获取:当前价格Product p1 = productMapper.selectById(1L);System.out.println("小李取出的价格:" + p1.getPrice());//2、小王获取:当前价格Product p2 = productMapper.selectById(1L);System.out.println("小王取出的价格:" + p2.getPrice());//3、小李修改:将价格加了50元,存入了数据库p1.setPrice(p1.getPrice() + 50);int result1 = productMapper.updateById(p1);System.out.println("小李修改结果:" + result1);//4、小王修改:将商品减了30元,存入了数据库p2.setPrice(p2.getPrice() - 30);int result2 = productMapper.updateById(p2);System.out.println("小王修改结果:" + result2);//5、老板查询最后的结果:价格覆盖,最后的结果:70(小于成本价,亏)Product p3 = productMapper.selectById(1L);System.out.println("老板查询最后的结果:" + p3.getPrice());}
} @Data
@TableName("t_product")
public class Product {private Long id;private String name;private Integer price;@Version //标识:数据库表中,哪个字段做为乐观锁版本号字段(这里是version)private Integer version;
} @SpringBootTest
public class LeguanTest {@Autowiredprivate ProductMapper productMapper;@Testpublic void testConcurrentUpdate() {//第1步:小李获获取:当前的价格,100Product p1 = productMapper.selectById(1L);//第2步:小王获获取:当前的价格,100Product p2 = productMapper.selectById(1L);//第3步:小李修改 + 50p1.setPrice(p1.getPrice() + 50);int result1 = productMapper.updateById(p1);System.out.println("小李修改的结果:" + result1);//第4步:小王修改 - 30p2.setPrice(p2.getPrice() - 30);int result2 = productMapper.updateById(p2);System.out.println("小王修改的结果:" + result2);if(result2 == 0){//第5步:操作失败,重试:重新获取version并更新p2 = productMapper.selectById(1L);p2.setPrice(p2.getPrice() - 30);result2 = productMapper.updateById(p2);}System.out.println("小王修改重试的结果:" + result2);//第6步:老板看价格,120,满意Product p3 = productMapper.selectById(1L);System.out.println("老板看价格:" + p3.getPrice());}
}