• SpringBoot整合MyBatis多数据源


    SpringBoot整合MyBatis多数据源

    一、介绍

    在平常的项目中,我们有连接数据库的需求。一般都是一个项目一个数据库,但也有例外需要连接多个数据库的。

    那么该如何配置,可以达到多数据源的需求呢。

    本次为SpringBootMyBatis的整合,其实掌握了需要配置什么,也很容易进行复刻。

    推荐访问:个人博客

    二、配置

    1)数据库准备

    首先,我们先准备三个数据库吧,这边都使用MySQL了,实际可以是不同的数据库

    • test数据库

      create database `test` character set utf8mb4 collate utf8mb4_general_ci;
      
      CREATE TABLE `sys_user` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `username` varchar(32) NOT NULL COMMENT '用户名',
        `password` varchar(128) NOT NULL COMMENT '密码',
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
      
      INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (1, 'banmoon', '1234');
      INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (2, 'user', '1234');
      
    • test01数据库

      create database `test01` character set utf8mb4 collate utf8mb4_general_ci;
      
      CREATE TABLE `sys_user` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `username` varchar(32) NOT NULL COMMENT '用户名',
        `password` varchar(128) NOT NULL COMMENT '密码',
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
      
      INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (1, 'test01', '1234');
      INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (2, 'test01User', '1234');
      
    • test02数据库

      create database `test02` character set utf8mb4 collate utf8mb4_general_ci;
      
      CREATE TABLE `sys_user` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `username` varchar(32) NOT NULL COMMENT '用户名',
        `password` varchar(128) NOT NULL COMMENT '密码',
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
      
      INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (1, 'test02', '1234');
      INSERT INTO `sys_user`(`id`, `username`, `password`) VALUES (2, 'test02User', '1234');
      

    2)配置

    首先,maven依赖包不能忘记

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.2.2</version>
    </dependency>
    

    然后,我们需要在配置文件上配置上三个数据库的配置信息。

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Shanghai&allowMultiQueries=true
        username: root
        password: 1234
    
    dynamic-datasource:
      test01:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/test01?serverTimezone=Asia/Shanghai&allowMultiQueries=true
        username: root
        password: 1234
      test02:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/test02?serverTimezone=Asia/Shanghai&allowMultiQueries=true
        username: root
        password: 1234
    

    怎么配置不重要,清爽就好,重点在于读取。

    我们需要读取上面配置文件的信息,配置生成SqlSessionTemplateSqlSessionFactoryPlatformTransactionManager,如此来达到多数据源的功能

    test数据库连接的相关配置

    package com.banmoon.test.config.datasource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import javax.sql.DataSource;
    
    @Configuration
    @MapperScan(basePackages = {"com.banmoon.test.persistent.master.mapper"},
            sqlSessionFactoryRef = "masterSqlSessionFactory")
    public class MasterDatasourceConfig {
    
        /**
         * 寻找配置文件中的数据源配置信息
         * @return
         */
        @Primary
        @Bean("masterDatasourceProperties")
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSourceProperties dataSourceProperties(){
            return new DataSourceProperties();
        }
    
        /**
         * 构建数据源
         * @param properties
         * @return
         */
        @Primary
        @Bean("masterDatasource")
        public DataSource dataSource(@Qualifier("masterDatasourceProperties") DataSourceProperties properties){
            DataSource build = DataSourceBuilder.create()
                    .driverClassName(properties.getDriverClassName())
                    .url(properties.getUrl())
                    .username(properties.getUsername())
                    .password(properties.getPassword())
                    .build();
            return build;
        }
    
        /**
         * 构建事务管理器
         * @param dataSource
         * @return
         */
        @Primary
        @Bean(name = "masterTransactionManager")
        public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("masterDatasource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
        /**
         * 构建sqlSession工厂
         * @param dataSource
         * @return
         * @throws Exception
         */
        @Bean(name = "masterSqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDatasource") DataSource dataSource) throws Exception {
            final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setTypeHandlersPackage("com.banmoon.test.persistent.master.entity");
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/master/*.xml"));
            return sessionFactoryBean.getObject();
        }
    
        /**
         * 构建sqlSession
         * @param sqlSessionFactory
         * @return
         */
        @Primary
        @Bean(name = "masterSqlSessionTemplate")
        public SqlSessionTemplate sqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    
    }
    

    test01数据库连接的相关配置

    package com.banmoon.test.config.datasource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import javax.sql.DataSource;
    
    @Configuration
    @MapperScan(basePackages = {"com.banmoon.test.persistent.test01.mapper"},
            sqlSessionFactoryRef = "test01SqlSessionFactory")
    public class Test01DatasourceConfig {
    
        @Bean("test01DatasourceProperties")
        @ConfigurationProperties(prefix = "dynamic-datasource.test01")
        public DataSourceProperties dataSourceProperties(){
            return new DataSourceProperties();
        }
    
        @Primary
        @Bean("test01Datasource")
        public DataSource dataSource(@Qualifier("test01DatasourceProperties") DataSourceProperties properties){
            DataSource build = DataSourceBuilder.create()
                    .driverClassName(properties.getDriverClassName())
                    .url(properties.getUrl())
                    .username(properties.getUsername())
                    .password(properties.getPassword())
                    .build();
            return build;
        }
    
        @Primary
        @Bean(name = "test01TransactionManager")
        public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("test01Datasource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
        @Bean(name = "test01SqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("test01Datasource") DataSource dataSource) throws Exception {
            final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setTypeHandlersPackage("com.banmoon.test.persistent.test01.entity");
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/test01/*.xml"));
            return sessionFactoryBean.getObject();
        }
    
        @Primary
        @Bean(name = "test01SqlSessionTemplate")
        public SqlSessionTemplate sqlSessionTemplate(@Qualifier("test01SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    
    }
    

    test02数据库连接的相关配置

    package com.banmoon.test.config.datasource;
    
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionFactoryBean;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import javax.sql.DataSource;
    
    @Configuration
    @MapperScan(basePackages = {"com.banmoon.test.persistent.test02.mapper"},
            sqlSessionFactoryRef = "test02SqlSessionFactory")
    public class Test02DatasourceConfig {
    
        @Bean("test02DatasourceProperties")
        @ConfigurationProperties(prefix = "dynamic-datasource.test02")
        public DataSourceProperties dataSourceProperties(){
            return new DataSourceProperties();
        }
    
        @Primary
        @Bean("test02Datasource")
        public DataSource dataSource(@Qualifier("test02DatasourceProperties") DataSourceProperties properties){
            DataSource build = DataSourceBuilder.create()
                    .driverClassName(properties.getDriverClassName())
                    .url(properties.getUrl())
                    .username(properties.getUsername())
                    .password(properties.getPassword())
                    .build();
            return build;
        }
    
        @Primary
        @Bean(name = "test02TransactionManager")
        public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("test02Datasource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
        @Bean(name = "test02SqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("test02Datasource") DataSource dataSource) throws Exception {
            final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setTypeHandlersPackage("com.banmoon.test.persistent.test02.entity");
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/test02/*.xml"));
            return sessionFactoryBean.getObject();
        }
    
        @Primary
        @Bean(name = "test02SqlSessionTemplate")
        public SqlSessionTemplate sqlSessionTemplate(@Qualifier("test02SqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    
    }
    

    还有一个需要注意,我们需要排除掉MybatisAutoConfiguration类,避免它自动进行配置

    package com.banmoon.test;
    
    import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication(exclude = MybatisAutoConfiguration.class)
    public class TestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(TestApplication.class, args);
        }
    
    }
    

    配置完成,那么该如何去写EntityMapper呢?

    请注意,在我们构建sqlSessionFactory的时候,就已经指定了它Entity的包路径和Mapper的包路径。

    所以我只需要在指定的包路径在创建EntityMapper就可以了。

    3)编写实体和Mapper

    如下进行编写User.javaUserMapper.javaUserMapper.xml

    package com.banmoon.test.persistent.master.entity;
    
    import java.io.Serializable;
    import lombok.Data;
    import lombok.EqualsAndHashCode;
    import lombok.experimental.Accessors;
    
    @Data
    @EqualsAndHashCode(callSuper = false)
    @Accessors(chain = true)
    public class User implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private Integer id;
    
        /**
         * 用户名
         */
        private String username;
    
        /**
         * 密码
         */
        private String password;
    
    }
    
    package com.banmoon.test.persistent.master.mapper;
    
    import com.banmoon.test.persistent.master.entity.User;
    import org.apache.ibatis.annotations.Mapper;
    
    import java.util.List;
    
    @Mapper
    public interface UserMapper {
    
        List<User> selectList();
    
    }
    
    <?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.banmoon.test.persistent.master.mapper.UserMapper">
    
        <!-- 通用查询映射结果 -->
        <resultMap id="BaseResultMap" type="com.banmoon.test.persistent.master.entity.User">
            <id column="id" property="id" />
            <result column="username" property="username" />
            <result column="password" property="password" />
        </resultMap>
        
        <select id="selectList" resultType="com.banmoon.test.persistent.master.entity.User">
            select * from sys_user
        </select>
    
    </mapper>
    

    由于演示的三个数据库,里面建的表结构都是一样的,这里就不再贴代码了,贴一个包路径结构

    image-20220606214416229

    image-20220606214444285

    4)测试

    以前我还很喜欢写Controller去进行测试,现在直接单元测试,直接进行调试了,简单快捷

    package com.banmoon.test;
    
    import com.banmoon.test.persistent.master.entity.User;
    import com.banmoon.test.persistent.master.mapper.UserMapper;
    import com.banmoon.test.persistent.test01.entity.Test01User;
    import com.banmoon.test.persistent.test01.mapper.Test01UserMapper;
    import com.banmoon.test.persistent.test02.entity.Test02User;
    import com.banmoon.test.persistent.test02.mapper.Test02UserMapper;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.List;
    
    @SpringBootTest
    class ServiceTest {
    
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private Test01UserMapper test01UserMapper;
    
        @Autowired
        private Test02UserMapper test02UserMapper;
    
        @Test
        void insertTest() {
            List<User> list = userMapper.selectList();
            list.forEach(System.out::println);
    
            System.out.println("============");
            List<Test01User> test01UserList = test01UserMapper.selectList();
            test01UserList.forEach(System.out::println);
    
            System.out.println("============");
            List<Test02User> test02UserList = test02UserMapper.selectList();
            test02UserList.forEach(System.out::println);
        }
    
    }
    

    image-20220606220338657

    三、MyBatis-Plus多数据源

    1)自己配置

    首先就是先写入maven依赖,这一点去官网可以查看到

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.1</version>
    </dependency>
    

    至于多数据源的配置,其实和上面差不多的,主要需要将SqlSessionFactory改成MyBatis-plus中的实现就可以了,如下

    package com.banmoon.test.config.datasource;
    
    import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.mybatis.spring.SqlSessionTemplate;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import javax.sql.DataSource;
    
    @Configuration
    @MapperScan(basePackages = {"com.banmoon.test.persistent.master.mapper"},
            sqlSessionFactoryRef = "masterSqlSessionFactory")
    public class MasterDatasourceConfig {
    
        /**
         * 寻找配置文件中的数据源配置信息
         * @return
         */
        @Primary
        @Bean("masterDatasourceProperties")
        @ConfigurationProperties(prefix = "spring.datasource")
        public DataSourceProperties dataSourceProperties(){
            return new DataSourceProperties();
        }
    
        /**
         * 构建数据源
         * @param properties
         * @return
         */
        @Primary
        @Bean("masterDatasource")
        public DataSource dataSource(@Qualifier("masterDatasourceProperties") DataSourceProperties properties){
            DataSource build = DataSourceBuilder.create()
                    .driverClassName(properties.getDriverClassName())
                    .url(properties.getUrl())
                    .username(properties.getUsername())
                    .password(properties.getPassword())
                    .build();
            return build;
        }
    
        /**
         * 构建事务管理器
         * @param dataSource
         * @return
         */
        @Primary
        @Bean(name = "masterTransactionManager")
        public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("masterDatasource") DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    
        /**
         * 构建sqlSession工厂
         * @param dataSource
         * @return
         * @throws Exception
         */
        @Bean(name = "masterSqlSessionFactory")
        public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDatasource") DataSource dataSource) throws Exception {
            // 修改为mp的SqlSessionFactoryBean
            final MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
            sessionFactoryBean.setDataSource(dataSource);
            sessionFactoryBean.setTypeHandlersPackage("com.banmoon.test.persistent.master.entity");
            sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/master/*.xml"));
            return sessionFactoryBean.getObject();
        }
    
        /**
         * 构建sqlSession
         * @param sqlSessionFactory
         * @return
         */
        @Primary
        @Bean(name = "masterSqlSessionTemplate")
        public SqlSessionTemplate sqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    
    }
    

    注意一下,由于只需要引入MyBatis-plus,所以启动类上的排除的类,已经可以不需要了

    package com.banmoon.test;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class TestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(TestApplication.class, args);
        }
    
    }
    

    其他都差不多,是由代码生成器生成的EntityMapper,这里就不贴了,直接翻官网文档吧,里面很详细

    上代码测试一下吧,其实和之前差不多,只是使用到的是MyBatis-plus中的方法

    package com.banmoon.test;
    
    import com.banmoon.test.persistent.master.entity.User;
    import com.banmoon.test.persistent.master.mapper.UserMapper;
    import com.banmoon.test.persistent.test01.entity.Test01User;
    import com.banmoon.test.persistent.test01.mapper.Test01UserMapper;
    import com.banmoon.test.persistent.test02.entity.Test02User;
    import com.banmoon.test.persistent.test02.mapper.Test02UserMapper;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.List;
    
    @SpringBootTest
    class ServiceTest {
    
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private Test01UserMapper test01UserMapper;
    
        @Autowired
        private Test02UserMapper test02UserMapper;
    
        @Test
        void insertTest() {
            List<User> list = userMapper.selectList(null);
            list.forEach(System.out::println);
    
            System.out.println("============");
            List<Test01User> test01UserList = test01UserMapper.selectList(null);
            test01UserList.forEach(System.out::println);
    
            System.out.println("============");
            List<Test02User> test02UserList = test02UserMapper.selectList(null);
            test02UserList.forEach(System.out::println);
        }
    
    }
    

    image-20220607095738103

    2)官方插件

    在MyBatis-Plus中,有一个多数据源启动器,它可以做到以下这些功能

    • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
    • 支持数据库敏感配置信息 加密 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的分布式事务方案。
    • 提供 本地多数据源事务方案。

    具体还是看官网文档吧,已经写的十分详细了,建议使用!!!

    四、最后

    虽然最近暂时没有此类的需求,但提前先记录测试一波,免得到时候手忙脚乱。

    哦对,现在的确很少使用原生的MyBatis了,最近都是在使用MyBatis-plus

    这是一个好框架,十分好用,建议学习,直接使用。

    我是半月,祝你幸福!!!

  • 相关阅读:
    Eclipse Plugin for Hadoop
    Hadoop伪分布模式配置
    Hadoop单机模式配置
    20180711-Java Number类
    20180711-Java分支结构 – if…else/switch
    20180709-Java循环结构
    20180708-Java运算符
    20180708-Java修饰符
    20180708-Java变量类型
    20180705-Java对象和类
  • 原文地址:https://www.cnblogs.com/banmoon/p/16379228.html
Copyright © 2020-2023  润新知