SpringBoot

1.Spring Boot

1.历史

  • 样板化配置,springBoot可以简化项目的配置,让SSM项目的配置变得更加简单
  • 内置了tomcat服务器,以后的web项目不用部署,直接运行main方法后,就启动了tomcat,tomcat里面就有我们的项目

2.定义

3.优缺点

4.适用场景

5.第一个SpringBoot程序

1.新建Maven项目

2.引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SpringBoot</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
	
	<!-- 1.配置jdk版本,因为springboot2依赖了Spring5,Spring5又依赖jdk8,所以jdk至少8版本-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>
    </dependencies>
</project>

3.引入配置文件

  • application.yml/yaml或application.properties
    server:
      #修改项目端口号
      port: 8989
      #修改项目访问路径
      servlet:
        context-path: /springboot_test
    

4.编写启动类和接口

  • 启动类
    package com.wd;
    
    import org.springframework.boot.SpringApplication;
    
    //类名一般以项目名称+Appliction,注意如果取SpringBootApplication,导入的注解需要带包名以区分
    //注意springboot扫描的范围,放在次一级的包中,只有建在这个包里面的springboot才会扫描本包以及子包中的注解
    //启动类上加注解@SpringBootApplication
    @org.springframework.boot.autoconfigure.SpringBootApplication
    public class SpringBootApplication {
        //启动tomcat部署项目
        public static void main(String[] args) {
            SpringApplication.run(SpringBootApplication.class,args);
        }
    
    }
    
  • 接口
    package com.wd.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    @RequestMapping("/test")
    public class TestController {
    
        @RequestMapping("hello")
        @ResponseBody
        public String hello(){
            return "hello  springboot";
        }
    }
    

6.测试配置

  • 1.点击启动类
    2022-10-18 12:21:43.430  INFO 19204 --- [           main] com.wd.SpringBootApplication             : Starting SpringBootApplication on DESKTOP-6RBSD56 with PID 19204 (E:\MySelfProject\SpringBoot\target\classes started by 32929 in E:\MySelfProject\SpringBoot)
    2022-10-18 12:21:43.434  INFO 19204 --- [           main] com.wd.SpringBootApplication             : No active profile set, falling back to default profiles: default
    2022-10-18 12:21:44.154  INFO 19204 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8989 (http)
    2022-10-18 12:21:44.162  INFO 19204 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2022-10-18 12:21:44.162  INFO 19204 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]
    2022-10-18 12:21:44.226  INFO 19204 --- [           main] o.a.c.c.C.[.[.[/springboot_test]         : Initializing Spring embedded WebApplicationContext
    2022-10-18 12:21:44.226  INFO 19204 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 742 ms
    2022-10-18 12:21:44.376  INFO 19204 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2022-10-18 12:21:44.522  INFO 19204 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8989 (http) with context path '/springboot_test'
    2022-10-18 12:21:44.524  INFO 19204 --- [           main] com.wd.SpringBootApplication             : Started SpringBootApplication in 1.553 seconds (JVM running for 2.533)
    2022-10-18 12:23:13.427  INFO 19204 --- [nio-8989-exec-1] o.a.c.c.C.[.[.[/springboot_test]         : Initializing Spring DispatcherServlet 'dispatcherServlet'
    2022-10-18 12:23:13.427  INFO 19204 --- [nio-8989-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
    2022-10-18 12:23:13.434  INFO 19204 --- [nio-8989-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 7 ms
    
  • 访问接口
    http://localhost:8989/springboot_test/test/hello/
    

6.@SpringBootApplication注解

  • 1.SpringBoot启动类上面的注解为@SpringBootApplication,这个注解主要的三个子注解
    • 1.@SpringBootConfiguration
    • 2.@EnableAutoConfiguration
    • 3.@ComponentScan

1.@ComponentScan

  • 1.该注解是指定SpringBoot去扫描哪些包下的注解,然后交给Spring容器管理,默认是扫描该该注解所在包及其子包下的注解
  • 2.通过scanBasePackages属性可以指定扫描哪些包(当入口类不在当前文件的外层包时)
    //注意:子注解的属性可以在父注解中配置
    @SpringBootApplication(scanBasePackages = "com.wd.controller")
    

2.@EnableAutoConfiguration

  • 这个注解跟springboot的start机制有关系,springboot能够减少配置文件,都是依赖了这个注解,这个注解可以自动去找底层jar包中的配置文件

3.SpringBootConfiguration

  • 1.非自定义类交给当前Spring容器管理可以使用@Configuration,然后通过@bean注解指定
  • 2.该注解是基于@Configuration进行封装的,表示当前的启动类也是一个配置类,可以进行@Bean注解的配置
    @org.springframework.boot.autoconfigure.SpringBootApplication
    public class SpringBootApplication {
        public static void main(String[] args) {
         SpringApplication.run(SpringBootApplication.class,args);
        }
        
        @Bean
        public TestService getTestService(){
            return new TestServiceImpl();
        }
    }
    

7.SpringBoot配置文件

  • 配置文件可以是properties,yml,yaml类型
  • 配置文件名一般是application,一般存放在resource目录下

1.配置文件优先级

  • 如果两种文件同时存在且都在resources目录下,则properties的优先级更高

2.多环境配置

  • 1.SpringBoot多环境配置有以下几种配置文件
    • 1.application.properties:默认配置
    • 2.application-dev.properties:开发环境
    • 3.application-test.properties:测试环境
    • 4.application-prod.properties:生产环境
  • 2.根据application.properties文件中的spring.profiles.active属性来设置具体被加载的配置文件(下列图片会加载application-dev.properties配置文件内容)
    在这里插入图片描述
  • 3.针对不同的配置文件可以设置不同的属性,项目启动时会先从application-dev.properties加载配置,再从application.properties配置文件加载配置,如果有重复的配置则会以application-dev.properties配置文件为准
  • 4.如果application.ymlapplication.properties配置文件同时存在,则以application.properties配置文件为准,因为后加载的配置文件中重复的配置项会覆盖先加载的配置项,两者中如果用spring.profiles.active指定其他配置文件,最终重复项以spring.profiles.active指定的配置文件为准

3.动态注解配置

  • 1.可以通过@Profile注解匹配active参数,动态加载内部配置
  • 2.其中@Profile可接受字符串数组
    在这里插入图片描述
    在这里插入图片描述
  • 3.说明
    • 1.当spring.profiles.active=hello-world,sender时,该配置类生效且第一个@Bean和第三个@Bean生效
    • 2.当spring.profiles.active=hello-world时,该配置文件生效且第一个@Bean生效
    • 3.当spring.profiles.active=sender时,该配置文件未生效所以下面的@Bean都不会生效

8.SpringBoot事务管理

9.SpringBoot自动加载

SpringBoot集成mybatis

1.引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SpringBoot</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
			<!--注意版本问题,2.2.2版本会报错-->
            <version>2.1.4.RELEASE</version>
        </dependency>
        <!--SpringBoot测试(@SpringBootTest注解)-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.1.4.RELEASE</version>
        </dependency>
        <!--mybatis集成springboot依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--mysql数据库驱动(Driver)-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!--lombok简化实体类(@Data)-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
        <!--junit测试(@SpringRunner)-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <!--SpringBoot项目必须4.12版本以上-->
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

2.引入配置文件

  • application.yaml
    server:
      #修改项目端口号
      port: 8989
      #修改项目访问路径
      servlet:
        context-path: /springboot_test
    
    spring:
      #数据源配置
      datasource:
        url: jdbc:mysql://localhost:3306/mybatis_test?useUniccode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
    
    mybatis:
      #Mybatis配置
      type-aliases-package: com.wd.domains
      mapper-locations: classpath:com/wd/mapper/*xml
    

3.编写实体类以及mapper文件

package com.wd.domains;

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
    private Double height;
    private Double weight;
}
package com.wd.mapper;

import com.wd.domains.User;

import java.util.List;

public interface UserMapper {

    List<User> selectAll();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.wd.mapper.UserMapper">

    <sql id="baseUserColumn">id,name,sex,age,height,weihgt</sql>

    <resultMap id="userMap" type="user">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="weight" column="weihgt"/>
    </resultMap>

    <!--List<User> selectAll();-->
    <select id="selectAll" resultMap="userMap">
        select <include refid="baseUserColumn"/> from t_user
    </select>

</mapper>

4.SpringBoot集成Junit测试

import com.wd.SpringBootApplication;
import com.wd.domains.User;
import com.wd.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringRunner.class)
//入口类对象作为该注解的参数
@SpringBootTest(classes = SpringBootApplication.class)
public class TestSpringBoot {

    //@Autowired Spring提供 根据类型查找容器中的对象注入
    @Resource //JDK提供 根据名称查找容器中的对象注入
    private UserMapper userMapper;

    @Test
    public void test1(){
        List<User> users = userMapper.selectAll();
        users.forEach(System.out::println);
    }
}

5.SpringBoot使用Mybatis分页插件

SpringBoot集成Mybatis-Plus

  • Mybatis-Plus(简称 MP)是 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,简化开发,提高效率
  • MyBatis-Plus提供了通用的mapper和service,可以不编写任何SQL,快速实现对表单的CRUD,批量/逻辑删除,分页等操作
    在这里插入图片描述
  • 1.扫描实体类(SQL语句不需要手动创建,自动生成)
  • 2.通过反射分析表和实体类对应关系
  • 3.生成对应的MySQL语句然后注入到Mybatis容器中

1.第一个Mybatis-Plus程序

1.建表

use mybatis_plus;
create table t_user(
	id bigint(20) not null primary key,
	name varchar(30),
	sex varchr(20)
	age int(11),
	height double(20),
	weihgt double(20)
);

2.创建maven项目

3.导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SpringBoot</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.6.3</version>
        </dependency>
        <!--SpringBoot测试(@SpringBootTest注解)-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.6.3</version>
        </dependency>
        <!--mybatis集成springboot依赖-->
<!--        <dependency>-->
<!--            <groupId>org.mybatis.spring.boot</groupId>-->
<!--            <artifactId>mybatis-spring-boot-starter</artifactId>-->
<!--            <version>1.3.2</version>-->
<!--        </dependency>-->
        <!--mybatis-plus集成springboot依赖-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
        <!--mysql数据库驱动(Driver)-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!--lombok简化实体类(@Data)-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>
        <!--junit测试(@SpringRunner)-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <!--SpringBoot项目必须4.12版本以上-->
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

4.导入配置文件

  • application.properties
  • 注意
    • 1.驱动类driver-class-name
      • spring boot 2.0(内置jdbc5驱动,驱动类使用:com.mysql.jdbc.Driver)
      • spring boot 2.1及以上(内置jdbc8驱动,驱动类使用:com.mysql.cj.jdbc.Driver)
    • 2.连接地址url
      • Mysql5.7版本的url:jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
      • MySQL8.0版本的url需要加上时区:jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
    server:
      #修改项目端口号
      port: 8989
      #修改项目访问路径
      servlet:
        context-path: /springboot_test
    
    spring:
      #数据源配置
      datasource:
        url: jdbc:mysql://localhost:3306/mybatis_test?useUniccode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
    
    mybatis-plus:
      #Mybatis-Plus配置
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      mapper-locations: classpath:com/wd/mapper/*xml
      type-aliases-package: com.wd.domains
    

5.编写实体类以及mapper文件

  • mybatis-plus动态生成接口对应的mapper文件,不需要手动创建
    在这里插入图片描述
    package com.wd.domains;
    
    import com.baomidou.mybatisplus.annotation.TableName;
    import lombok.Data;
    
    @Data
    @TableName("t_user")//表名和实体类不一致时使用@TableName指定实体类对应的表
    public class User {
        private Integer id;
        private String name;
        private String sex;
        private Integer age;
        private Double height;
        private Double weihgt;
    }
    
    package com.wd.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.wd.domains.User;
    
    public interface UserMapper extends BaseMapper<User> {
    }
    
    package com.wd;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    
    @org.springframework.boot.autoconfigure.SpringBootApplication(scanBasePackages = "com.wd.controller")
    @MapperScan("com.wd.mapper")//扫描mapper接口动态生成的代理类,也可以在具体mapper接口上使用mapper接口,二选一
    public class SpringBootApplication {
        //启动tomcat部署项目
        public static void main(String[] args) {
            SpringApplication.run(SpringBootApplication.class,args);
        }
    }
    

6.测试

import com.wd.SpringBootApplication;
import com.wd.domains.User;
import com.wd.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.List;

@RunWith(SpringRunner.class)
//入口类对象作为该注解的参数
@SpringBootTest(classes = SpringBootApplication.class)
public class TestSpringBoot {

    //@Autowired Spring提供 根据类型查找容器中的对象注入
    @Resource //JDK提供 根据名称查找容器中的对象注入
    private UserMapper userMapper;

    @Test
    public void test1(){
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}

7.添加日志配置

server:
  #修改项目端口号
  port: 8989
  #修改项目访问路径
  servlet:
    context-path: /springboot_test

spring:
  #数据源配置
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_test?useUniccode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

mybatis-plus:
  #Mybatis-Plus日志配置
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

2.基本功能

1.通用mapper(BaseMapper)

  • Mybatis-plus只是在Mybatis的基础上进行了增强,可以直接使用BaseMapper提供的代理方法,也可以自定义方法
1.自定义方法
  • 自定义方法和mybatis一样,只是需要更改为mybatis-plus的配置
    package com.wd.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.wd.domains.User;
    import org.apache.ibatis.annotations.Param;
    
    public interface UserMapper extends BaseMapper<User> {
    
        User selectByUserId(@Param("id") Integer id);
    
    }
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.wd.mapper.UserMapper">
        <!--User selectByUserId(@Param("id") Integer id);-->
        <select id="selectByUserId" resultType="User">
            select * from t_user where id = #{id}
        </select>
    </mapper>
    
    server:
      #修改项目端口号
      port: 8989
      #修改项目访问路径
      servlet:
        context-path: /springboot_test
    
    spring:
      #数据源配置
      datasource:
        url: jdbc:mysql://localhost:3306/mybatis_test?useUniccode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
    
    mybatis-plus:
      #Mybatis-Plus日志配置
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      mapper-locations: classpath:com/wd/mapper/*xml
      type-aliases-package: com.wd.domains
    
2.BaseMapper方法
import com.wd.SpringBootApplication;
import com.wd.domains.User;
import com.wd.mapper.UserMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.*;

@RunWith(SpringRunner.class)
//入口类对象作为该注解的参数
@SpringBootTest(classes = SpringBootApplication.class)
public class TestSpringBoot {

    //@Autowired Spring提供 根据类型查找容器中的对象注入
    @Resource //JDK提供 根据名称查找容器中的对象注入
    private UserMapper userMapper;

    @Test
    public void testSelect(){
        //SELECT id,name,sex,age,height,weihgt FROM t_user
        List<User> users = userMapper.selectList(null);
        //SELECT id,name,sex,age,height,weihgt FROM t_user WHERE id=?
        User user = userMapper.selectById(10);
        //SELECT id,name,sex,age,height,weihgt FROM t_user WHERE id IN ( ? , ? , ? )
        List<User> users1 = userMapper.selectBatchIds(Arrays.asList(7,8,9));
        Map<String, Object> nameMap = new HashMap<>();
        nameMap.put("name","李四");
        nameMap.put("sex","男");
        //SELECT id,name,sex,age,height,weihgt FROM t_user WHERE sex = ? AND name = ?
        List<User> users2 = userMapper.selectByMap(nameMap);

        users.forEach(System.out::println);
        System.out.println("------------------");
        users1.forEach(System.out::println);
        System.out.println("------------------");
        users2.forEach(System.out::println);
        System.out.println("------------------");
        System.out.println(user);

        User user1 = userMapper.selectByUserId(2);
        System.out.println(user1);

    }

    @Test
    public void testInsert(){
        //mybatis-plus默认通过雪花算法生成id,所以一般id为Long类型
        User user = new User(null, "七十二", "男", 18, 185.5, 115.3);
        //INSERT INTO t_user ( id, name, sex, age, height, weihgt ) VALUES ( ?, ?, ?, ?, ?, ? )
        int result = userMapper.insert(user);

        System.out.println("result:" + result);
        System.out.println("id:" + user.getId());

    }

    @Test
    public void testDelete(){
        User user = new User(1, "七十一", "男", 18, 58.2, 15.3);
        //DELETE FROM t_user WHERE id=?
        int result = userMapper.deleteById(2066276353);
        //DELETE FROM t_user WHERE id=?
        int result1 = userMapper.deleteById(user);
        //DELETE FROM t_user WHERE id IN ( ? , ? )
        int result2 = userMapper.deleteBatchIds(Arrays.asList(10,11));
        Map<String, Object> nameMap = new HashMap<>();
        nameMap.put("name","李四");
        nameMap.put("sex","男");
        //DELETE FROM t_user WHERE sex = ? AND name = ?
        int result3 = userMapper.deleteByMap(nameMap);
        System.out.println("result:" + result);
        System.out.println("result1:" + result1);
        System.out.println("result2:" + result2);
        System.out.println("result:" + result3);
    }

    @Test
    public void testUpdate(){
        User user = new User(8, "七十一", "男", 18, 58.2, 15.3);
        //UPDATE t_user SET name=?, sex=?, age=?, height=?, weihgt=? WHERE id=?
        int result = userMapper.updateById(user);

        System.out.println("result:" + result);
        System.out.println("id:" + user.getId());
    }
}

2.通用service

package com.wd.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.wd.domains.User;

public interface UserService extends IService<User> {
}
package com.wd.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wd.domains.User;
import com.wd.mapper.UserMapper;
import com.wd.service.UserService;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> >implements UserService {
}
import com.wd.SpringBootApplication;
import com.wd.domains.User;
import com.wd.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.util.*;

@RunWith(SpringRunner.class)
//入口类对象作为该注解的参数
@SpringBootTest(classes = SpringBootApplication.class)
public class TestSpringBoot {
    @Resource
    private UserService userService;
    
    @Test
    public void testServiceMethods(){
        long count = userService.count();
        System.out.println("总数量:" + count);
        //批量添加的方法在service中,其中也是通过多次执行单个sql添加语句完成批量添加
        List<User> users = new ArrayList<>();
        users.add(new User());
        users.add(new User());
        userService.saveBatch(users);
    }
}

3.常用注解

1.@TableName
  • Mybatis-plus中如果实体类和表的名称不一致,可以在实体上使用@TableName注解指定对应的表的名称
    @TableName("t_user")//表名和实体类不一致时使用@TableName指定实体类对应的表
    
  • 全局配置也可实现@TableName的效果,全局实体类都加上对应前缀
    mybatis-plus:
      #Mybatis-Plus日志配置
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      mapper-locations: classpath:com/wd/mapper/*xml
      type-aliases-package: com.wd.domains
      #Mybatis-Plus的全局配置
      global-config:
        db-config:
          table-prefix: t_
    
2.@TableId
  • 1.Mybatis-Plus默认将id作为主键,如果主键名不为id则会报错
  • 2.当没有设置主键名为id时,可以通过@TableId将指定属性设置为主键
  • 3.当主键名和属性名不对应时,可以通过@TableId的value属性指定该实体类属性对应的字段名
  • 4.当想使用主键的其他生成策略时,可以通过@TableId的type属性制定该主键的生成策略,默认为雪花算法(IdType.ASSIGN_ID)
    @TableId(type = IdType.AUTO)//自增
    
  • 全局配置也可实现@TableId的效果
    mybatis-plus:
      #Mybatis-Plus日志配置
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      mapper-locations: classpath:com/wd/mapper/*xml
      type-aliases-package: com.wd.domains
      #Mybatis-Plus的全局配置
      global-config:
        db-config:
          #设置实体类所对应的统一前缀
          table-prefix: t_
          #设置统一的主键生成策略
          id-type: auto
    
3.@TableField
  • 当普通实体类属性名和表的字段名不对应,可以通过@TableField设置对应关系
    @TableField(value = "weihgt")
        private Double weight;
    
4.@TableLogic
  • 逻辑删除:假删除,将对应数据中代表是否被删除字段的状态修改为被删除状态(数据库中仍能看到此条数据记录,此时变成了修改状态)
  • 物理删除:真实删除,将对应数据从数据库中删除,之后查询不到此条被删除的数据
  • 使用场景:可以进行数据恢复
实现逻辑删除
  • 数据表中创建逻辑删除状态列is_deleted,设置默认值为0,默认存在
  • 实体类中创建字段isDeleted,然后加上注解@TableLogic
  • 此时删除变为为修改删除状态列的状态
    @TableLogic
        private Integer isDeleted;
    

4.条件构造器

1.Wrapper架构
  • 架构图在这里插入图片描述
  • Wrapper:条件构造抽象类,最顶端父类
    • AbstractWrapper:用于查询条件封装,生成sql的where条件
      • QueryWrapper::查询条件封装
      • UpdateWrapper:Update条件封装
      • AbstractLambdaWrapper:使用Lambda语法
        • LambdaQueryWrapper:用于Lambda语法使用的查询Wrapper
        • LambdaUpdateWrapper:用于Lambda语法使用的更新Wrapper
2.QueryWrapper
  • 1.组装条件查询
    	@Test
        public void testWrapperMethods(){
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.like("name","七")
                    .eq("sex","男")
                    .isNotNull("age");
            //SELECT id,name,sex,age,height,weihgt AS weight FROM t_user WHERE (name LIKE ? AND sex = ? AND age IS NOT NULL)
            List<User> users = userMapper.selectList(userQueryWrapper);
            System.out.println(users);
        }
    
  • 2.组装排序查询
    @Test
     public void testWrapperMethods(){
         QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
         userQueryWrapper.orderByDesc("age")
                 .orderByAsc("height");
         //SELECT id,name,sex,age,height,weihgt AS weight FROM t_user ORDER BY age DESC,height ASC
         List<User> users = userMapper.selectList(userQueryWrapper);
         System.out.println(users);
         /*
         [
                 User(id=-85364734, name=手动阀, sex=男, age=25, height=null, weight=null), 
                 User(id=8, name=七十一, sex=男, age=18, height=58.2, weight=15.3), 
                 User(id=12, name=萨达, sex=女, age=18, height=165.0, weight=80.0), 
                 User(id=-2111225855, name=七十二, sex=男, age=18, height=185.5, weight=115.3), 
                 User(id=-72781822, name=萨达时, sex=女, age=null, height=null, weight=null)
         ]
          */
     }
    
  • 3.组装删除查询
    @Test
     public void testWrapperMethods(){
         QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
         userQueryWrapper.isNull("age");
         //DELETE FROM t_user WHERE (age IS NULL)
         int result = userMapper.delete(userQueryWrapper);
         System.out.println("result:" + result);
     }
    
  • 4.组装修改查询
    @Test
     public void testWrapperMethods(){
         QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
         userQueryWrapper.isNull("age");
         User user = new User();
         user.setName("赵六");
         user.setAge(18);
         user.setHeight(185.0);
         user.setSex("男");
         user.setWeight(65.5);
         //UPDATE t_user SET name=?, sex=?, age=?, height=?, weihgt=? WHERE (age IS NULL)
         int result = userMapper.update(user,userQueryWrapper);
         System.out.println("result:" + result);
     }
    
  • 5.条件优先查询
    @Test
     public void testWrapperMethods(){
         //and()和or()可以提高优先级
         QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
         userQueryWrapper.like("name","赵")
                 .between("age",10,40);
         //SELECT id,name,sex,age,height,weihgt AS weight FROM t_user WHERE (name LIKE ? AND age BETWEEN ? AND ?)
    	//userQueryWrapper.like("name","赵")
    	//.and(wrapper -> wrapper.between("age",10,40));
         //SELECT id,name,sex,age,height,weihgt AS weight FROM t_user WHERE (name LIKE ? AND (age BETWEEN ? AND ?))
         List<User> users = userMapper.selectList(userQueryWrapper);
         users.forEach(System.out::println);
     }
    
  • 6.查询指定字段
    @Test
     public void testWrapperMethods(){
         QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
         userQueryWrapper.select("name","sex","age").between("age",10,40);
         //SELECT name,sex,age FROM t_user WHERE (age BETWEEN ? AND ?)
         List<Map<String, Object>> maps = userMapper.selectMaps(userQueryWrapper);
         maps.forEach(System.out::println);
     }
    
  • 7.组装子查询
    @Test
     public void testWrapperMethods() {
         QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
         userQueryWrapper.inSql("id", "select id from t_user where age <= 100");
         //SELECT id,name,sex,age,height,weihgt AS weight FROM t_user WHERE (id IN (select id from t_user where age <= 100))
         List<User> users = userMapper.selectList(userQueryWrapper);
         users.forEach(System.out::println);
     }
    
3.UpdateWrapper
  • 1.组装条件修改
    @Test
     public void testWrapperMethods() {
         UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<User>();
         userUpdateWrapper.like("name","赵")
                 .and(wrapper -> wrapper.between("age",10,20));
         userUpdateWrapper.set("name","王五");
         //UPDATE t_user SET name=? WHERE (name LIKE ? AND (age BETWEEN ? AND ?))
         int result = userMapper.update(null, userUpdateWrapper);
         System.out.println("result:" + result);
     }
    
4.实际开发组装条件
@Test
 public void testWrapperMethods() {
     //通过形参从前端传数据
     String name = "王";
     Integer ageBegin = 15;
     Integer ageEnd = 30;
     QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
     if(StringUtils.isNotBlank("name")){
         //isNotBlank:判断某个字符不是空字符串,不是空白符,不是null
         userQueryWrapper.like("name",name);
     }
     if(ageBegin != null){
         userQueryWrapper.ge("age",ageBegin);
     }
     if(ageEnd != null){
         userQueryWrapper.lt("age",ageEnd);
     }
     List<User> users = userMapper.selectList(userQueryWrapper);
     users.forEach(System.out::println);
 }
5.condition组装条件
@Test
 public void testWrapperMethods() {
     //通过形参从前端传数据
     String name = "王";
     Integer ageBegin = 15;
     Integer ageEnd = 30;
     QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.like(StringUtils.isNotBlank("name"),"name",name)
             .gt(ageBegin != null,"age",ageBegin)
             .lt(ageEnd != null,"age",ageEnd);
     List<User> users = userMapper.selectList(userQueryWrapper);
     users.forEach(System.out::println);
 }
6.LambdaQueryWrapper
@Test
 public void testWrapperMethods() {
     //通过形参从前端传数据
     String name = "王";
     Integer ageBegin = 15;
     Integer ageEnd = 30;
     LambdaQueryWrapper<User> userQueryWrapper = new LambdaQueryWrapper<>();
     //使用lambda表达式自动获取属性名
     userQueryWrapper.like(StringUtils.isNotBlank("name"),User::getName,name)
             .gt(ageBegin != null,User::getAge,ageBegin)
             .lt(ageEnd != null,User::getAge,ageEnd);
     List<User> users = userMapper.selectList(userQueryWrapper);
     users.forEach(System.out::println);
 }
7.LambdaUpdateWrapper
@Test
 public void testWrapperMethods() {
     LambdaUpdateWrapper<User> userUpdateWrapper = new LambdaUpdateWrapper<>();
     userUpdateWrapper.like(User::getName,"王")
             .and(wrapper -> wrapper.between(User::getAge,10,20));
     userUpdateWrapper.set(User::getName,"Nissan");
     //UPDATE t_user SET name=? WHERE (name LIKE ? AND (age BETWEEN ? AND ?))
     int result = userMapper.update(null, userUpdateWrapper);
     System.out.println("result:" + result);
 }

3.Mybatis-Plus分页插件

  • Mybatis Plus自带分页插件,只要简单的配置即可实现分页功能
  • MybatisPlusConfig.java
    package com.wd.config;
    
    import com.baomidou.mybatisplus.annotation.DbType;
    import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MybatisPlusConfig {
    
        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor(){
            MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
            mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
            return mybatisPlusInterceptor;
        }
    }
    
    @Test
     public void testPage() {
         Page<User> userPage = new Page<>(1,3);
         userMapper.selectPage(userPage,null);
         System.out.println(userPage);
         System.out.println(userPage.getRecords());
         System.out.println(userPage.getCurrent());
         System.out.println(userPage.getPages());
     }
    

1.自定义方法使用分页插件

  • 自定义接口的返回值和第一个形参必须是Page对象
    /**
      * 通过年龄查询用户信息并分页
      * @param page Mybatis-Plus所提供的分页对象,必须位于第一个参数位置
      * @param age 年龄
      * @return
      */
     Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.wd.mapper.UserMapper">
        <!--Page<User> selectPageVo(@Param("page") Page<User> page,@Param("age") Integer age);-->
        <!--注意需要在plus配置文件中配置别名,xml文件中别名不区分大小写-->
        <select id="selectPageVo" resultType="User">
            select * from t_user where age > #{age}
        </select>
    </mapper>
    
    @Test
     public void tetPageVo() {
         Page<User> userPage = new Page<>(1,3);
         userMapper.selectPageVo(userPage,10);
         System.out.println(userPage.getRecords());
     }
    

4.Mybatis-Plus乐观锁插件

  • 前提:多线程增删改操作导致数据不一致
    @Test
        public void testProduct01(){
            Product productL = productMapper.selectById(1);
            System.out.println("李四查询商品价格:" + productL.getPrice());
            Product productW = productMapper.selectById(1);
            System.out.println("王五查询商品价格:" + productW.getPrice());
            productL.setPrice(productL.getPrice()+50);
            productMapper.updateById(productL);
            productW.setPrice(productW.getPrice()-30);
            productMapper.updateById(productW);
    
            Product product = productMapper.selectById(1);
            //原值90,正确结果应该为110,结果却为90,因为前者操作被后者操作覆盖
            System.out.println("老板查询商品价格" + product.getPrice());
        }
    
  • 悲观锁:线程A操作数据时,线程B只能阻塞等待
  • 乐观锁:线程A和B都可以操作数据,不过需要比较条件,一般项目中使用version作为比较条件
    //数据表和实体类中都添加version字段
    //取出记录时,获取当前version
    SELECT id,name,price,version FROM t_product WHERE id = 1
    //更新时,version+1,如果where语句中的version版本不对,则更新失败
    UPDATE product SET proce=price+50,version=version+1 WHERE id = 1 AND version = 1
    

1.建表

create table t_product(
	id bigint(20) not null,
	name varchar(30) null default NULL,
	price int(11) default 0,
	version int(11) default 0,
	primary key(id)
);

2.实体类

package com.wd.domains;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

@Data
@TableName("t_product")
public class Product {
    private Long id;
    private String name;
    private Integer price;
	@Version//标识乐观锁版本号字段
    private Integer version;
}

3.配置乐观锁插件

package com.wd.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        //添加分页插件
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //添加乐观锁插件
        mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

4.测试

@Test
    public void testProduct01(){
        Product productL = productMapper.selectById(1);
        System.out.println("李四查询商品价格:" + productL.getPrice());
        Product productW = productMapper.selectById(1);
        System.out.println("王五查询商品价格:" + productW.getPrice());
        productL.setPrice(productL.getPrice()+50);
        productMapper.updateById(productL);
        productW.setPrice(productW.getPrice()-30);
        productMapper.updateById(productW);

        Product product = productMapper.selectById(1);
        //原值90,正确结果应该为110,结果却为50,因为versiong改变后,王五的更新失败
        System.out.println("老板查询商品价格" + product.getPrice());
    }

5.正确代码

@Test
 public void testProduct01(){
     Product productL = productMapper.selectById(1);
     System.out.println("李四查询商品价格:" + productL.getPrice());
     Product productW = productMapper.selectById(1);
     System.out.println("王五查询商品价格:" + productW.getPrice());
     productL.setPrice(productL.getPrice()+50);
     productMapper.updateById(productL);
     productW.setPrice(productW.getPrice()-30);
     int result = productMapper.updateById(productW);
     //操作失败则重试
     if(result == 0){
         Product productNew = productMapper.selectById(1);
         productNew.setPrice(productNew.getPrice()-30);
         productMapper.updateById(productNew);
     }

     Product product = productMapper.selectById(1);
     System.out.println("老板查询商品价格" + product.getPrice());
 }

5.通用枚举

  • 表中的某些字段值是固定的(例:性别只有男或女),可以通过Mybatis-Plus的通用枚举实现

1.创建枚举类

package com.wd.enums;

import com.baomidou.mybatisplus.annotation.EnumValue;
import lombok.Getter;

@Getter//枚举中存储的是常量,所以不需要Setter方法
public enum SexEnum {
   MALE(1,"男"),
   FEMALE(2,"女");
   
   //属性
   @EnumValue //将注解所标识的属性的值存储到数据库中,不设置会报错
   private Integer sex;
   @EnumValue
   private String sexName;

   //构造器
   SexEnum(Integer sex, String sexName) {
       this.sex = sex;
       this.sexName = sexName;
   }
}

2.实体类中使用枚举属性

private SexEnum sex;

3.设置配置文件

mybatis-plus:
 #Mybatis-Plus日志配置
 configuration:
   log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
 mapper-locations: classpath:com/wd/mapper/*xml
 type-aliases-package: com.wd.domains
 #Mybatis-Plus的全局配置
 global-config:
   db-config:
     #设置实体类所对应的统一前缀
     table-prefix: t_
     #设置统一的主键生成策略
     id-type: auto
 # 扫描通用枚举的包
 type-enums-package: com.wd.enums

4.测试

   @Test
   public void testInsert() {
       //mybatis-plus默认通过雪花算法生成id,所以一般id为Long类型
       User user = new User(null, "七十二", SexEnum.MALE, 18, 185.5, 115.3);
       //INSERT INTO t_user ( id, name, sex, age, height, weihgt ) VALUES ( ?, ?, ?, ?, ?, ? )
       int result = userMapper.insert(user);

       System.out.println("result:" + result);
       System.out.println("id:" + user.getId());
	}

6.代码生成器

1.引入依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.1</version>
</dependency>
<dependency>
     <groupId>org.freemarker</groupId>
     <artifactId>freemarker</artifactId>
     <version>2.3.31</version>
</dependency>

2.快速生成

  • 点击运行即可
    @Test
     public void FastAutoGeneratorTest(){
         FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_test?useUniccode=true&characterEncoding=utf-8&useSSL=false", "root", "root")
                 //全局配置
                 .globalConfig(builder -> {
                     builder.author("wd") // 设置作者
                             //.enableSwagger() // 开启 swagger 模式
                             .fileOverride() // 覆盖已生成文件
                             .outputDir("E:\\Mybatis-Plus"); // 指定输出目录
                 })
                 //包配置
                 .packageConfig(builder -> {
                     builder.parent("com.wd") // 设置父包名
                             .moduleName("mybatisplus") // 设置父包模块名
                             .pathInfo(Collections.singletonMap(OutputFile.mapperXml, "E:\\Mybatis-Plus")); // 设置mapperXml生成路径
                 })
                 //策略配置
                 .strategyConfig(builder -> {
                     builder.addInclude("t_user") // 设置需要生成的表名
                             .addTablePrefix("t_", "c_"); // 设置过滤表前缀
                 })
                 .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                 .execute();
     }
    

7.多数据源

  • 使用于多种场景:纯粹多库(当前项目操作的表分布在多个数据库中),读写分离,一主多从,混合模式等
  • 纯粹多库情景
    • 两个表分别存放在不同的数据库中

1.引入依赖

<dependency>
       <groupId>com.baomidou</groupId>
       <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
       <version>3.5.0</version>
</dependency>

2.创建数据库及表

3.配置多数据源

spring:
# 配置数据源信息
datasource:
 dynamic:
   primary: master #设置默认的数据源或者数据源组,默认值即为master
   strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
   datasource:
     master:
       url: //localhost:3306/mybatis_test?useUniccode=true&characterEncoding=utf-8&useSSL=false
       username: root
       password: root
       driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
     slave_1:
       url: //localhost:3306/mybatis_plus?useUniccode=true&characterEncoding=utf-8&useSSL=false
       username: root
       password: root
       driver-class-name: com.mysql.jdbc.Driver

4.创建domains,mapper,service

  • 通过@DB(“对应数据源配置名”)在service中选择所使用的数据源
  • 其中创建domains和mapper省略,步骤如上述所示
    package com.wd.service;
    
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.wd.domains.User;
    
    public interface UserService extends IService<User> {
    }
    
    package com.wd.service;
    
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.wd.domains.Product;
    
    public interface ProductService extends IService<Product> {
    }
    
    package com.wd.service.impl;
    
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.wd.domains.User;
    import com.wd.mapper.UserMapper;
    import com.wd.service.UserService;
    import org.springframework.stereotype.Service;
    
    @DS("master")
    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> >	implements UserService {
    }
    
    package com.wd.service.impl;
    
    import com.baomidou.dynamic.datasource.annotation.DS;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.wd.domains.Product;
    import com.wd.mapper.ProductMapper;
    import com.wd.service.ProductService;
    import org.springframework.stereotype.Service;
    
    @DS("slave_1")//通过@DS注解指定使用的数据源
    @Service
    public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
    }
    

5.测试

@Test
 public void testDataSource(){
     System.out.println(userService.getById(1));
     System.out.println(productService.getById(1));
 }

8.MyBatisX插件

  • MyBatisX是一款基于IDEA的快速开发插件
    在这里插入图片描述
  • 如上图所示安装即可,安装好后可以在Mapper接口和Mapper文件上通过标志彼此定位

1.MyBatisX代码快速生成

  • 1.IDEA配置Database数据源
    在这里插入图片描述
  • 2.由键单击t_user后点击MybatisX-Generator
    在这里插入图片描述
    在这里插入图片描述

2.MybatisX代码快速生成CRUD

  • 在Mapper接口中根据见名知意编辑方法名,然后Alt+Enter选择如下图所示选项,自动生成SQL
    在这里插入图片描述

9.雪花算法

  • 需要选择合适的方法去应对数据规模的增长,以应对逐渐增长的访问压力和数据量
  • 数据库的扩展方式主要包括:业务分库,主从复制,数据库分表

1.数据库分表

  • 将不同业务数据分散存储到不同的数据库服务器,能够支撑百万甚至千万用户规模的业务,但如果业务继续发展,同一业务的单表数据也会达到单台数据库服务器的处理瓶颈,所以需要对单表数据进行拆分
  • 单表数据拆分有两种方式:垂直分表和水分分表
1.垂直分表
  • 将表中某些不常用且占了大量空间的列拆分出去
2.水平分表
  • 将表以某一标准进行分表
  • 问题:水平分表比垂直分表会引入更多复杂性,例:要求全局唯一的数据id如何处理
  • 主键自增
    优点:可以随着数据的增加平滑的扩充新的表
    缺电:分段大小的选取不好确定,分段太小会导致子表数量过多,分段太大会导致单表依然存在性能问题
  • 取模
  • 用主键%数据表个数
    优点:表分布比较均匀
    缺电:扩充新的表很麻烦,所有数据都要重分布
    雪花算法
  • 雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性
  • 核心思想
  • 长度共64bit(一个long型)
  • 首先是一个符号位,1bit标识,由于long基本类型在java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0
  • 41bit时间戳(毫秒级),存储的时间的差值
  • 10位作为及其的ID
  • 12bit作为毫秒内的流水号
    优点:整体上按时间自增排序,并且整个分布式系统不会产生ID碰撞,并且效率高
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值