如何在 Spring Boot 中配置多个数据源、实体管理器、事务管理器

x33g5p2x  于2021-10-16 转载在 Spring  
字(21.7k)|赞(0)|评价(0)|浏览(594)

早些时候,我们探索了使用 Spring Data JPA 和 Hibernate 加入不相关实体并将结果映射到 POJO 的各种方法。在本文中,我们将在 Spring Boot 应用程序中配置多个数据库、实体管理器、事务管理器和 Hikari 连接池。

项目结构

这就是我们的项目结构的样子。 模型和存储库包是特定于数据库的。这样我们就可以在特定于数据库的配置类中指定相应的包,用于扫描实体和存储库。多个数据库的实体和存储库不应放在同一个包中。

依赖

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.javachinna</groupId>
	<artifactId>multiple-datasources</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>multiple-datasources</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

配置数据源和连接池

假设我们有 2 个不同的数据库,即 PRIME 和 PRODUCT。 PRIME 是用于用户管理的主数据库,而 PRODUCT 用于产品管理。现在让我们在 Spring Boot 应用程序中配置这两个数据库。此外,我们将配置 Hikari CP,因为它是 Spring Boot 2.x 使用的默认连接池

配置应用程序属性

application.properties
### Prime Database Details
app.datasource.prime.url=jdbc:mysql://localhost:3306/prime?createDatabaseIfNotExist=true
app.datasource.prime.username=root
app.datasource.prime.password=secret
app.datasource.prime.driver-class-name=com.mysql.cj.jdbc.Driver
### Prime Database Connection Pool Details
app.datasource.prime.hikari.idle-timeout=10000
app.datasource.prime.hikari.maximum-pool-size=10
app.datasource.prime.hikari.minimum-idle=5
app.datasource.prime.hikari.pool-name=PrimeHikariPool

### Product Database Details
app.datasource.product.url=jdbc:mysql://localhost:3306/product?createDatabaseIfNotExist=true
app.datasource.product.username=root
app.datasource.product.password=secret
app.datasource.product.driver-class-name=com.mysql.cj.jdbc.Driver
### Product Database Connection Pool Details
app.datasource.product.hikari.idle-timeout=10000
app.datasource.product.hikari.maximum-pool-size=10
app.datasource.product.hikari.minimum-idle=5
app.datasource.product.hikari.pool-name=ProductHikariPool

# Hibernate props
hibernate.hbm2ddl.auto=create
hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

配置主数据库

PrimeDataSourceConfiguration.java

@Primary 注释表示当多个候选者有资格自动装配单值依赖项时,应该优先考虑一个 bean。如果候选中恰好存在一个“主要”bean,它将是自动装配的值。简单来说,它用于将 bean 标记为默认 bean。当定义了多个相同类型的 bean 并且我们想在不指定其名称的情况下注入 bean 时,这很有用。

package com.javachinna.config;

import java.util.HashMap;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import com.zaxxer.hikari.HikariDataSource;

@Configuration
@EnableJpaRepositories(basePackages = "com.javachinna.repo.prime", entityManagerFactoryRef = "primeEntityManager", transactionManagerRef = "primeTransactionManager")
public class PrimeDataSourceConfiguration {

	@Autowired
	Environment env;

	@Bean
	@Primary
	@ConfigurationProperties(prefix = "app.datasource.prime")
	public DataSourceProperties primeDataSourceProperties() {
		return new DataSourceProperties();
	}

	@Bean
	@Primary
	public DataSource primeDataSource() {
		return primeDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
	}

	@Bean
	@Primary
	public LocalContainerEntityManagerFactoryBean primeEntityManager() {
		LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
		em.setDataSource(primeDataSource());
		em.setPackagesToScan("com.javachinna.model.prime");
		HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
		em.setJpaVendorAdapter(vendorAdapter);
		HashMap<String, Object> properties = new HashMap<>();
		properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
		properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
		em.setJpaPropertyMap(properties);
		return em;
	}

	@Bean
	@Primary
	public PlatformTransactionManager primeTransactionManager() {
		JpaTransactionManager transactionManager = new JpaTransactionManager();
		transactionManager.setEntityManagerFactory(primeEntityManager().getObject());
		return transactionManager;
	}
}

请注意,我们分别指定了 com.javachinna.repo.primecom.javachinna.model.prime 作为扫描 JPA 存储库和 PRIME 数据库实体的包名称。

配置辅助数据库

ProductDataSourceConfiguration.java
package com.javachinna.config;

import java.util.HashMap;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;

import com.zaxxer.hikari.HikariDataSource;

@Configuration
@EnableJpaRepositories(basePackages = "com.javachinna.repo.product", entityManagerFactoryRef = "productEntityManager", transactionManagerRef = "productTransactionManager")
public class ProductDataSourceConfiguration {

	@Autowired
	Environment env;

	@Bean
	@ConfigurationProperties(prefix = "app.datasource.product")
	public DataSourceProperties productDataSourceProperties() {
		return new DataSourceProperties();
	}

	@Bean
	public DataSource productDataSource() {
		return productDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class).build();
	}

	@Bean
	public LocalContainerEntityManagerFactoryBean productEntityManager() {
		LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
		em.setDataSource(productDataSource());
		em.setPackagesToScan("com.javachinna.model.product");
		HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
		em.setJpaVendorAdapter(vendorAdapter);
		HashMap<String, Object> properties = new HashMap<>();
		properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
		properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
		em.setJpaPropertyMap(properties);
		return em;
	}

	@Bean
	public PlatformTransactionManager productTransactionManager() {
		JpaTransactionManager transactionManager = new JpaTransactionManager();
		transactionManager.setEntityManagerFactory(productEntityManager().getObject());
		return transactionManager;
	}
}

请注意,我们已分别指定 com.javachinna.repo.productcom.javachinna.model.product 作为用于扫描 JPA 存储库和 PRODUCT 数据库实体的包名称。

创建 JPA 实体和 POJO

UserInfo.java

这个 POJO 类用于从 prime 数据库中的本机查询结果集中映射用户信息。

package com.javachinna.model.prime;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserInfo {
	private String id;
	private String name;
}

#####角色.java

此实体映射到 prime 数据库中的 role

package com.javachinna.model.prime;

import java.io.Serializable;
import java.util.Objects;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

/**
 * The persistent class for the role database table.
 * 
 */
@Entity
@Getter
@Setter
@NoArgsConstructor
public class Role implements Serializable {
	private static final long serialVersionUID = 1L;
	public static final String USER = "USER";
	public static final String ADMIN = "ADMIN";
	public static final String ROLE_USER = "ROLE_USER";
	public static final String ROLE_ADMIN = "ROLE_ADMIN";

	@Id
	@Column(name = "ROLE_ID")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int roleId;

	private String name;

	// bi-directional many-to-many association to User
	@ManyToMany(mappedBy = "roles")
	private Set<User> users;

	public Role(String name) {
		this.name = name;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		return Objects.equals(name, ((Role) obj).getName());
	}

	@Override
	public String toString() {
		final StringBuilder builder = new StringBuilder();
		builder.append("Role [name=").append(name).append("]").append("[id=").append(roleId).append("]");
		return builder.toString();
	}
}
User.java

该实体映射到 prime 数据库中的 user

package com.javachinna.model.prime;

import java.util.Set;

import javax.persistence.Column;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.SqlResultSetMapping;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Entity
@NoArgsConstructor
@SqlResultSetMapping(name = "UserInfoMapping", classes = @ConstructorResult(targetClass = UserInfo.class, columns = {@ColumnResult(name = "user_id", type = String.class),
		@ColumnResult(name = "username", type = String.class)}))
public class User {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "USER_ID")
	private Long id;
	private String username;
	private String password;
	// bi-directional many-to-many association to Role
	@ManyToMany
	@JoinTable(name = "user_role", joinColumns = {@JoinColumn(name = "USER_ID")}, inverseJoinColumns = {@JoinColumn(name = "ROLE_ID")})
	private Set<Role> roles;

	/**
	 * @param username
	 * @param password
	 */
	public User(String username, String password, Set<Role> roles) {
		this.username = username;
		this.password = password;
		this.roles = roles;
	}
}
ProductInfo.java

这个 POJO 类用于从 product 数据库中的本机 SQL 查询结果集中映射产品信息。

package com.javachinna.model.product;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductInfo {
	private String id;
	private String name;
	private String price;
}
Product.java

该实体映射到 product 数据库中的 product

package com.javachinna.model.product;

import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SqlResultSetMapping;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Entity
@NoArgsConstructor
@SqlResultSetMapping(name = "ProductInfoMapping", classes = @ConstructorResult(targetClass = ProductInfo.class, columns = {@ColumnResult(name = "id", type = String.class),
		@ColumnResult(name = "name", type = String.class), @ColumnResult(name = "price", type = String.class)}))
public class Product {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;
	private String name;
	private String price;
	/**
	 * @param name
	 * @param price
	 */
	public Product(String name, String price) {
		this.name = name;
		this.price = price;
	}

}

创建 Spring Data Repository 和 DAO 类

我们将分别为 User 和 Role 表创建 User 和 Role 存储库,以演示对一个数据库中多个表的 CRUD 操作。

RoleRepository.java
package com.javachinna.repo.prime;

import org.springframework.data.jpa.repository.JpaRepository;

import com.javachinna.model.prime.Role;

public interface RoleRepository extends JpaRepository<Role, Long> {
	Role findByName(String name);
}
UserRepository.java
package com.javachinna.repo.prime;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.javachinna.model.prime.User;

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

	User findByUsername(String userName);
}
UserInfoRepository.java

这只是一个 DAO 类,用于演示如何使用 @Qualifier 注释在不指定名称 primeEntityManager 的情况下注入主实体管理器。

package com.javachinna.repo.prime;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.hibernate.procedure.ProcedureOutputs;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.javachinna.model.prime.UserInfo;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Repository
@Transactional
public class UserInfoRepository {

	@PersistenceContext
	private EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public List<UserInfo> getUerInfo() {
		List<UserInfo> list = new ArrayList<>();
		Query query = entityManager.createNativeQuery("select user_id, username from user", "UserInfoMapping");
		try {
			// Execute query
			list = query.getResultList();
		} catch (Exception e) {
			log.error("Error while querying the db", e);
		} finally {
			try {
				query.unwrap(ProcedureOutputs.class).release();
			} catch (Exception e) {
			}
		}
		return list;
	}
}

请注意,我们使用 @Transactional 注释了这个类,而没有指定事务管理器名称。这意味着默认情况下将使用主事务管理器。

ProductRepository.java

这是用于辅助数据库中的产品 CRUD 操作的 JPA 存储库类。

@Transactional 表示执行更新查询需要一个事务。这里我们不需要显式指定事务管理器,因为我们已经在 ProductDataSourceConfiguration 类中使用 @EnableJpaRepositories 注释指定了 productTransactionManager

@Modifying 注释表明查询方法应该被视为修改查询,因为它改变了它需要执行的方式。只有在通过 @Query 注释定义的查询方法上使用时才考虑此注释。

package com.javachinna.repo.product;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.javachinna.model.product.Product;

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {

	@Transactional
	@Modifying
	@Query("update Product set name=:name where id=:id")
	void updateProduct(String name, Long id);
}
ProductInfoRepository.java

这只是一个 DAO 类,用于演示如何使用 @Qualifier 注释自动连接辅助实体管理器并用于查询辅助数据库。

package com.javachinna.repo.product;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.hibernate.procedure.ProcedureOutputs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.javachinna.model.product.ProductInfo;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Repository
public class ProductInfoRepository {

	@Autowired
	@Qualifier("productEntityManager")
	private EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public List<ProductInfo> getProductInfo() {
		List<ProductInfo> list = new ArrayList<>();
		Query query = entityManager.createNativeQuery("select id, name, price from product", "ProductInfoMapping");
		try {
			// Execute query
			list = query.getResultList();
		} catch (Exception e) {
			log.error("Error while querying the db", e);
		} finally {
			try {
				query.unwrap(ProcedureOutputs.class).release();
			} catch (Exception e) {
			}
		}
		return list;
	}

	@Transactional("productTransactionManager")
	public void updateProductInfo(String name, Long id) {
		Query query = entityManager.createQuery("update Product set name=:name where id=:id");
		try {
			// Execute query
			query.setParameter("name", name);
			query.setParameter("id", id);
			query.executeUpdate();
		} catch (Exception e) {
			log.error("Error while querying the db", e);
		} finally {
			try {
				query.unwrap(ProcedureOutputs.class).release();
			} catch (Exception e) {
			}
		}
	};
}

请注意,我们用 @Transactional("productTransactionManager") 注释对 updateProductInfo() 方法进行了注释,这意味着 productTransactionManager 将在此处使用。

创建 Spring Boot 主应用程序

MultipleDatasourcesApplication.java
package com.javachinna.multipledatasources;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(scanBasePackages = "com.javachinna")
public class MultipleDatasourcesApplication {

	public static void main(String[] args) {
		SpringApplication.run(MultipleDatasourcesApplication.class, args);
	}
}

创建 JUnit 测试

PrimeDataSourceTests.java

@TestInstance(Lifecycle.PER_CLASS) 注释用于将测试实例生命周期模式设置为 PER_CLASS,这意味着测试实例状态在给定测试类中的测试方法之间以及非静态 [[$35$] 之间共享]] 和 @AfterAll 方法在测试类中。如果我们不使用这个注解,那么我们就不能在非静态方法上使用 @BeforeAll 注解。如果我们将 init 方法设为静态,那么我们就不能在其中使用自动装配的存储库。

package com.javachinna.multipledatasources;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import java.util.Set;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.javachinna.model.prime.Role;
import com.javachinna.model.prime.User;
import com.javachinna.model.prime.UserInfo;
import com.javachinna.repo.prime.RoleRepository;
import com.javachinna.repo.prime.UserInfoRepository;
import com.javachinna.repo.prime.UserRepository;

@SpringBootTest
@TestInstance(Lifecycle.PER_CLASS)
class PrimeDataSourceTests {

	@Autowired
	private RoleRepository roleRepository;

	@Autowired
	private UserRepository userRepository;

	@Autowired
	private UserInfoRepository userInfoRepository;

	@BeforeAll
	public void init() {
		Role userRole = roleRepository.save(new Role(Role.USER));
		userRepository.save(new User("test", "secret", Set.of(userRole)));
	}

	@Test
	public void getUserTest() {
		List<User> list = userRepository.findAll();
		assertThat(list).isNotEmpty();
	}

	@Test
	public void getUserInfoTest() {
		List<UserInfo> list = userInfoRepository.getUerInfo();
		assertThat(list).isNotEmpty();
		assertThat(list.get(0).getName()).isEqualTo("test");
	}

}
ProductDataSourceTests.java
package com.javachinna.multipledatasources;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import java.util.Optional;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import com.javachinna.model.product.Product;
import com.javachinna.model.product.ProductInfo;
import com.javachinna.repo.product.ProductInfoRepository;
import com.javachinna.repo.product.ProductRepository;

@SpringBootTest
@TestInstance(Lifecycle.PER_CLASS)
class ProductDataSourceTests {

	@Autowired
	private ProductRepository productRepository;

	@Autowired
	private ProductInfoRepository productInfoRepository;

	@BeforeAll
	public void init() {
		Product product = new Product("phone", "secret");
		product = productRepository.save(product);
	}

	@Test
	public void getProductTest() {
		List<Product> list = productRepository.findAll();
		assertThat(list).isNotEmpty();
	}

	@Test
	public void getProductInfoTest() {
		List<ProductInfo> list = productInfoRepository.getProductInfo();
		assertThat(list).isNotEmpty();
		assertThat(list.get(0).getName()).isEqualTo("phone");
	}

	@Test
	public void updateProductTest() {
		productRepository.updateProduct("smartphone", 1L);
		Optional<Product> product = productRepository.findById(1L);
		assertThat(product.get().getName()).isEqualTo("smartphone");
	}

	@Test
	public void updateProductInfoTest() {
		productInfoRepository.updateProductInfo("cellphone", 1L);
		Optional<Product> product = productRepository.findById(1L);
		assertThat(product.get().getName()).isEqualTo("cellphone");
	}

}

相关文章