MyBatis使用Zookeeper保存数据库的配置可动态刷新的实现代码

yizhihongxing

下面我将为你详细讲解使用Zookeeper保存数据库的配置并实现动态刷新的实现过程。本文主要分为以下几个部分:

  1. MyBatis使用Zookeeper保存数据库的配置的原理
  2. 实现动态刷新的流程
  3. 代码实现及示例说明

1. MyBatis使用Zookeeper保存数据库的配置的原理

MyBatis使用Zookeeper保存数据库的配置,可以将配置信息保存在Zookeeper的某个节点上,MyBatis应用程序可以从该节点上获取配置信息。由于数据存储在Zookeeper上,因此可以实现动态刷新,直接修改Zookeeper上的配置,应用程序能够及时获取最新的配置信息。

以下是使用Zookeeper保存MyBatis数据库配置的具体原理:

  • 在MyBatis配置文件中添加Zookeeper配置信息(如Zookeeper连接地址、节点路径等);
  • 应用程序启动时,连接Zookeeper并获取指定节点上的配置信息;
  • 将获取到的配置信息设置到MyBatis的SqlSessionFactoryBean中;
  • 当Zookeeper上的配置信息发生变化时,应用程序能够及时获取最新的配置信息,并将其设置到SqlSessionFactoryBean中。

2. 实现动态刷新的流程

具体实现动态刷新的流程如下:

  • 连接Zookeeper,获取指定节点上的配置信息;
  • 构建MyBatis的SqlSessionFactoryBean时,将获取到的配置信息设置到该Bean中;
  • 监听Zookeeper节点上配置信息的变化;
  • 当Zookeeper上的配置信息发生变化时,动态更新SqlSessionFactoryBean中的配置信息。

3. 代码实现及示例说明

下面以一个实例来说明如何使用Zookeeper保存数据库的配置并实现动态刷新。

代码实现

在这个实现中,我们使用了Spring和Curator来连接Zookeeper。而这里使用了org.springframework.jdbc.datasource.DataSourceTransactionManager来实现事务控制的方式,如有需要,可以查看源代码中详细的内容。

  1. 在pom.xml文件中添加以下依赖:
<!-- MyBatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>

<!-- Curator -->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>5.1.0</version>
</dependency>

<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.1.0</version>
</dependency>
  1. 在MyBatis配置文件中添加Zookeeper的配置信息:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath*:mapper/*Mapper.xml"/>

    <property name="configLocation" value="classpath:/mybatis-config.xml"/>
    <property name="configurationProperties">
        <props>
            <prop key="zookeeper.url">192.168.1.101:2181</prop>
            <prop key="zookeeper.config.node">/config/mybatis</prop>
        </props>
    </property>
</bean>
  1. 实现Zookeeper的连接和配置信息的获取逻辑:
@Service
public class ZookeeperHolder {

    private static final Logger LOGGER = LoggerFactory.getLogger(ZookeeperHolder.class);

    private CuratorFramework curatorFramework;

    private String zookeeperConnectUrl;

    private String zookeeperConfigNode;

    private Properties props;

    public ZookeeperHolder(//
                           @Value("${zookeeper.url}") String zookeeperConnectUrl,//
                           @Value("${zookeeper.config.node}") String zookeeperConfigNode) {
        this.zookeeperConnectUrl = zookeeperConnectUrl;
        this.zookeeperConfigNode = zookeeperConfigNode;

        try {
            curatorFramework = CuratorFrameworkFactory.newClient(zookeeperConnectUrl, new ExponentialBackoffRetry(1000, 3));
            curatorFramework.start();
            props = loadFromZookeeper();
        } catch (Exception exception) {
            LOGGER.error("Failed to get config from zookeeper, will continue with empty config", exception);
        }
    }

    public Properties getProps() {
        return props;
    }

    public void addChangeListener() throws Exception {
        PathChildrenCache childrenCache = new PathChildrenCache(curatorFramework, zookeeperConfigNode, true);
        childrenCache.getListenable().addListener(new PathChildrenCacheListener() {
            @Override
            public void childEvent(CuratorFramework curatorFramework, PathChildrenCacheEvent pathChildrenCacheEvent) {
                switch (pathChildrenCacheEvent.getType()) {
                    case CHILD_ADDED:
                    case CHILD_REMOVED:
                    case CHILD_UPDATED:
                        try {
                            Properties newProps = loadFromZookeeper();
                            if (newProps != null && newProps.size() > 0) {
                                synchronized (ZookeeperHolder.this) {
                                    ZookeeperHolder.this.props = newProps;
                                }

                                LOGGER.info("Update zookeeper props: {}", newProps);
                            } else {
                                LOGGER.warn("No found properties at zookeeper node: {}", zookeeperConfigNode);
                            }
                        } catch (Exception exception) {
                            LOGGER.error("Failed to update config from zookeeper", exception);
                        }
                        break;
                    default:
                        LOGGER.warn("Unknown event type: {}", pathChildrenCacheEvent.getType());
                        break;
                }
            }
        });

        childrenCache.start();
    }

    private Properties loadFromZookeeper() throws Exception {
        if (curatorFramework.checkExists().forPath(zookeeperConfigNode) == null) {
            LOGGER.warn("Node not exists in zookeeper node: {}", zookeeperConfigNode);
            return null;
        }

        Properties props = new Properties();

        List<String> children = curatorFramework.getChildren().forPath(zookeeperConfigNode);
        for (String child : children) {
            byte[] bytes = curatorFramework.getData().forPath(zookeeperConfigNode + "/" + child);
            if (bytes == null) {
                LOGGER.warn("Not found data for child: {}", child);
                continue;
            }

            String value = new String(bytes, "UTF-8");
            props.put(child, value);
        }

        return props;
    }
}
  1. 在MyBatis的Mapper和Service中,通过@Autowired注入ZookeeperHolder,然后将获取到的配置信息设置到SqlSessionFactoryBean中即可:
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private ZookeeperHolder zookeeperHolder;

    @Override
    public User queryUserById(Long id) {
        DataSource dataSource = new DruidDataSource();
        JdbcTransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment("Development", transactionFactory, dataSource);
        Configuration configuration = new Configuration(environment);
        configuration.setLazyLoadingEnabled(true);
        configuration.addMapper(UserMapper.class);

        Properties properties = zookeeperHolder.getProps();
        if (properties != null) {
            Set<Map.Entry<Object, Object>> entrySet = properties.entrySet();
            for (Map.Entry<Object, Object> entry : entrySet) {
                configuration.set(entry.getKey().toString(), entry.getValue().toString());
            }
        }

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
        SqlSession session = sqlSessionFactory.openSession();
        try {
            UserMapper userMapper = session.getMapper(UserMapper.class);
            return userMapper.queryUserById(id);
        } finally {
            session.close();
        }
    }
}
  1. 将ZookeeperHolder添加到Spring的Bean容器中,然后在Spring的创建和启动过程中添加监听器:
@Configuration
public class MyConfig implements WebApplicationInitializer {
    @Bean
    public ZookeeperHolder zookeeperHolder() {
        return new ZookeeperHolder("192.168.1.101:2181", "/config/mybatis");
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(MyConfig.class);

        servletContext.addListener(new ContextLoaderListener(rootContext));

        try {
            rootContext.getBean(ZookeeperHolder.class).addChangeListener();
        } catch (Exception exception) {
            LOGGER.error("Failed to add zookeeper change listener", exception);
        }
    }
}

示例说明

在这个实现中,我们使用了一个名为/config/mybatis的Zookeeper节点来存储MyBatis的配置信息,包括JDBC的URL、用户名、密码等信息。

下面是一个简单的MyBatis Mapper和Service用于查询用户信息并返回。这些示例代码都是基于上面介绍的代码实现中编写的:

@Mapper
@Repository
public interface UserMapper {
    User queryUserById(@Param("id") Long id);
}

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User queryUserById(Long id) {
        return userMapper.queryUserById(id);
    }
}

最后,我们假设我们需要修改数据库的密码。我们不需要重启整个应用程序,只需要将密码更新到Zookeeper中即可。这样,MyBatis应用程序会及时从Zookeeper获取最新的密码。

以上就是使用Zookeeper保存数据库的配置并实现动态刷新的实现过程。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:MyBatis使用Zookeeper保存数据库的配置可动态刷新的实现代码 - Python技术站

(0)
上一篇 2023年6月16日
下一篇 2023年6月16日

相关文章

  • 详解spring整合shiro权限管理与数据库设计

    详解Spring整合Shiro权限管理与数据库设计 引言 本文详细讲解如何使用Spring框架整合Shiro权限管理,并给出完整的数据库设计方案和示例代码。 Shiro简介 Shiro是一个强大的Java安全框架,可以提供身份认证、授权、加密等各种安全相关的功能。Shiro使用非常简单,易于集成到Java应用中。 Spring整合Shiro权限管理 引入Sh…

    Java 2023年5月20日
    00
  • 如何解决hibernate一对多注解懒加载失效问题

    下面就来详细讲解如何解决 Hibernate 一对多注解懒加载失效问题。 问题描述 在 Hibernate 中,我们通过一对多的注解来建立两个表的关联关系。如果这个关联关系是懒加载的,那么在查询父表时,子表的数据不会立即被加载,而会在需要使用时再去查询。但是有时候会遇到懒加载失效的问题,这时候就需要解决。下面就是一些常见的解决方法。 解决方法一:使用 Hib…

    Java 2023年5月20日
    00
  • 聊聊Spring MVC JSON数据交互的问题

    下面是详细讲解“聊聊Spring MVC JSON数据交互的问题”的完整攻略。 1. 什么是Spring MVC Spring MVC是Spring框架中的一个模块,它是一种基于Java的应用程序设计框架,可以用于快速开发Java Web应用程序。Spring MVC是一种MVC设计模式的实现,它实现了一个前端控制器(Front Controller)模式,…

    Java 2023年6月15日
    00
  • Java顺序表实现图书管理系统

    让我详细讲解一下“Java顺序表实现图书管理系统”的完整攻略。 概述 顺序表是一种简单、易于实现的数据结构,在实现图书管理系统时,可以用来存储图书信息,如书名、作者、出版社、出版日期等。本文将介绍如何使用Java语言实现顺序表来完成一个简单的图书管理系统。 步骤 1.定义Book类 首先,我们需要定义一个Book类来表示图书信息。该类包含以下属性: 书名(S…

    Java 2023年5月30日
    00
  • Mybatis中使用万能的Map传参实现

    现在我将给你详细讲解“Mybatis中使用万能的Map传参实现”完整攻略,让我们开始吧。 什么是Mybatis? MyBatis 是一个基于 Java 的持久层框架。通过配置 XML 映射文件或注解方式将 java 对象与 SQL 语句映射,是非常流行的 ORM 框架。Mybatis 提供了很多查询方法,我们可以使用 select、update、insert…

    Java 2023年5月20日
    00
  • Midjourney 提示词工具(10 个国内外最好最推荐的)

    Midjourney,是一个革命性的基于人工智能的艺术生成器,可以从被称为提示的简单文本描述中生成令人惊叹的图像。Midjourney已经迅速成为艺术家、设计师和营销人员的首选工具(包括像我这样根本不会设计任何东西的无能之辈)。 为了帮助你开始使用这个强大的工具,我们汇编了一份15个资源的清单,可以帮助你为你的下一个项目制作更好的提示语……或者让我们…

    Java 2023年4月22日
    00
  • Java对字符串进行加密解密

    Java 对字符串进行加密解密攻略 简介 Java 中提供了多种加密解密的方案,涉及对称加密、非对称加密、哈希算法等等。本文将主要讲解在 Java 中对字符串进行加密解密的方法。 对称加密 对称加密是指加密和解密使用同一个密钥的方式,常见的有 AES、DES 等算法。 AES 加密 在 Java 中使用 AES 进行加密解密的主要步骤如下: 生成一个 AES…

    Java 2023年5月26日
    00
  • SpringBoot HikariCP连接池详解

    SpringBoot HikariCP连接池详解 本文介绍如何使用SpringBoot和HikariCP来管理MySQL数据库连接池。 什么是HikariCP? HikariCP是一个高效的、快速的、轻量级的JDBC连接池,取名自日本的“光之屋”。与其他连接池相比,它有更快的启动时间、更小的内存占用以及更高的性能。 SpringBoot集成HikariCP …

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部