meilin

Preface

目前国内使用较多的持久层(关系型)有,mybatis,data-jpa/hibernate,data-jdbc/jdbc,r2dbc,
基于mybatis的有广泛的用户群,以前面试我说用hibernate和data-jdbc还被几家公司嘲笑了,
个人推荐:r2dbc > data-jdbc > jpa > mybatis,但reactive全套对成员平均水平要求较高,
很多思想一到两年内,大众很难达到一个相对成熟的水平,基于这方面不是很推荐,但必须是趋势;
第二个推荐的是data-jdbc,这个优势是多方面的,比如缓存,关联,领域驱动等,
目前spring data是把新增和修改合并在一起,统一使用save方法,这需要额外处理,
至于jpa是标准,但想要运用得很灵活还是比较难,hibernate封装得比较复杂,
mybatis既然有这么大的用户群体,就不是好不好的问题了,
只是说有些方面已经超出了面向对象编程,如果只是简单的crud,其实选啥都没多少关系,
相反spring-data抽象得比较好,尤其是对entity class,会有审计等等
  • R2dbc Dependency
<dependency>
			<groupId>dev.miku</groupId>
			<artifactId>r2dbc-mysql</artifactId>
			<scope>runtime</scope>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-r2dbc</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

            <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>

Persistence:Generic

public abstract class AbstractEntity implements Serializable,Persistable<String>  {

	private static final long serialVersionUID = -2396899308150035721L;
	
	@Id
	protected String id;
	
	protected String status = Const.STATUS_ENABLE;
	
	@CreatedBy
	protected String creator;

	@CreatedDate
	protected LocalDateTime createTime = LocalDateTime.now();
	
	@LastModifiedBy
	protected String editor;
	
	@LastModifiedDate
	protected LocalDateTime editTime = LocalDateTime.now();
	
	//不推荐使用此属性
	@Transient
	protected Boolean newFlag;
	
	public final String getId() {
		return id;
	}
	public final AbstractEntity setId(String id) {
		this.id = id;
		return this;
	}
	
	public final String getStatus() {
		return status;
	}
	public final AbstractEntity setStatus(String status) {
		this.status = status;
		return this;
	}
	
	public final String getCreator() {
		return creator;
	}
	public final AbstractEntity setCreator(String creator) {
		this.creator = creator;
		return this;
	}
	
	public final LocalDateTime getCreateTime() {
		return createTime;
	}
	public final AbstractEntity setCreateTime(LocalDateTime createTime) {
		this.createTime = createTime;
		return this;
	}
	
	public final String getEditor() {
		return editor;
	}
	public final AbstractEntity setEditor(String editor) {
		this.editor = editor;
		return this;
	}
	
	public final LocalDateTime getEditTime() {
		return editTime;
	}
	public final AbstractEntity setEditTime(LocalDateTime editTime) {
		this.editTime = editTime;
		return this;
	}
	
	public final Boolean getNewFlag() {
		return newFlag;
	}
	public final AbstractEntity setNewFlag(Boolean newFlag) {
		this.newFlag = newFlag;
		return this;
	}
	
	@Override
	public boolean isNew() {
		return Objects.isNull(id) || this.newFlag;
	}
	
}

Persistence:Entity

public class Product extends AbstractEntity {
	
	private static final long serialVersionUID = -3999986688148474587L;
	
	private String productTypeId;
	private String productName;

	public Product() {}
	
	public Product(String id,String productTypeId,String productName) {
		this.id = id;
		this.productTypeId = productTypeId;
		this.productName = productName;
	}
	
	public final String getProductTypeId() {
		return productTypeId;
	}
	public final void setProductTypeId(String productTypeId) {
		this.productTypeId = productTypeId;
	}
	public final String getProductName() {
		return productName;
	}
	public final void setProductName(String productName) {
		this.productName = productName;
	}
	
	@Override
	public int hashCode() {
		return Objects.hash(productName,productTypeId,
			id,status,creator,createTime,editor,editTime);
	}
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Product other = (Product) obj;
		return Objects.equals(id, other.id) 
			&& Objects.equals(productName, other.productName)
			&& Objects.equals(productTypeId, other.productTypeId)
			&& Objects.equals(status, other.status)
			&& Objects.equals(creator, other.creator)
			&& Objects.equals(createTime, other.createTime)
			&& Objects.equals(editor, other.editor)
			&& Objects.equals(editTime, other.editTime);
	}

}

Repository

public interface ProductRepository extends ReactiveCrudRepository<Product, String>{
	
	@Query("select * from product where product_type_id = :productTypeId")
	Flux<Product> getByProductTypeId(String productTypeId);

}

Service Api and RI

public interface ProductService {

	Mono<Product> save(Product product);

	Flux<Product> saveAll(Iterable<Product> productIterable);

	Mono<Product> deleteById(String productId);
	
	Mono<Product> getById(String productId);
	
	Flux<Product> getAll();
	
	Flux<Product> getByProductTypeId(String productTypeId);
	
}

@Service
public class ProductServiceImpl implements ProductService{

	private ProductRepository productRepository;
	
	@Autowired
	public ProductServiceImpl(ProductRepository productRepository) {
		this.productRepository = productRepository;
	}

	@Override
	public Mono<Product> save(Product product) {
		return productRepository.save(product);
	}

	@Override
	public Flux<Product> saveAll(Iterable<Product> productIterable) {
		return productRepository.saveAll(productIterable);
	}

	@Override
	public Mono<Product> deleteById(String productId) {
		return productRepository.findById(productId)
			.flatMap(product -> 
				productRepository.deleteById(product.getId())
					.thenReturn(product)
			);
	}

	@Override
	public Mono<Product> getById(String productId) {
		return productRepository.findById(productId);
	}

	@Override
	public Flux<Product> getAll() {
		return productRepository.findAll();
	}

	@Override
	public Flux<Product> getByProductTypeId(String productTypeId) {
		return productRepository.getByProductTypeId(productTypeId);
	}
	
}

Yaml Configuration

server:
  port: 8080
  servlet:
    context-path: /r2dbc
spring:
  r2dbc:
    url: r2dbc:mysql://localhost:3306
    name: test
    username: root
    password: our cipher code
    properties: 
      locale: zh_US
      useServerPrepareStatement: true
logging:
  level:
    org.springframework.data.r2dbc: debug
  • Test
@DataR2dbcTest
@Import(ProductServiceImpl.class)
public class ProductServiceTest {
	
	private static final Logger logger = LoggerFactory
		.getLogger(MethodHandles.lookup().lookupClass());
	
	private ProductService productService;
	
	@Autowired
	public ProductServiceTest(ProductService productService) {
		this.productService = productService;
	}
	
	@Test
	public void testSave() {
		Product product = createProduct();
		product.setNewFlag(Boolean.TRUE);
		Mono<Product> mp = productService.save(product);
		StepVerifier.create(mp)
			.expectNextMatches(
				p -> StringUtils.hasText(p.getProductName()))
		.verifyComplete();
		logger.info("save test!");
	}

	@Test
	public void testUpdate() {
		Product product = createProduct();
		product.setNewFlag(Boolean.TRUE);
		Mono<Product> mp = productService.save(product);
		Product savedProduct = mp.block(Duration.ofSeconds(3));
		String productName = "update product name";
		savedProduct.setCreator("1");
		savedProduct.setEditor("1");
		savedProduct.setProductName(productName);
		product.setNewFlag(Boolean.FALSE);
		Mono<Product> ump = productService.save(savedProduct);
		StepVerifier.create(ump)
			.expectNextMatches(
				p -> p.getProductName().equals(productName))
		.verifyComplete();
		logger.info("update test!");
	}
	
	@Test
	public void testDelete() {
		Product product = createProduct();
		product.setNewFlag(Boolean.TRUE);
		Mono<Product> mp = productService.save(product)
			.flatMap(p -> productService.deleteById(product.getId()));
		StepVerifier.create(mp)
			.expectNextMatches (
				p -> p.getProductName().equals("elf"))
		.verifyComplete();
		logger.info("delete test!");
	}
	
	@Test
	public void testRetrieve() {
		Product product = createProduct();
		product.setNewFlag(Boolean.TRUE);
		Mono<Product> mp = productService.save(product)
				.flatMap(p -> productService.getById(product.getId()));
		StepVerifier.create(mp)
		.expectNextMatches (
				p -> p.getProductName().equals("elf"))
		.verifyComplete();
		logger.info("retrieve test!");
	}
	
	private Product createProduct() {
		String uuid = UUID.randomUUID().toString();
		return new Product(uuid.substring(0,20), "1","elf");
	}
	
}

Tbd...

分类:

技术点:

相关文章:

  • 2021-08-15
  • 2021-04-01
  • 2020-12-22
  • 2018-05-19
  • 2021-08-10
  • 2021-11-21
  • 2021-09-24
  • 2021-09-03
猜你喜欢
  • 2019-11-04
  • 2021-06-26
  • 2021-03-09
  • 2021-08-14
  • 2021-08-06
  • 2021-05-24
  • 2021-09-15
相关资源
相似解决方案