前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot+Mybatis+Mycat+Apollo

SpringBoot+Mybatis+Mycat+Apollo

作者头像
黑洞代码
发布2021-01-14 15:43:50
1.2K0
发布2021-01-14 15:43:50
举报

Apollo配置中心

Apollo是什么?

携程中间件团队研发的分布式配置中心。

什么是配置中心?

1.够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端。

2.具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

Apollo简介

1. Apollo服务端基于Spring Boot和Spring Cloud开发,可以直接运行,不需额外安装应用容器。

2.Apollo的Java客户端不依赖任何框架,同时对Spring/Spring Boot环境也有较好的支持。

3.Net客户端不依赖任何框架,能够运行于所有.Net运行时环境。

Apollo的特性

1.统一管理不同环境、不同集群的配置

2.配置修改实时生效(热发布)

3.版本发布管理:所有的配置发布都有版本概念,从而可以方便的支持配置的回滚。

4.灰度发布:只对部分应用实例生效,观察一段时间确认没问题后再推给所有应用实例

5.权限管理、发布审核、操作审计

6.客户端配置信息监控:可以方便的看到配置在被哪些实例使用

7.提供Java和.Net原生客户端

8.提供开放平台API

9.部署简单

Apollo的安装

一、准备工作: 1. JDK——Apollo服务端JDK1.8+,Apollo客户端JDK1.7+ 2. MySQL——5.6.5+ 3. 必备的Linux操作技能

二、下载地址

代码语言:javascript
复制
https://github.com/nobodyiam/apollo-build-scripts

三、配置信息 3.1 创建数据库 (1)创建ApolloPortalDB (2)创建ApolloConfigDB (3)验证创建结果 (4)select `Id`, `AppId`, `Name` from ApolloPortalDB.App; (5)select `NamespaceId`, `Key`, `Value`, `Comment` from ApolloConfigDB.Item; 3.2 配置数据库连接

代码语言:javascript
复制
###修改build.sh配置
(1)apollo config db info
apollo_config_db_url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
apollo_config_db_username=用户名
apollo_config_db_password=密码(如果没有密码,留空即可)
(2)apollo portal db info
apollo_portal_db_url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8
apollo_portal_db_username=用户名
apollo_portal_db_password=密码(如果没有密码,留空即可)

四、获取安装包通过编译Apollo源码的方式获取安装包。Apollo Portal需要在不同的环境访问不同的meta service(apollo-configservice)地址,所以需要在打包时提供这些信息。假设DEV的apollo-configservice未绑定域名,地址是1.1.1.1:8080,FAT的apollo-configservice绑定了域名apollo.fat.xxx.com,UAT的apollo-configservice绑定了域名apollo.uat.xxx.com,PRO的apollo-configservice绑定了域名apollo.xxx.com,那么编辑scripts/build.sh,如下修改各环境meta service服务地址,格式为{env}_meta=http://{config-service-url:port},如果某个环境不需要,也可以直接删除对应的配置项

代码语言:javascript
复制
dev_meta=http://1.1.1.1:8080
fat_meta=http://apollo.fat.xxx.com
uat_meta=http://apollo.uat.xxx.com
pro_meta=http://apollo.xxx.com
META_SERVERS_OPTS="-Ddev_meta=$dev_meta -Dfat_meta=$fat_meta -Duat_meta=$uat_meta -Dpro_meta=$pro_meta"

五、打包编译

代码语言:javascript
复制
执行./build.sh

六、获取各个安装包 6.1 获取apollo-configservice安装包 apollo-configservice位于apollo-configservice/target/目录下的apollo-configservice-x.x.x-github.zip 6.2 获取apollo-adminservice安装包 位于apollo-adminservice/target/目录下的apollo-adminservice-x.x.x-github.zip 6.3 获取apollo-portal安装包 位于apollo-portal/target/目录下的apollo-portal-x.x.x-github.zip

七、启动apollo 将对应环境的安装包上传到服务器上,解压后执行scripts/startup.sh即可。如需停止服务,执行scripts/shutdown.sh。为了方便起见,可以将多个执行脚本打包成一个执行脚本。如下:

代码语言:javascript
复制
vim startall.sh
sh ~/Downloads/code/github/apollo/apollo-adminservice/target/apollo-adminservice-1.4.0-SNAPSHOT-github/scripts/startup.sh
sh ~/Downloads/code/github/apollo/apollo-configservice/target/apollo-configservice-1.4.0-SNAPSHOT-github/scripts/startup.sh
sh ~/Downloads/code/github/apollo/apollo-portal/target/apollo-portal-1.4.0-SNAPSHOT-github/scripts/startup.sh
vim stopall.sh
sh ~/Downloads/code/github/apollo/apollo-adminservice/target/apollo-adminservice-1.4.0-SNAPSHOT-github/scripts/shutdown.sh
sh ~/Downloads/code/github/apollo/apollo-configservice/target/apollo-configservice-1.4.0-SNAPSHOT-github/scripts/shutdown.sh
sh ~/Downloads/code/github/apollo/apollo-portal/target/apollo-portal-1.4.0-SNAPSHOT-github/scripts/shutdown.sh
运行Apollo
./startall.sh

运行Apollo

代码语言:javascript
复制
./startall.sh

启动结果如下:

Apollo的使用

1. 查看配置demo

代码语言:javascript
复制
http://localhost:8070

输入用户名apollo,密码admin后登录

点击SampleApp进入配置界面,可以看到当前有一个配置timeout=100

2. 创建自己的个人项目并创建配置

此处让Apollo管理JDBC连接。我们的程序中不直接配置JDBC连接。目的是为了接下来验证项目中没有JDBC连接也可以实现数据库操作。

Spring集成Apollo

我们都遇到过项目越长越大,越来越膨胀,需要将数据库进行分库分表的需求。下面以SpringBoot+Mybatis+Mycat+Apollo实现一个从单体数据库向分库分表数据源切换的动态切换数据源的Demo。

1.准备单库单表的建表语句

代码语言:javascript
复制
#############################单表单库测试##################

DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
USE test;
CREATE TABLE customer (
  id INT NOT NULL AUTO_INCREMENT COMMENT '客户id',
  name VARCHAR(20) DEFAULT '' COMMENT '客户姓名',
  phone VARCHAR(11) DEFAULT '' COMMENT '客户手机号',
  adddate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
  updatedate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE item (
    id INT NOT NULL AUTO_INCREMENT,
    value INT NOT NULL default 0,
    adddate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
    updatedate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
    PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE customer_order (
    id INT NOT NULL AUTO_INCREMENT,
    amount INT NOT NULL default 0,
    adddate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
    updatedate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
    PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

2. 创建与以上实体表对应的Java代码

2.1 创建Model

代码语言:javascript
复制
public class Customer {
    private int id;
    private String name;
    private String phone;
    private Date addDate;
    private Date updateDate;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public Date getAddDate() {
        return addDate;
    }

    public void setAddDate(Date addDate) {
        this.addDate = addDate;
    }

    public Date getUpdateDate() {
        return updateDate;
    }

    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }
}
代码语言:javascript
复制
public class CustomerOrder {
    private int id;
    private int amount;
    private Date addDate;
    private Date updateDate;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }

    public Date getAddDate() {
        return addDate;
    }

    public void setAddDate(Date addDate) {
        this.addDate = addDate;
    }

    public Date getUpdateDate() {
        return updateDate;
    }

    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }
}
代码语言:javascript
复制
public class Item {
    private int id;
    private int value;
    private Date addDate;
    private Date updateDate;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public Date getAddDate() {
        return addDate;
    }

    public void setAddDate(Date addDate) {
        this.addDate = addDate;
    }

    public Date getUpdateDate() {
        return updateDate;
    }

    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }
}

2.2 创建DAO和Mybatis Mapper文件

代码语言:javascript
复制
@Mapper
public interface CustomerDao {
    int save(Customer customer);
    Customer query(int id);
}
代码语言:javascript
复制
@Mapper
public interface CustomerOrderDao {
    int save(CustomerOrder customer);
    CustomerOrder query(int id);
}
代码语言:javascript
复制
@Mapper
public interface ItemDao {
    int save(Item customer);
    Item query(int id);
}
代码语言:javascript
复制
<mapper namespace="com.yunxi.apollodemo.test.dao.CustomerDao">
    <resultMap id="BaseResultMap" type="com.yunxi.apollodemo.test.model.Customer">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="name" jdbcType="VARCHAR" property="name" />
        <result column="phone" jdbcType="VARCHAR" property="phone" />
        <result column="adddate" jdbcType="TIMESTAMP" property="addDate" />
        <result column="updatedate" jdbcType="TIMESTAMP" property="updateDate" />
    </resultMap>
    <select id="query" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select
        *
        from customer
        where id = #{id,jdbcType=BIGINT}
    </select>

    <insert id="save" parameterType="com.yunxi.apollodemo.test.model.Customer">
        insert into customer (id,name, phone)
        values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR})
    </insert>
</mapper>
代码语言:javascript
复制
<?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.yunxi.apollodemo.test.dao.CustomerOrderDao">
    <resultMap id="BaseResultMap" type="com.yunxi.apollodemo.test.model.CustomerOrder">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="amount" jdbcType="INTEGER" property="amount" />
        <result column="adddate" jdbcType="TIMESTAMP" property="addDate" />
        <result column="updatedate" jdbcType="TIMESTAMP" property="updateDate" />
    </resultMap>
    <select id="query" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select
        *
        from customer_order
        where id = #{id,jdbcType=BIGINT}
    </select>

    <insert id="save" parameterType="com.yunxi.apollodemo.test.model.CustomerOrder">
        insert into customer_order (id,amount)
        values (#{id,jdbcType=INTEGER}, #{amount,jdbcType=INTEGER})
    </insert>
</mapper>
代码语言:javascript
复制
<?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.yunxi.apollodemo.test.dao.ItemDao">
    <resultMap id="BaseResultMap" type="com.yunxi.apollodemo.test.model.Item">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="value" jdbcType="INTEGER" property="value" />
        <result column="adddate" jdbcType="TIMESTAMP" property="addDate" />
        <result column="updatedate" jdbcType="TIMESTAMP" property="updateDate" />
    </resultMap>
    <select id="query" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select
        *
        from item
        where id = #{id,jdbcType=BIGINT}
    </select>

    <insert id="save" parameterType="com.yunxi.apollodemo.test.model.Item">
        insert into item (id,value)
        values (#{id,jdbcType=INTEGER}, #{value,jdbcType=INTEGER})
    </insert>
</mapper>

2.3 创建Controller

代码语言:javascript
复制
@RestController
@RequestMapping("customer")
public class CustomerController {
    @Autowired
    private CustomerDao customerDao;

    @RequestMapping("/save")
    public void save() {
        Customer customer_1 = new Customer();
        customer_1.setId(1);
        customer_1.setName("yunxi");
        customer_1.setPhone("3344625292");
        customerDao.save(customer_1);
        Customer customer_2 = new Customer();
        customer_2.setId(2);
        customer_2.setName("wushuang");
        customer_2.setPhone("3190976240");
        customerDao.save(customer_2);
    }

    @RequestMapping("/query")
    public void query() {
        System.out.println("用户1=" + JSON.toJSONString(customerDao.query(1)));
        System.out.println("用户2=" + JSON.toJSONString(customerDao.query(2)));
    }
}
代码语言:javascript
复制
@RestController
@RequestMapping("customerOrder")
public class CustomerOrderController {
    @Autowired
    private CustomerOrderDao customerOrderDao;

    @RequestMapping("save")
    public void save() {
        CustomerOrder customerOrder_1 = new CustomerOrder();
        customerOrder_1.setId(1);
        customerOrder_1.setAmount(100);
        customerOrderDao.save(customerOrder_1);
        CustomerOrder customerOrder_2 = new CustomerOrder();
        customerOrder_2.setId(2);
        customerOrder_2.setAmount(200);
        customerOrderDao.save(customerOrder_2);
        CustomerOrder customerOrder_3 = new CustomerOrder();
        customerOrder_3.setId(3);
        customerOrder_3.setAmount(300);
        customerOrderDao.save(customerOrder_3);
    }

    @RequestMapping("query")
    public void query() {
        System.out.println("订单1=" + JSON.toJSONString(customerOrderDao.query(1)));
        System.out.println("订单2=" + JSON.toJSONString(customerOrderDao.query(2)));
        System.out.println("订单3=" + JSON.toJSONString(customerOrderDao.query(3)));
    }
}
代码语言:javascript
复制
@RestController
@RequestMapping("item")
public class ItemController {
    @Autowired
    private ItemDao itemDao;

    @RequestMapping("save")
    public void ave() {
        Item item_1 = new Item();
        item_1.setId(1);
        item_1.setValue(100);
        itemDao.save(item_1);
        Item item_2 = new Item();
        item_2.setId(2);
        item_2.setValue(200);
        itemDao.save(item_2);
        Item item_3 = new Item();
        item_3.setId(3);
        item_3.setValue(300);
        itemDao.save(item_3);
    }

    @RequestMapping("query")
    public void query() {
        System.out.println("商品1=" + JSON.toJSONString(itemDao.query(1)));
        System.out.println("商品2=" + JSON.toJSONString(itemDao.query(2)));
        System.out.println("商品3=" + JSON.toJSONString(itemDao.query(3)));
    }
}

2.4 配置Apollo集成

【注】此时的SpringBoot项目并没有配置JDBC连接。SpringBoot配置文件如下:

代码语言:javascript
复制
app.id=yunxi-java-apollo
server.port=9999
#Apollo Meta Server
apollo.bootstrap.enabled = true
apollo.meta=http://127.0.0.1:8080


spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456

logging.level.com.yunxi.apollodemo = debug

mybatis.type-aliases-package=com.yunxi.apollodemo.test.model
mybatis.mapper-locations=classpath:mapper/*.xml

配置SpringBoot集成Apollo:

代码语言:javascript
复制
@Slf4j
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceConfig {
    @Autowired
    ApplicationContext context;
    @Autowired
    private org.springframework.cloud.context.scope.refresh.RefreshScope refreshScope;

    @ApolloConfigChangeListener
    private void onChange(ConfigChangeEvent changeEvent) {
        DataSourceProperties dataSourceProperties = context.getBean(DataSourceProperties.class);
        changeEvent.changedKeys().stream().forEach(s -> {
            if (s.contains("spring.datasource.url")) {
                dataSourceProperties.setUrl(changeEvent.getChange(s).getNewValue());
            }
        });
        refreshScope.refresh("dataSource");
    }

    @RefreshScope
    @Bean
    public DataSource dataSource(DataSourceProperties dataSourceProperties) {
        return dataSourceProperties.initializeDataSourceBuilder().build();
    }
}

2.5 启动SpringBoot应用程序

代码语言:javascript
复制
 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.4.RELEASE)
2019-05-12 18:33:46.524  INFO 2135 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.17]
2019-05-12 18:33:46.613  INFO 2135 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-05-12 18:33:46.613  INFO 2135 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1017 ms
2019-05-12 18:33:47.119  INFO 2135 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-05-12 18:33:47.456  INFO 2135 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9999 (http) with context path ''
2019-05-12 18:33:47.459  INFO 2135 --- [           main] c.y.apollodemo.ApolloDemoApplication     : Started ApolloDemoApplication in 13.665 seconds (JVM running for 19.471)
 

2.6 测试单库单表下集成Apollo

分别在浏览器中执行输入以下连接,验证执行结果。

代码语言:javascript
复制
http://localhost:9999/customer/save
http://localhost:9999/customer/query
http://localhost:9999/customerOrder/save
http://localhost:9999/customerOrder/query
http://localhost:9999/item/save
http://localhost:9999/item/query

执行结果无异常,说明Apollo集成的单库单表的JDBC连接生效了。

此时的JDBC连接为如下配置项。

2.7 配置Mycat服务

参考本公众号Mycat安装

2.8 修改Apollo配置

将数据源修改为Mycat

再次重复执行2.6节中的操作,发现分库分表后的数据源生效。至此验证了SpringBoot+Mybatis+Mycat+Apollo集成成功。下一次再进行数据库迁移时,就不需要再加班熬夜搞通宵啦。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 落叶飞翔的蜗牛 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档