Spring-Data-MongoDB
Spring Data MongoDB 使用笔记
SpringBoot整合MongoDB
MongoTemplate方式
SpringBoot 集成 Spring Data Mongodb 操作 MongoDB 详解
http://www.mydlq.club/article/85/
MongoRepository方式
spring-data-mongodb 中的实体映射是通过 MongoMappingConverter 这个类实现的。它可以通过注释把 java 类转换为 mongodb 的文档。
它有以下几种注解:
@Id 文档的唯一标识,在mongodb中为ObjectId,它是唯一的,通过时间戳+机器标识+进程ID+自增计数器(确保同一秒内产生的Id不会冲突)构成。
@Document 把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。@Document(collection=“mongodb”) mongodb对应表
@DBRef 声明类似于关系数据库的关联关系。ps:暂不支持级联的保存功能,当你在本实例中修改了DERef对象里面的值时,单独保存本实例并不能保存DERef引用的对象,它要另外保存。
@Indexed 声明该字段需要索引,建索引可以大大的提高查询效率。
@CompoundIndex 复合索引的声明,建复合索引可以有效地提高多字段的查询效率。
@GeoSpatialIndexed 声明该字段为地理信息的索引。
@Transient 映射忽略的字段,该字段不会保存到mongodb。
@PersistenceConstructor 声明构造函数,作用是把从数据库取出的数据实例化为对象。该构造函数传入的值为从DBObject中取出的数据
Mongo 3.0 Java driver不支持通过spring.data.mongodb.host配置连接
错误:
通过下面这三个参数配置 mongo 连接
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=app1
SpringBoot 启动时报错
2021-05-27 18:47:58.395 [cluster-ClusterId{value='60af78debbf59a7c9ef01bed', description='null'}-localhost:27017] INFO org.mongodb.driver.cluster - Exception in monitor thread while connecting to server localhost:27017
com.mongodb.MongoSocketOpenException: Exception opening socket
at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:70)
at com.mongodb.internal.connection.InternalStreamConnection.open(InternalStreamConnection.java:128)
at com.mongodb.internal.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:117)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at com.mongodb.internal.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:64)
at com.mongodb.internal.connection.SocketStream.initializeSocket(SocketStream.java:79)
at com.mongodb.internal.connection.SocketStream.open(SocketStream.java:65
原因:
Mongo 3.0 Java driver 不支持通过 spring.data.mongodb.host 和 spring.data.mongodb.port 配置连接,必须使用 spring.data.mongodb.uri 配置连接参数。
If you use the Mongo 3.0 Java driver, spring.data.mongodb.host and spring.data.mongodb.port are not supported. In such cases, spring.data.mongodb.uri should be used to provide all of the configuration.
31.2.1 Connecting to a MongoDB Database
https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/boot-features-nosql.html
解决:
改为通过 uri 配置连接则可以正常启动
spring.data.mongodb.uri=mongodb://localhost:27017/test
Spring Data MongoDB可自动创建数据库
连接中配置的 MongoDB 数据库不存在也没关系,Spring Data MongoDB 可自动创建 DB, collection 当然更能自动创建了。
spring.data.mongodb.uri=mongodb://localhost:27017/test
Spring Data 连接 MongoDB开启认证
MongoDB 连接串格式:
mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
注意:password 中的 @ 等符号需要做 url 编码,比如 @ 要替换为 %40
spring:
data:
mongodb:
uri: mongodb://user:passwd@127.0.0.1:8017/dbname?authSource=admin
SpringBoot同时集成SpringDataJpa+MongoDB
项目中要同时使用 MySQL 和 MongoDB, 使用 Spring Data 统一对接,整合到一个统一的 persistent 持久化模块中,对其他模块只暴露 Service 层,屏蔽底层 Jpa 和 Mongo 差异。
定义Jpa和Mongo实体
这里我将 Jpa 和 Mongo 的实体类放在同一包下了。
Jpa 实体:
@Data
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "rules")
public class RulesDO extends DefaultDateDO {
private String name;
@ColumnDefault("'enabled'")
private String status;
}
Mongo 实体:
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "msg")
public class MessageDO {
@Id
private String id;
private String name;
}
Jpa和Mongo的Repository
实际使用中,还会再包一层 Service 层,对外都通过 Service 层访问,这里略过,直接使用 Repository
这里我将 Jpa 和 Mongo 的 Repository 接口放在同一包下了。
Jpa 的 repository
@Repository
public interface RulesRepository extends JpaRepository<RulesDO, Long> {
}
Mongo 的 repository
@Repository
public interface MessageRepository extends MongoRepository<MessageDO, String> {
}
Jpa和Mongo配置类
Jpa 配置类, PersistenceRepositoryPackage 是 Repository 所在包的一个标记接口,也可以直接通过 basePackages 属性配置包路径。
@Configuration
@EnableJpaAuditing
@EnableJpaRepositories(basePackageClasses = {PersistenceRepositoryPackage.class})
public class JpaConfiguration {
}
Mongo 配置类
@Configuration
@EnableMongoRepositories(basePackageClasses = {PersistenceRepositoryPackage.class})
public class MongoConfiguration {
}
总的持久化配置
PersistenceDOPackage 是 Jpa 和 Mongo 实体类所在包的一个标记接口,也可以直接通过 basePackages 属性配置包路径。
@Configuration
@ComponentScan
@EntityScan(basePackageClasses = {PersistenceDOPackage.class})
@Import({JpaConfiguration.class, MongoConfiguration.class})
public class PersistenceConfiguration {
}
单测集成H2内存数据库及EmbedMongo
maven引入依赖
引入maven依赖,为了使用内存数据库需要引入 h2, 为了使用内存mongo需要引入 de.flapdoodle.embed.mongo 和 embedmongo-spring
SpringBoot 版本是 2.2.6.RELEASE, 默认是 JUnit5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>1.50.5</version>
</dependency>
<dependency>
<groupId>cz.jirutka.spring</groupId>
<artifactId>embedmongo-spring</artifactId>
<version>RELEASE</version>
</dependency>
<dependencies>
<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>
配置apt-maven-plugin插件同时支持jpa和mongo
apt-maven-plugin 是 QueryDSL 用来生成查询Q类的插件,需要改下配置来同时支持 Jpa 和 Mongo
<build>
<plugins>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<executions>
<execution>
<id>jpa</id>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
<execution>
<id>mongo</id>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>
org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
</processor>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
单测yml配置
debug: true
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
username: sa
jpa:
database: h2
show-sql: true
properties:
hibernate:
format_sql: true
BaseTest单测基类
JUnit5 中不再使用 @RunWith(SpringRunner.class)
替换为 @ExtendWith(SpringExtension.class)
@SpringBootTest
@ExtendWith(SpringExtension.class)
public abstract class BaseTest {
@SpringBootApplication
@Import(PersistenceConfiguration.class)
public static class TestApplication {
}
}
Mongo单测
@Slf4j
public class MessageTest extends BaseTest {
@Autowired
private MessageRepository messageRepository;
@Test
public void testSaveAndFind() {
MessageDO messageDO = MessageDO.builder().name("name").build();
messageRepository.save(messageDO);
log.info(JsonMappers.NonEmpty.toPrettyJson(messageDO));
Assertions.assertNotNull(messageDO.getId());
List<MessageDO> res = Lists.newArrayList(messageRepository.findAll(QMessageDO.messageDO.name.eq("name")));
log.info(JsonMappers.NonEmpty.toPrettyJson(res));
Assertions.assertTrue(res.size() >= 1);
}
}
Jpa单测
Jpa 的测试可以分为两种方式:
1、加 @DataJpaTest
注解,不启动 Spring 上下文,只关注Jpa的测试,可以注入 TestEntityManager 使用。
2、使用传统的 @SpringBootTest
启动 Spring 上下文,注入 EntityManager 使用。
两种方式都可以使用 @AutoConfigureTestDatabase
注解,不需要准备 data.sql 初始化脚本,会自动根据 Jpa 实体初始化 h2 数据库。
Jpa单测基类
//@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class BaseJpaTest extends BaseTest {
@Autowired
private EntityManager entityManager;
@BeforeEach
public void setUp() {
RulesDO rulesDO = new RulesDO();
rulesDO.setName("测试");
entityManager.persist(rulesDO);
}
}
Jpa 单测类:
@Slf4j
@Transactional
public class RulesTest extends BaseJpaTest {
@Autowired
private RulesRepository rulesRepository;
@Test
public void testSaveAndFind() {
RulesDO rulesDO = RulesDO.builder().name("测试").build();
rulesRepository.save(rulesDO);
Assertions.assertNotNull(rulesDO.getId());
List<RulesDO> rulesDOList = Lists.newArrayList(rulesRepository.findAll(QRulesDO.rulesDO.name.eq("测试")));
Assertions.assertTrue(rulesDOList.size() >= 1);
}
}
Spring Boot with Embedded MongoDB
https://springframework.guru/spring-boot-with-embedded-mongodb/
Spring Boot Integration Testing with Embedded MongoDB
https://www.baeldung.com/spring-boot-embedded-mongodb
Spring Data设置MongoDB TTL索引(过期时间)
给索引注解 @Indexed
加 expireAfterSeconds 参数来设置过期时间。
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "msg")
public class MessageDO {
@Id
private String id;
// code
@Indexed(name = "msgCode")
private String msgCode;
// 过期时间
@Indexed(name = "expireAt", expireAfterSeconds = 0)
private Date expireAt;
@CreatedDate
private Date createdDate;
@LastModifiedDate
private Date lastModifiedDate;
}
运行时有如下提示:
2021-05-31 17:47:24.761 [main] WARN o.s.d.m.c.i.MongoPersistentEntityIndexCreator.warnOnce:72 - Automatic index creation will be disabled by default as of Spring Data MongoDB 3.x.
Please use 'MongoMappingContext#setAutoIndexCreation(boolean)' or override 'MongoConfigurationSupport#autoIndexCreation()' to be explicit.
However, we recommend setting up indices manually in an application ready block. You may use index derivation there as well.
> -----------------------------------------------------------------------------------------
> @EventListener(ApplicationReadyEvent.class)
> public void initIndicesAfterStartup() {
>
> IndexOperations indexOps = mongoTemplate.indexOps(DomainType.class);
>
> IndexResolver resolver = new MongoPersistentEntityIndexResolver(mongoMappingContext);
> resolver.resolveIndexFor(DomainType.class).forEach(indexOps::ensureIndex);
> }
> -----------------------------------------------------------------------------------------
Spring Data MongoDB 审计
Spring Data MongoDB 和 Jpa 类似,也支持在字段或者方法上进行注解 @CreateDate @CreatedBy @LastModifiedDate @LastModifiedBy
@CreateDate 表示该字段为创建时间时间字段,在这个实体被 insert 的时候,会设置默认值
@CreatedBy 表示该字段为创建人,在这个实体被 insert 的时候,会设置值。
指定 @EnableMongoAuditing
来启用JPA审计:
@Configuration
@EnableMongoAuditing
public class MongoConfiguration {
}
上一篇 MapStruct
页面信息
location:
protocol
: host
: hostname
: origin
: pathname
: href
: document:
referrer
: navigator:
platform
: userAgent
: