ITPub博客

首页 > 数据库 > > 「Java」 - SpringBoot & MongoDB

「Java」 - SpringBoot & MongoDB

作者:浪花小雨滴 时间:2020-05-12 11:49:03 0 删除 编辑

MongoDB是目前热门的非关系数据库,广泛的应用于国内外的互联网公司。

一、MongoDB简介

MongoDB(来自于英文单词Humongous,含义为「庞大」),可以应用于各种规模的企业、各个行业以及各类应用程序的开源数据库,基于分布式文件存储的数据库。C++语言编写,旨在为web应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似Json的bjson格式,因此可以存储比较复杂的数据类型。MongoDB最大的特点是支持的查询语言非常强大,语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

传统的关系数据库一般由数据库(DataBase)、表(Table)、记录(Record)三个层次概念组成;MongoDB是由数据库(DataBase)、集合(Collection)、文档对象(Document)三个层次组成。MongoDB对应关系型数据库里的表,但是集合中没有列、行和关系概念。

MongoDB中的一条记录就是一个文档,是一个数据结构,由字段和值对组成。MongoDB文档与Json对象类似。字段的值有可能包括其他文档、数组及文档数组。MongoDB支持几乎所有主流操作系统,并提供了Java、Python、PHP及C++等编程语言的驱动程序。

MongoDB适合对大量或者无固定格式的数据进行存储,如日志、缓存等。对事物支持较弱,不适用复杂的多文档(多表)的级联查询。

二、MongoDB安装(单点)

订单系统使用了MongoDB,刚好可以通过Spring Boot进行学习,确认了订单系统使用的版本是3.4.2,官网已经是4.x版本,这里还是跟公司环境保持一致。

Download:mongodb.org/dl/linux/x8

# 下载解压二进制文件
wget http://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.4.2.tgz
tar -vxzf mongodb-linux-x86_64-rhel62-3.4.2.tgz
mv mongodb-linux-x86_64-rhel62-3.4.2 /usr/local/mongodb-3.4.2

# 创建data和log目录
mkdir -p /data01/mongodata /data01/mongolog

# 增加环境变量
vim /etc/profile
    export PATH=/usr/local/mongodb-3.4.2/bin:$PATH
source /etc/profile 

# 增加conf配置
vim mongo.conf
    bind_ip = 10.255.242.129
    port = 27017
    #fork = true

    ## MongoDB Data path
    dbpath=/data01/mongodata

    ## Log path
    logpath=/data01/mongolog/mongodb.log
 
    ## is log Rotate mongoDB 3.0
    logappend = true
    #logRotate = true

    ## is Open journal log
    journal = true

    ## use small files for develop
    smallfiles = true

# 设置启动脚本
vim mongo.sh
    #!/bin/bash
    mongod -fork -config /usr/local/mongodb-3.4.2/mongo.conf
chmod 755 mongo.sh

# 启动MongoDB
sh mongo.sh

通过进程、telnet、以及日志,都能确认MongoDB已经成功启动。

关于MongoDB集群、配置、运维等总结,以后有机会再进行。这里还是安装后,使用Spring Boot进行操作。

三、spring-boot-starter-data-mongodb

Spring Data是Spring为了简化数据库操作而封装的一个组件包,提供了操作多种数据库的支持,API简洁、调用方便。

spring-boot-starter-data-mongodb是Spring Data的一个子模块。目标是为MongoDB提供一个相近的、一致的、基于Spring的编程模型。spring-boot-starter-data-mongodb核心功能是映射POJO到MongoDB的DBCollection中的文档,并且提供Repository风格数据访问层。除继承Spring Data的通用功能外,针对MongoDB的特性开发了很多定制的功能,使得Spring Boot操作MongoDB更加简便。

MongoDB有两种比较流行的使用方法,一种是直接将MongoTemplate直接注入到Dao中使用;另一种是继承MongoRepository,MongoRepository内置了很多方法可直接使用(类似JPA的Repository)。

A、MongoTemplate使用

1、相关依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

2、application.properties

# spring.data.mongodb.uri=mongodb://name:pass@localhost:27017/test
spring.data.mongodb.uri=mongodb://10.255.242.129:27017/test

多IP集群配置:

spring.data.mongodb.uri=mongodb://user:pwd@ip1:port1,ip2:port2/database

PS:MongoDB 3.0,Java驱动不支持spring.data.mongodb.host和spring.data.mongodb.port,需要在spring.data.mongodb.uri提供全部的配置信息。

3、创建数据实体

@Getter
@Setter
public class User
{
    private Long id;
    private String username;
    private String password;
}

4、Dao层增删改查

public interface UserDao
{
    void save(User user);
    
    User findUserByUsername(String username);
    
    long update(User user);
    
    void deleteById(Long id);
}

@Service
public class UserDaoImpl implements UserDao
{
    @Autowired
    private MongoTemplate mongoTemplate;
    
    @Override
    public void save(User user)
    {
        mongoTemplate.save(user);
    }
    
    @Override
    public User findUserByUsername(String username)
    {
        Query query = new Query(Criteria.where("username").is(username));
        User user = mongoTemplate.findOne(query, User.class);
        return user;
    }
    
    @Override
    public long update(User user)
    {
        Query query = new Query(Criteria.where("id").is(user.getId()));
        Update update = new Update().set("username", user.getUsername()).set("password", user.getPassword());
        
        // 更新查询返回结果集的第一条
        UpdateResult result = mongoTemplate.updateFirst(query, update, User.class);
        
        // 更新查询返回结果集的所有
        // mongoTemplate.updateMulti(query,update,UserEntity.class);
        if (result != null)
        {
            return result.getMatchedCount();
        }
        else
        {
            return ;
        }
    }
    
    @Override
    public void deleteById(Long id)
    {
        Query query = new Query(Criteria.where("id").is(id));
        mongoTemplate.remove(query, User.class);
    }
}

5、测试

@Slf4j
public class UserDaoTest extends MongodbTemplateApplicationTests
{
    @Autowired
    private UserDao userDao;
    
    @Test
    public void save()
    {
        User user = new User();
        user.setId(1L);
        user.setUsername("isisiwish");
        user.setPassword("pass");
        userDao.save(user);
    }
    
    @Test
    public void findUserByUsername()
    {
        User user = userDao.findUserByUsername("isisiwish");
        log.info("{}", JSON.toJSONString(user));
    }
    
    @Test
    public void update()
    {
        User user = new User();
        user.setId(1L);
        user.setUsername("isisiwish");
        user.setPassword("password");
        userDao.update(user);
    }
    
    @Test
    public void deleteById()
    {
        userDao.deleteById(1L);
    }
}

6、查看验证结果

使用工具Studio 3T来连接后直接图形化展示查看。

也可以登录服务器用命令来查看:

  • 登录MongoDB Server:mongo -host localhost -port 20000
  • 切换test库:use test
  • 查询user集合数据:db.user.find()

B、MongoRepository的使用

MongoRepository的使用方式和之前项目结构类似,只有Dao层的代码有所变化。

1、Repository

新建UserRepository需要继承MongoRepository,这样就可直接使用MongoRepository的内置方法。对于分页需要在UserRepository加入一个空方法,不需要自己实现。

public interface UserRepository extends MongoRepository<User, Long>
{
    User findByUsername(String username);

    @Override
    Page<User> findAll(Pageable pageable);
}

2、测试

UserRepository已经自动实现了常用的数据库操作,不用像使用MongoTemplate那样需要手动来实现。

@Slf4j
public class UserRepositoryTest extends MongodbRepositoryApplicationTests
{
    @Autowired
    private UserRepository userRepository;
    
    @Test
    public void save()
    {
        User user = new User();
        user.setId(2L);
        user.setUsername("isisiwish");
        user.setPassword("pass");
        userRepository.save(user);
    }
    
    @Test
    public void findUserByUsername()
    {
        User user = userRepository.findByUsername("isisiwish");
        log.info("{}", JSON.toJSONString(user));
    }
    
    @Test
    public void update()
    {
        User user = new User();
        user.setId(2L);
        user.setUsername("isisiwish");
        user.setPassword("password");
        userRepository.save(user);
    }
    
    @Test
    public void deleteById()
    {
        userRepository.deleteById(2L);
    }
    
    @Test
    public void testPage()
    {
        for (long i = ; i < 100; i++)
        {
            User user = new User();
            user.setId(i);
            user.setUsername("isisiwish:" + i);
            user.setPassword("pass");
            userRepository.save(user);
        }
        
        Sort sort = new Sort(Sort.Direction.DESC, "id");
        Pageable pageable = PageRequest.of(, 5, sort);
        Page<User> page = userRepository.findAll(pageable);
        List<User> userList = page.getContent();
        for (User user : userList)
        {
            log.info("{}", JSON.toJSONString(user));
        }
    }
}

Repository的方式和Spring Boot JPA非常相似,spring-boot-starter-data-mongodb和spring-boot-starter-data-jpa都来自于Spring Data家族,实现原理基本一致,因此使用Repository完全可以参考JPA用法。

C、MongoDB多数据源

1、添加配置

首先在配置文件添加不同的数据源。

mongodb.primary.uri=mongodb://192.168.0.1:27017
mongodb.primary.database=primary

mongodb.secondary.uri=mongodb://192.168.0.1:27017
mongodb.secondary.database=secondary

2、配置两个库的数据源

封装读取以mongodb开头的两个配置文件。

@Getter
@Setter
@ConfigurationProperties(prefix = "mongodb")
public class MultipleMongoProperties
{
    private MongoProperties primary = new MongoProperties();
    private MongoProperties secondary = new MongoProperties();
}

配置不同包路径下使用不同的数据源。

@Configuration
@EnableConfigurationProperties(MultipleMongoProperties.class)
@EnableMongoRepositories(basePackages = "top.cfish.mongodbmulti.repository.primary", mongoTemplateRef = "primaryMongoTemplate")
public class PrimaryMongoConfig
{}

@Configuration
@EnableConfigurationProperties(MultipleMongoProperties.class)
@EnableMongoRepositories(basePackages = "top.cfish.mongodbmulti.repository.secondary", mongoTemplateRef = "secondaryMongoTemplate")
public class SecondaryMongoConfig
{
}

读取配置信息封装为Properties,根据Properties信息构建Factory,再由Factory构建出最后需要使用的MongoTemplate,MongoTemplate在根据包路径配置注入到对应的包下。

@Configuration
public class MultipleMongoConfig
{
    @Autowired
    private MultipleMongoProperties mongoProperties;
    
    @Primary
    @Bean(name = "primaryMongoTemplate")
    public MongoTemplate primaryMongoTemplate() throws Exception
    {
        return new MongoTemplate(primaryFactory(this.mongoProperties.getPrimary()));
    }
    
    @Bean
    @Qualifier("secondaryMongoTemplate")
    public MongoTemplate secondaryMongoTemplate() throws Exception
    {
        return new MongoTemplate(secondaryFactory(this.mongoProperties.getSecondary()));
    }
    
    @Bean
    @Primary
    public MongoDbFactory primaryFactory(MongoProperties mongo) throws Exception
    {
        MongoClient client = new MongoClient(new MongoClientURI(mongoProperties.getPrimary().getUri()));
        return new SimpleMongoDbFactory(client, mongoProperties.getPrimary().getDatabase());
    }
    
    @Bean
    public MongoDbFactory secondaryFactory(MongoProperties mongo) throws Exception
    {
        MongoClient client = new MongoClient(new MongoClientURI(mongoProperties.getSecondary().getUri()));
        return new SimpleMongoDbFactory(client, mongoProperties.getSecondary().getDatabase());
    }
}

3、创建对象和两个库分别对应的Repository

@Getter
@Setter
@AllArgsConstructor
public class User
{
    private Long id;
    private String username;
    private String password;
}

public interface UserPrimaryRepository extends MongoRepository<User, Long>
{
}

public interface UserSecondaryRepository extends MongoRepository<User, Long>
{
}

4、测试

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class MongodbMultiApplicationTests
{
    @Autowired
    UserPrimaryRepository userPrimaryRepository;
    
    @Autowired
    UserSecondaryRepository userSecondaryRepository;
    
    @Test
    public void TestMulti()
    {
        this.userPrimaryRepository.save(new User(1L,"isisiwish-frist", "123456"));
        this.userSecondaryRepository.save(new User(1L,"isisiwish-sec", "654321"));
        
        List<User> primaries = this.userPrimaryRepository.findAll();
        for (User primary : primaries)
        {
            log.info("{}", JSON.toJSONString(primary));
        }
        
        List<User> secondaries = this.userSecondaryRepository.findAll();
        for (User secondary : secondaries)
        {
            log.info("{}", JSON.toJSONString(secondary));
        }
    }
}

输出内容如下:

2019-05-17 14:41:36.153  INFO 44440 --- {"id":1,"password":"123456","username":"isisiwish-frist"}
2019-05-17 14:41:36.182  INFO 44440 --- {"id":1,"password":"654321","username":"isisiwish-sec"}

使用Studio 3T分别查看两个库的数据,均已经有对应的user 对象,多数据源使用测试成功。

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31537575/viewspace-3127657/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2018-05-16

  • 博文量
    4259
  • 访问量
    40005