SpringBoot多数据源的两种实现方式实例

目录
  • 前言
  • 基于dynamic-datasource实现多数据源
    • dynamic-datasource介绍
    • dynamic-datasource特性
    • 使用 @DS 切换数据源
    • @DS使用实例
  • 基于AOP手动实现多数据源
  • 总结

前言

公司项目有连接多个不同数据库的需求,特研究了一下,根据网上的资料,造了一个基于AOP方式的数据源切换轮子,但继续探索,突然发现有开源的多数据源管理启动器。不过,本篇两种方式都会介绍。

基于dynamic-datasource实现多数据源

dynamic-datasource介绍

dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。

其支持 Jdk 1.7+, SpringBoot 1.4.x 1.5.x 2.x.x

dynamic-datasource特性

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  • 支持数据库敏感配置信息 加密 ENC()。
  • 支持每个数据库独立初始化表结构schema和数据库database。
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 支持 自定义注解 ,需继承DS(3.2.0+)。
  • 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
  • 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
  • 提供 自定义数据源来源 方案(如全从数据库加载)。
  • 提供项目启动后 动态增加移除数据源 方案。
  • 提供Mybatis环境下的 纯读写分离 方案。
  • 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
  • 提供 基于seata的分布式事务方案。
  • 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。

我们目前只探讨使用dynamic-datasource进行数据源切换,其他请自行搜索

dynamic-datasource的相关约定

  1. dynamic-datasource只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何CRUD。
  2. 配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。
  3. 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
  4. 默认的数据源名称为 master ,你可以通过 spring.datasource.dynamic.primary 修改。
  5. 方法上的注解优先于类上注解。
  6. DS支持继承抽象类上的DS,暂不支持继承接口上的DS。

引入dynamic-datasource依赖

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

配置数据源

spring:
  datasource:
    dynamic:
      primary: mysql #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        mysql:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
        pgsql:
          url: ENC(xxxxx) # 内置加密
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: org.postgresql.Driver

使用 @DS 切换数据源

@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解

注解 结果
不使用@DS注解 默认数据源,即primary: mysql
@DS(“dsName”) dsName可以为组名也可以为具体某个库的名称

@DS使用实例

@Service
@DS("mysql")
public class UserServiceImpl implements UserService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  // 不使用@DS注解则代表使用默认数据源
  // 如果类上存在,则使用类上标注的数据源
  public List selectAll() {
    return  jdbcTemplate.queryForList("select * from user");
  }

  @Override
  @DS("pgsql")
  // 方法上注解 优先于 类上注解,即使类上标注也优先采用方法上的标注
  public List selectByCondition() {
    return  jdbcTemplate.queryForList("select * from user where age >10");
  }
}

基于AOP手动实现多数据源

本次代码参考 https://github.com/mianshenglee/my-example/tree/master/multi-datasource/dynamic-datasource ,因源码不满足的需求,因此我在此基础做了修改。

项目工程结构

项目依赖

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>me.mason.demo</groupId>
    <artifactId>dynamic-datasource</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dynamic-datasource</name>
    <description>Demo project for dynamic datasource</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--spring boot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--mysql 驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置文件

server.port=8080
server.servlet.context-path=/dd

logging.level.root=INFO
logging.level.me.mason.demo.dynamicdatasource.mapper=DEBUG

# mybatis-plus
mybatis-plus.type-aliases-package=me.mason.demo.dynamicdatasource.entity
# 默认位置,可不配置
#mybatis-plus.mapper-locations=classpath*:/mapper/*.xml
mybatis.mapper-locations=classpath*:/mapper/*.xml
# 使用数据库自增ID
mybatis-plus.global-config.db-config.id-type=auto

# master
spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.master.url=jdbc:mysql://10.0.1.243:3306/scheduling?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8
spring.datasource.master.username=root
spring.datasource.master.password=123456

# slave
spring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.slave.url=jdbc:mysql://10.0.1.243:3306/scheduling1?useSSL=false&serverTimezone=GMT%2B8&characterEncoding=UTF-8
spring.datasource.slave.username=root
spring.datasource.slave.password=123456

自定义注解

// 标记注解可使用在方法与类上
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DS {
	// 默认值为MASTER
    String value() default DataSourceConstants.DS_KEY_MASTER;
}

编写DataSourceConstants

/**
 * 数据源常量
 **/
public class DataSourceConstants {
    /**
     * master数据源
     */
    public static final String DS_KEY_MASTER = "master";
    /**
     * slave数据源
     */
    public static final String DS_KEY_SLAVE = "slave";
}

动态数据源名称上下文处理

/**
 * 动态数据源名称上下文处理
 **/
public class DynamicDataSourceContextHolder {

    /**
     * 动态数据源名称上下文
     */
    private static final ThreadLocal<String> DATASOURCE_CONTEXT_KEY_HOLDER = new ThreadLocal<>();

    /**
     * 设置数据源
     * @param key
     */
    public static void setContextKey(String key){
        DATASOURCE_CONTEXT_KEY_HOLDER.set(key);
    }

    /**
     * 获取数据源名称
     * @return
     */
    public static String getContextKey(){
        String key = DATASOURCE_CONTEXT_KEY_HOLDER.get();
        return key == null?DataSourceConstants.DS_KEY_MASTER:key;
    }

    /**
     * 删除当前数据源名称
     */
    public static void removeContextKey(){
        DATASOURCE_CONTEXT_KEY_HOLDER.remove();
    }
}

获取当前动态数据源方法

/**
 * 动态数据源
 **/
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getContextKey();
    }
}

动态数据源配置

/**
 * 动态数据源配置
 **/
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
@Configuration
// 此处我们
//@PropertySource("classpath:config/jdbc.properties")
@MapperScan(basePackages = "me.mason.demo.dynamicdatasource.mapper")
public class DynamicDataSourceConfig {
    @Bean(DataSourceConstants.DS_KEY_MASTER)
    // 需要与配置文件中对应
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DruidDataSource masterDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(DataSourceConstants.DS_KEY_SLAVE)
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DruidDataSource slaveDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DynamicDataSource dynamicDataSource() {
        Map<Object, Object> dataSourceMap = new HashMap<>(2);
        dataSourceMap.put(DataSourceConstants.DS_KEY_MASTER, masterDataSource());
        dataSourceMap.put(DataSourceConstants.DS_KEY_SLAVE, slaveDataSource());
        //设置动态数据源
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setTargetDataSources(dataSourceMap);
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
        return dynamicDataSource;
    }

}

AOP切面

/**
 * 切面
 */
@Aspect
@Component
//@Order(-10)
public class DynamicDataSourceAspect {
	// 以在类上使用了@Service作为切入点
    @Pointcut("@within(org.springframework.stereotype.Service)")
    public void dataSourcePointCut() {
    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Class<?> aClass = Class.forName(signature.getDeclaringType().getName());
        // 方法优先,如果方法上存在注解,则优先使用方法上的注解
        if (signature.getMethod().isAnnotationPresent(DS.class)) { DynamicDataSourceContextHolder.setContextKey(signature.getMethod().getAnnotation(DS.class).value());
            // 其次类优先,如果类上存在注解,则使用类上的注解
        }else  if (aClass.isAnnotationPresent(DS.class)) { DynamicDataSourceContextHolder.setContextKey(aClass.getAnnotation(DS.class).value());
            // 如果都不存在,则使用默认
        }   else {
 DynamicDataSourceContextHolder.setContextKey(DataSourceConstants.DS_KEY_MASTER);
        }
        try {
            return joinPoint.proceed();
        } finally {
            DynamicDataSourceContextHolder.removeContextKey();
        }
    }
}

编写TestUser实体

@Data
@TableName("test_user")
public class TestUser implements Serializable {
    private static final long serialVersionUID = 1L;
    /** id */
    private Long id;
    /** 姓名 */
    private String name;
    /** 手机号 */
    private String phone;
    /** 职称职别 */
    private String title;
    /** 邮箱 */
    private String email;
    /** 性别 */
    private String gender;
    /** 出生时间 */
    private Date dateOfBirth;
    /** 1:已删除,0:未删除 */
    private Integer deleted;
    /** 创建时间 */
    private Date sysCreateTime;
    /** 创建人 */
    private String sysCreateUser;
    /** 更新时间 */
    private Date sysUpdateTime;
    /** 更新人 */
    private String sysUpdateUser;
    /** 版本号 */
    private Long recordVersion;

    public TestUser() {
    }
}

TestUserMapper

@Service
//@DS(DataSourceConstants.DS_KEY_SLAVE)
public class TestUserService {
    @Autowired
    private TestUserMapper testUserMapper;

    /**
     * 查询master库User
     * @return
     */
//    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getMasterUser(){
        QueryWrapper<TestUser> queryWrapper = new QueryWrapper<>();
        return testUserMapper.selectAll(queryWrapper.isNotNull("name"));
    }

    /**
     * 查询slave库User
     * @return
     */
//    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getSlaveUser(){
        return testUserMapper.selectList(null);
    }
}

TestUserService

@Service
//@DS(DataSourceConstants.DS_KEY_SLAVE)
public class TestUserService {
    @Autowired
    private TestUserMapper testUserMapper;

    /**
     * 查询master库User
     * @return
     */
//    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getMasterUser(){
        QueryWrapper<TestUser> queryWrapper = new QueryWrapper<>();
        return testUserMapper.selectAll(queryWrapper.isNotNull("name"));
    }

    /**
     * 查询slave库User
     * @return
     */
//    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getSlaveUser(){
        return testUserMapper.selectList(null);
    }
}

TestUserController

@RestController
@RequestMapping("/user")
public class TestUserController {
    @Autowired
    private TestUserService testUserService;
    /**
     * 查询全部
     */
    @GetMapping("/listall")
    public Object listAll() {
        int initSize = 2;
        Map<String, Object> result = new HashMap<>(initSize);
        List<TestUser> masterUser = testUserService.getMasterUser();
        result.put("masterUser", masterUser);
        List<TestUser> slaveUser = testUserService.getSlaveUser();
        result.put("getSlaveUser", slaveUser);
        return ResponseResult.success(result);
    }

}

MapperXml

<?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="me.mason.demo.dynamicdatasource.mapper.TestUserMapper">
    <select id="selectAll" resultType="me.mason.demo.dynamicdatasource.entity.TestUser">
        select * from test_user
        <if test="ew!=null">
          ${ew.customSqlSegment}
        </if>
    </select>
</mapper>

启动测试

不使用注解

@Service
//@DS(DataSourceConstants.DS_KEY_SLAVE)
public class TestUserService {
    @Autowired
    private TestUserMapper testUserMapper;

    /**
     * 查询master库User
     * @return
     */
//    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getMasterUser(){
        QueryWrapper<TestUser> queryWrapper = new QueryWrapper<>();
        return testUserMapper.selectAll(queryWrapper.isNotNull("name"));
    }

    /**
     * 查询slave库User
     * @return
     */
//    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getSlaveUser(){
        return testUserMapper.selectList(null);
    }

}

效果

该代码优先级与使用框架效果一致,即不使用注解将默认使用MASTER数据库,方法上存在注解优先使用方法上标注的注解。

已知MASTER 6条数据, SLAVE4条数据

访问 http://127.0.0.1:8080/dd/user/listall 查看效果

类上使用注解

@Service
@DS(DataSourceConstants.DS_KEY_SLAVE)
public class TestUserService {
    @Autowired
    private TestUserMapper testUserMapper;

    /**
     * 查询master库User
     * @return
     */
//    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getMasterUser(){
        QueryWrapper<TestUser> queryWrapper = new QueryWrapper<>();
        return testUserMapper.selectAll(queryWrapper.isNotNull("name"));
    }

    /**
     * 查询slave库User
     * @return
     */
//    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getSlaveUser(){
        return testUserMapper.selectList(null);
    }
}

效果

方法上使用注解

@Service
@DS(DataSourceConstants.DS_KEY_SLAVE)
public class TestUserService {
    @Autowired
    private TestUserMapper testUserMapper;
    /**
     * 查询master库User
     * @return
     */
    @DS(DataSourceConstants.DS_KEY_SLAVE)
    public List<TestUser> getMasterUser(){
        QueryWrapper<TestUser> queryWrapper = new QueryWrapper<>();
        return testUserMapper.selectAll(queryWrapper.isNotNull("name"));
    }
    /**
     * 查询slave库User
     * @return
     */
    @DS(DataSourceConstants.DS_KEY_MASTER)
    public List<TestUser> getSlaveUser(){
        return testUserMapper.selectList(null);
    }
}

效果

总结

到此这篇关于SpringBoot多数据源的两种实现方式的文章就介绍到这了,更多相关SpringBoot多数据源实现内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring Boot+Jpa多数据源配置的完整步骤

    关于 有时候,随着业务的发展,项目关联的数据来源会变得越来越复杂,使用的数据库会比较分散,这个时候就会采用多数据源的方式来获取数据.另外,多数据源也有其他好处,例如分布式数据库的读写分离,集成多种数据库等等. 下面分享我在实际项目中配置多数据源的案例.话不多说了,来一起看看详细的介绍吧 步骤 1.application.yml文件中,配置数据库源.这里primary是主库,secondary是从库. server: port: 8089 # 多数据源配置 #primary spring: pri

  • springboot下配置多数据源的方法

    一.springboot 简介 SpringBoot使开发独立的,产品级别的基于Spring的应用变得非常简单,你只需"just run". 我们为Spring平台及第三方库提 供开箱即用的设置,这样你就可以有条不紊地开始.多数Spring Boot应用需要很少的Spring配置. 你可以使用SpringBoot创建Java应用,并使用 java -jar 启动它或采用传统的war部署方式.我们也提供了一个运行"spring 脚本"的命令行工具. 二.传统的Dat

  • Spring Boot 动态数据源示例(多数据源自动切换)

    本文实现案例场景: 某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库. 为了在开发中以最简单的方法使用,本文基于注解和AOP的方法实现,在spring boot框架的项目中,添加本文实现的代码类后,只需要配置好数据源就可以直接通过注解使用,简单方便. 一配置二使用 1. 启动类注册动态数据源 2. 配置文件中配置多个数据源 3. 在需要的方法上使用注解指定数据源 1.在启动类添加 @Import({Dyna

  • 详解SpringBoot和Mybatis配置多数据源

    目前业界操作数据库的框架一般是 Mybatis,但在很多业务场景下,我们需要在一个工程里配置多个数据源来实现业务逻辑.在SpringBoot中也可以实现多数据源并配合Mybatis框架编写xml文件来执行SQL.在SpringBoot中,配置多数据源的方式十分便捷, 下面开始上代码: 在pom.xml文件中需要添加一些依赖 <!-- Spring Boot Mybatis 依赖 --> <dependency> <groupId>org.mybatis.spring.b

  • springboot + mybatis配置多数据源示例

    在实际开发中,我们一个项目可能会用到多个数据库,通常一个数据库对应一个数据源. 代码结构: 简要原理: 1)DatabaseType列出所有的数据源的key---key 2)DatabaseContextHolder是一个线程安全的DatabaseType容器,并提供了向其中设置和获取DatabaseType的方法 3)DynamicDataSource继承AbstractRoutingDataSource并重写其中的方法determineCurrentLookupKey(),在该方法中使用Da

  • springboot 多数据源的实现(最简单的整合方式)

    简介 相信大家有配置过多数据源,或者即将配置多数据的朋友们,会发现网上大概有以下几种方案: 1. 使用 AOP 切片进行动态数据源切换 2. 使用 MapperScan 的 basePackages 配置不同的 mapper 目录以及 template 3. 数据库代理中间件 这两种方式都能实现多数据源但是各有缺点: 1. 无法实现多数据源 XA 事物(全局事物管理 |JTA)这个缺点非常致命,配了多数据源但是没有全局事物那有什么用纯属坑爹,网上还有很多帖子教程使用这种虽然配置稍微简单但是如果你

  • SpringBoot项目中的多数据源支持的方法

    1.概述 项目中经常会遇到一个应用需要访问多个数据源的情况,本文介绍在SpringBoot项目中利用SpringDataJpa技术如何支持多个数据库的数据源. 具体的代码参照该 示例项目 2.建立实体类(Entity) 首先,我们创建两个简单的实体类,分别属于两个不同的数据源,用于演示多数据源数据的保存和查询. Test实体类: package com.example.demo.test.data; import javax.persistence.Entity; import javax.pe

  • Spring Boot多数据源及其事务管理配置方法

    准备工作 先给我们的项目添加Spring-JDBC依赖和需要访问数据库的驱动依赖. 配置文件 spring.datasource.prod.driverClassName=com.mysql.jdbc.Driver spring.datasource.prod.url=jdbc:mysql://127.0.0.1:3306/prod spring.datasource.prod.username=root spring.datasource.prod.password=123456 spring

  • SpringBoot多数据源的两种实现方式实例

    目录 前言 基于dynamic-datasource实现多数据源 dynamic-datasource介绍 dynamic-datasource特性 使用 @DS 切换数据源 @DS使用实例 基于AOP手动实现多数据源 总结 前言 公司项目有连接多个不同数据库的需求,特研究了一下,根据网上的资料,造了一个基于AOP方式的数据源切换轮子,但继续探索,突然发现有开源的多数据源管理启动器.不过,本篇两种方式都会介绍. 基于dynamic-datasource实现多数据源 dynamic-datasou

  • SpringBoot注册Filter的两种实现方式

    springboot版本:2.2.5 一.filter注册 springboot中添加filter有两种方式: 1.实现方法一 package com.example.demo.filter1; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.Servl

  • 详解springboot集成websocket的两种实现方式

    WebSocket跟常规的http协议的区别和优缺点这里大概描述一下 一.websocket与http http协议是用在应用层的协议,他是基于tcp协议的,http协议建立链接也必须要有三次握手才能发送信息.http链接分为短链接,长链接,短链接是每次请求都要三次握手才能发送自己的信息.即每一个request对应一个response.长链接是在一定的期限内保持链接.保持TCP连接不断开.客户端与服务器通信,必须要有客户端发起然后服务器返回结果.客户端是主动的,服务器是被动的.  WebSock

  • Android 中倒计时验证两种常用方式实例详解

    Android 中倒计时验证两种常用方式实例详解 短信验证码功能,这里总结了两种常用的方式,可以直接拿来使用.看图: 说明:这里的及时从10开始,是为了演示的时间不要等太长而修改的. 1.第一种方式:Timer /** * Description:自定义Timer * <p> * Created by Mjj on 2016/12/4. */ public class TimeCount extends CountDownTimer { private Button button; //参数依

  • bootstrap paginator分页插件的两种使用方式实例详解

    分页有两种方式: 1. 前台分页:ajax一次请求获取全部数据,适合少量数据(万条数据以下): $.ajax({ type: "GET", url: "",//后台接口地址 dataType: "json", success: function (msg) { var pages = Math.ceil(msg.data / 5);//data是数据总量 var element = $('#id');//对应ul的id element.boots

  • Vue弹窗的两种实现方式实例详解

    目录 方法一 使用.sync修饰符 方法二 使用v-model 方法一 使用.sync修饰符 element就是使用的这种方式,实现方式如下: 父组件: <template> <div id="demo"> <test-model :show.sync="showFlag"></test-model> </div> </template> <script> import testMo

  • MyBatis多数据源的两种配置方式

    前言 同一个项目有时会涉及到多个数据库,也就是多数据源.多数据源又可以分为两种情况: 1)两个或多个数据库没有相关性,各自独立,其实这种可以作为两个项目来开发.比如在游戏开发中一个数据库是平台数据库,其它还有平台下的游戏对应的数据库: 2)两个或多个数据库是master-slave的关系,比如有mysql搭建一个 master-master,其后又带有多个slave:或者采用MHA搭建的master-slave复制: MyBatis多数据源的配置主要有两种方式: 通过@MapperScan注解,

  • 详解springboot之jackson的两种配置方式

    springboot 针对jackson是自动化配置的,如果需要修改,有两种方式: 方式一:通过application.yml 配置属性说明:## spring.jackson.date-format指定日期格式,比如yyyy-MM-dd HH:mm:ss,或者具体的格式化类的全限定名 spring.jackson.deserialization是否开启Jackson的反序列化 spring.jackson.generator是否开启json的generators. spring.jackson

  • 利用SpringBoot实现多数据源的两种方式总结

    目录 前言 基于dynamic-datasource实现多数据源 dynamic-datasource介绍 dynamic-datasource的相关约定 引入dynamic-datasource依赖 配置数据源 使用 @DS 切换数据源 基于AOP手动实现多数据源 项目工程结构 项目依赖 配置文件 自定义注解 编写DataSourceConstants 动态数据源名称上下文处理 获取当前动态数据源方法 动态数据源配置 AOP切面 编写TestUser实体 TestUserMapper Test

  • 详解springboot整合Listener的两种方式

    1.通过注解 编写启动类 package cn.bl; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; @SpringBootApplication @ServletCompo

随机推荐