Spring Boot 학습 노트 06 -- JPA
본문 을 보고 나 면 다음 과 같은 지식 을 습득 할 것 이다.
머리말
JPA 는 Java Persistence API 로 O / R 맵 을 기반 으로 하 는 표준 규범 으로 이 규범 은 규칙 의 표준 (주해 또는 인터페이스) 만 정의 하고 구체 적 인 실현 을 제공 할 필요 가 없 으 며 구체 적 인 실현 은 소프트웨어 제공 업 체 에 의 해 이 루어 집 니 다. 현재 주요 한 JPA 공급 업 체 는 Hibernate, EclipseLink 와 OperJPA 입 니 다.
Spring Data JPA 는 Spring Data 의 하위 프로젝트 로 JPA 기반 Repository 를 제공 함으로써 코드 양 을 간소화 합 니 다.org. spring from work. data. jpa. reposcory. Jpa Repository 를 제공 합 니 다. 저희 Repository 는 이 Jpa Repository 를 계승 하면 JPA 가 가 져 온 좋 은 점 을 누 릴 수 있 습 니 다.
Spring Boot 는 spring - boot - starter - data - jpa 를 통 해 JPA 에 대한 지원 을 제공 합 니 다. Spring Boot 의 기본 JPA 실현 자 는 Hibernate 입 니 다.
아래 의 내용 을 설명 하기 전에, 우 리 는 먼저 데이터베이스 에 표를 한 장 만 들 었 다.
# 1
CREATE SCHEMA `springboot1` DEFAULT CHARACTER SET utf8 ;
CREATE TABLE `springboot1`.`person` (
`p_id` INT NOT NULL AUTO_INCREMENT COMMENT ' ',
`p_name` VARCHAR(45) NULL COMMENT ' ',
`p_age` INT NULL COMMENT ' ',
PRIMARY KEY (`p_id`))
ENGINE = InnoDB
COMMENT = ' ';
INSERT INTO `springboot1`.`person` (`p_id`, `p_name`, `p_age`) VALUES ('1', ' ', '20');
INSERT INTO `springboot1`.`person` (`p_id`, `p_name`, `p_age`) VALUES ('2', ' ', '25');
INSERT INTO `springboot1`.`person` (`p_id`, `p_name`, `p_age`) VALUES ('3', ' ', '18');
INSERT INTO `springboot1`.`person` (`p_id`, `p_name`, `p_age`) VALUES ('4', ' ', '18');
Spring Boot 항목 에 JPA 사용 하기
프로젝트 를 만 들 때 JPA 의존 도 를 선택 하거나 spring - boot - starter - data - jpa 를 pom 에 수 동 으로 추가 합 니 다.
org.springframework.boot
spring-boot-starter-data-jpa
이 항목 은 다음 두 개의 자동 설정 클래스 를 자동 으로 엽 니 다.
JpaRepositoriesAutoConfiguration HibernateJpaAutoConfiguration
application. properties 에 jpa 관련 설정 추가
#datasource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot1?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=newpwd
#spring_jpa
# , , , ;validate: , ;
spring.jpa.hibernate.ddl-auto=update
# sql
spring.jpa.show-sql=true
# json
spring.jackson.serialization.indent-output=true
프로젝트 에서 JPA 를 사용 할 때 JpaRepository 에 계승 되 는 Repository 인 터 페 이 스 를 만 들 면 JpaRepository 와 부모 클래스 에서 제공 하 는 모든 데이터 접근 방법 을 가 질 수 있 습 니 다.만약 제공 하 는 방법 이 업무 수 요 를 만족 시 키 지 못 한다 면 다음 과 같은 규칙 에 따라 데이터 방법 을 확장 할 수 있다.
JpaRepository
package org.springframework.data.jpa.repository;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
@NoRepositoryBean
public interface JpaRepository extends PagingAndSortingRepository, QueryByExampleExecutor {
List findAll();
List findAll(Sort var1);
List findAll(Iterable var1);
List save(Iterable var1);
void flush();
S saveAndFlush(S var1);
void deleteInBatch(Iterable var1);
void deleteAllInBatch();
T getOne(ID var1);
List findAll(Example var1);
List findAll(Example var1, Sort var2);
}
Repository: PersonRepository 를 사용자 정의 하고 데이터 접근 방법 을 확장 합 니 다. 구체 적 인 확장 방법 은 예제 코드 를 참조 하 십시오.
package com.example.dao;
import com.example.model.Person;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface PersonRepository extends JpaRepository {
//1. , , 。
// ,
//
List findByPName(String PName);
//And --- SQL and ;
List findByPNameAndPAge(String PName, Integer PAge);
// Or --- SQL or ;
List findByPNameOrPAge(String PName, Integer PAge);
//Between --- SQL between ;
List findByPAgeBetween(Integer min, Integer max);
//LessThan --- SQL " findByPAgeLessThan(Integer max);
//LessThanEqual --- SQL "<=";
List findByPAgeLessThanEqual(Integer max);
//GreaterThan --- SQL ">"; After
List findByPAgeGreaterThan(Integer min);
//GreaterThanEqual --- SQL ">=";
List findByPAgeGreaterThanEqual(Integer min);
//IsNull --- SQL "is null";
List findByPNameIsNull();
//IsNotNull --- SQL "is not null";
List findByPNameIsNotNull();
//NotNull --- IsNotNull ;
List findByPNameNotNull();
//Like --- SQL "like";
List findByPNameLike(String PName);
//NotLike --- SQL "not like";
List findByPNameNotLike(String PName);
//OrderBy --- SQL "order by";
List findByPNameNotNullOrderByPAgeAsc();
//Not --- SQL "! =";
List findByPNameNot(String PName);
//In --- SQL "in";
List findByPNameIn(String PName);
//NotIn --- SQL "not in";
List findByPNameNotIn(String PName);
//Top --- , First
List findTop2ByPName(String PName);
//2. @Query , , , @Modifying
//
@Query("select p from Person p where p.pName = :name and p.pAge = :age")
List withNameAndAgeQuery(@Param("name") String name, @Param("age") Integer age);
//
@Query("select p from Person p where p.pName = ?1 and p.pAge = ?2")
List withNameAndAgeQuery2(String name, Integer age);
// , hql, sql, nativeQuery = true
@Query(value = "delete from Person where pId=?1")
@Modifying
int deletePersonById(Integer id);
//
@Query(value = "update Person set pName=?1 where pId=?2 ")
@Modifying
int updatePersonName(String name, Integer id);
// , sql
@Query(value = "insert into person(p_name,p_age) value(?1,?2)",nativeQuery = true)
@Modifying
int insertPersonByParam(String name, Integer age);
//3. , Pageable pageable , Page
Page findByPNameNot(String name, Pageable pageable);
//
@Query("select p from Person p where p.pName = :name ")
Page withNameQueryPage(@Param("name") String name, Pageable pageable);
}
POJO 실체 대상: Person
package com.example.model;
import javax.persistence.*;
import static javax.persistence.GenerationType.IDENTITY;
@Entity
@Table(name = "person"
, catalog = "springboot1"
)
public class Person implements java.io.Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "p_id", unique = true, nullable = false)
private Integer pId;
@Column(name = "p_name", length = 45)
private String pName;
@Column(name = "p_age")
private Integer pAge;
//setter and getter
@Override
public String toString() {
return "Person{" +
"pId=" + pId +
", pName='" + pName + '\'' +
", pAge=" + pAge +
'}';
}
}
테스트 데모
package com.example;
import com.example.dao.PersonRepository;
import com.example.model.Person;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import java.util.Iterator;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class JpaSingleDatasourceApplicationTests {
@Autowired
private PersonRepository personRepository;
@Test
public void findByPName() {
String name = " ";
List list = personRepository.findByPName(name);
System.out.println(list.size());
for(Person person : list){
System.out.println(person);
}
}
@Test
public void findByPNameAndPAge() {
String name = " ";
int age = 18;
List list = personRepository.findByPNameAndPAge(name,age);
System.out.println(list.size());
for(Person person : list){
System.out.println(person);
}
}
@Test
public void findByPNameOrPAge() {
String name = " ";
int age = 25;
List list = personRepository.findByPNameOrPAge(name,age);
System.out.println(list.size());
for(Person person : list){
System.out.println(person);
}
}
@Test
public void findTop2ByPName() {
String name = " ";
List list = personRepository.findTop2ByPName(name);
System.out.println(list.size());
for(Person person : list){
System.out.println(person);
}
}
@Test
public void withNameAndAgeQuery() {
String name = " ";
int age = 18;
List list = personRepository.withNameAndAgeQuery(name,age);
System.out.println(list.size());
for(Person person : list){
System.out.println(person);
}
}
@Test
public void withNameAndAgeQuery2() {
String name = " ";
int age = 18;
List list = personRepository.withNameAndAgeQuery2(name,age);
System.out.println(list.size());
for(Person person : list){
System.out.println(person);
}
}
@Test
public void deletePersonById(){
int id = 1;
int result = personRepository.deletePersonById(id);
System.out.println("result = " + result);
}
@Test
public void updatePersonName(){
int id = 1;
String name = " ";
int result = personRepository.updatePersonName(name,id);
System.out.println("result = " + result);
}
@Test
public void insertPersonByParam(){
int age = 10;
String name = " ";
int result = personRepository.insertPersonByParam(name,age);
System.out.println("result = " + result);
}
@Test
public void findByPNameNot(){
String name = " ";
//
Sort sort = new Sort(Sort.Direction.DESC, "pId");
// ,
Pageable pageable = new PageRequest(0, 3, sort);
Page pages = personRepository.findByPNameNot(name,pageable);
System.out.println("pages.getTotalElements()" + pages.getTotalElements());
System.out.println("pages.getTotalPages()" + pages.getTotalPages());
Iterator it=pages.iterator();
while(it.hasNext()){
System.out.println("value:"+((Person)it.next()));
}
}
@Test
public void withNameQueryPage(){
String name = " ";
//
Sort sort = new Sort(Sort.Direction.DESC, "pId");
// ,
Pageable pageable = new PageRequest(1, 3, sort);
Page pages = personRepository.withNameQueryPage(name,pageable);
System.out.println("pages.getTotalElements()" + pages.getTotalElements());
System.out.println("pages.getTotalPages()" + pages.getTotalPages());
Iterator it=pages.iterator();
while(it.hasNext()){
System.out.println("value:"+((Person)it.next()));
}
}
}
Spring Boot 프로젝트 에서 Spring Data JPA 를 설정 하 는 방법
spring - boot - starter - data - jpa 에 의존 하지 않 으 려 면 설정 류 를 통 해 Spring Boot 가 Spring Data JPA 에 대한 지원 을 실현 할 수 있 습 니 다.
pom 교체 의존 은 여기 서 설명 합 니 다. 실제로 spring - boot - starter - data - jpa 의 의존 을 교체 하지 않 아 도 됩 니 다. 교체 의 장점 은 필요 하지 않 은 jar 에 대한 의존 을 줄 이 는 것 입 니 다.
mysql
mysql-connector-java
5.1.37
javax.transaction
jta
1.1
org.aspectj
aspectjweaver
1.8.9
org.hibernate
hibernate-core
4.3.5.Final
org.hibernate
hibernate-entitymanager
4.3.5.Final
org.springframework
spring-orm
4.3.3.RELEASE
org.springframework.data
spring-data-jpa
1.10.5.RELEASE
사용자 정의 설정 클래스: DataSourceConfig
package com.example;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
// Spring Data JPA
@EnableJpaRepositories(basePackages = "com.example.dao", entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
public class DataSourceConfig {
@Value("${spring.datasource.driver-class-name}")
String driverClass;
@Value("${spring.datasource.url}")
String url;
@Value("${spring.datasource.username}")
String userName;
@Value("${spring.datasource.password}")
String passWord;
@Bean(name = "dataSource")
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(userName);
dataSource.setPassword(passWord);
return dataSource;
}
// jpa
@Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager() {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setDataSource(dataSource());
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return jpaTransactionManager;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(true);
adapter.setDatabase(Database.MYSQL);
adapter.setGenerateDdl(true);
return adapter;
}
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(dataSource());
entityManager.setJpaVendorAdapter(jpaVendorAdapter());
entityManager.setPackagesToScan("com.example.model");// entity package
entityManager.setPersistenceProviderClass(HibernatePersistenceProvider.class);
return entityManager;
}
}
프로젝트 시작 클래스 에서 jpa 의 자동 설정 을 닫 습 니 다:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,JpaRepositoriesAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class JpaSingleDatasourceApplication {
public static void main(String[] args) {
SpringApplication.run(JpaSingleDatasourceApplication.class, args);
}
}
Spring Data JPA 와 Atomikos 를 통합 하여 다 중 데이터 소스 사무 관 리 를 실현 합 니 다.
spring - data - jpa 는 기본적으로 Hibernate 를 사용한다 고 하지만 Atomikos 통합 방식 과 Hibernate 는 약간 다르다.
pom
com.atomikos
transactions-jdbc
4.0.4
com.atomikos
transactions-jta
4.0.4
com.atomikos
transactions
4.0.4
com.atomikos
atomikos-util
4.0.4
javax.transaction
jta
1.1
org.aspectj
aspectjweaver
1.8.9
org.hibernate
hibernate-core
4.3.5.Final
org.springframework
spring-orm
4.3.3.RELEASE
org.springframework.data
spring-data-jpa
1.10.5.RELEASE
org.hibernate
hibernate-entitymanager
4.3.5.Final
mysql
mysql-connector-java
5.1.37
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
application.properties
#datasource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot1?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=newpwd
#datasource2
spring.datasource.driver-class-name2=com.mysql.jdbc.Driver
spring.datasource.url2=jdbc:mysql://localhost:3306/springboot2?useUnicode=true&characterEncoding=utf-8
spring.datasource.username2=root
spring.datasource.password2=newpwd
MainConfig: Atomikos 사무 관리자 등록 에 사용
package com.example;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
@Configuration
public class MainConfig {
@Bean(name = "userTransaction")
public UserTransaction userTransaction() throws Throwable {
UserTransactionImp userTransactionImp = new UserTransactionImp();
userTransactionImp.setTransactionTimeout(10000);
return userTransactionImp;
}
@Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")
public TransactionManager atomikosTransactionManager() throws Throwable {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(true);
return userTransactionManager;
}
@Bean(name = "transactionManager")
@DependsOn({ "userTransaction", "atomikosTransactionManager" })
public PlatformTransactionManager transactionManager() throws Throwable {
UserTransaction userTransaction = userTransaction();
TransactionManager atomikosTransactionManager = atomikosTransactionManager();
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager(userTransaction, atomikosTransactionManager);
jtaTransactionManager.setAllowCustomIsolationLevels(true);
return jtaTransactionManager;
}
// , bean
@Bean(name = "atomikosJtaPlatfom")
public AtomikosJtaPlatfom atomikosJtaPlatfom(){
AtomikosJtaPlatfom atomikosJtaPlatfom = new AtomikosJtaPlatfom();
try {
atomikosJtaPlatfom.setTm(atomikosTransactionManager());
atomikosJtaPlatfom.setUt(userTransaction());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return atomikosJtaPlatfom;
}
}
JPA 의 LocalContainer Entity Manager Factory Bean 을 설정 할 때 JTA 를 지원 할 수 있 도록 하려 면 Jpa Properties 를 설정 할 때 다음 과 같은 인 자 를 지정 해 야 합 니 다.
hibernate.transaction.jta.platform hibernate.current_session_context_class hibernate.transaction.factory_class
다음 에 LocalContainer Entity Manager Factory Bean 을 설정 할 때 해당 하 는 설정 을 볼 수 있 습 니 다. 여기 서 말 하고 자 하 는 것 은
hibernate.transaction.jta.platform
지정 org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform
의 실현 류 가 필요 합 니 다. 그 주요 기능 은 javax. transaction. TransactionManager 와 javax. transaction. UserTransaction 을 연결 하 는 것 입 니 다.spring - data - jpa 는 이러한 실현 클래스 를 제공 하지 않 았 으 나, hibenate 는 많은 실현 클래스 를 제공 하 였 으 며, spring boot 도 하나의 실현 클래스 인 SpringJ taPlatform 을 제공 하 였 으 나, 이러한 실현 클래스 는 모두 구조 함수 로 자바 x. transaction. Manager 와 자바 x. transaction. UserTransaction 을 연결 하 였 으 며, 결 성 된 구조 방법 을 제공 하지 않 았 기 때문에 속성 지정
hibernate.transaction.jta.platform
을 통 해 이 루어 졌 다.스프링 은 이 실현 클래스 를 초기 화 할 수 없습니다.따라서 구현 클래스 를 만 들 고 set 방법 으로 javax. transaction. TransactionManager 와 javax. transaction. UserTransaction 을 연결 할 수 있 습 니 다.이게 바로 Atomikos JtaPlatfom 입 니 다.
package com.example;
import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
public class AtomikosJtaPlatfom extends AbstractJtaPlatform {
private static UserTransaction ut;
private static TransactionManager tm;
@Override
protected TransactionManager locateTransactionManager() {
return tm;
}
@Override
protected UserTransaction locateUserTransaction() {
return ut;
}
public UserTransaction getUt() {
return ut;
}
public void setUt(UserTransaction ut) {
AtomikosJtaPlatfom.ut = ut;
}
public TransactionManager getTm() {
return tm;
}
public void setTm(TransactionManager tm) {
AtomikosJtaPlatfom.tm = tm;
}
}
다음은 설정 클래스 에 LocalContainer Entity Manager Factory Bean 을 등록 해 야 합 니 다. @ EnableJpa Repositories 주 해 는 같은 설정 클래스 에 두 번 설명 할 수 없 기 때문에 데이터 원본 에 따라 각각 설정 합 니 다.
JpaConfigDs 1: 데이터 원본 1
package com.example;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
// 1 Repository , 1 entityManagerFactory,
@EnableJpaRepositoryies(basePackages = "com.example.dao.ds1", entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager")
public class JpaConfigDs1 {
@Value("${spring.datasource.driver-class-name}")
String driverClass;
@Value("${spring.datasource.url}")
String url;
@Value("${spring.datasource.username}")
String userName;
@Value("${spring.datasource.password}")
String passWord;
@Bean(name = "dataSource", initMethod = "init", destroyMethod = "close")
public DataSource dataSource() {
System.out.println("dataSource init");
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(url);
mysqlXaDataSource.setPassword(passWord);
mysqlXaDataSource.setUser(userName);
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("dataSource");
xaDataSource.setMinPoolSize(10);
xaDataSource.setPoolSize(10);
xaDataSource.setMaxPoolSize(30);
xaDataSource.setBorrowConnectionTimeout(60);
xaDataSource.setReapTimeout(20);
xaDataSource.setMaxIdleTime(60);
xaDataSource.setMaintenanceInterval(60);
return xaDataSource;
}
@Bean(name = "jpaVendorAdapter")
public JpaVendorAdapter jpaVendorAdapter() {
System.out.println("jpaVendorAdapter init");
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(true);
adapter.setDatabase(Database.MYSQL);
adapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
adapter.setGenerateDdl(true);
return adapter;
}
@Bean(name = "entityManagerFactory")
@DependsOn({"atomikosJtaPlatfom"}) // atomikosJtaPlatfom
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
System.out.println("entityManagerFactory init");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJpaVendorAdapter(jpaVendorAdapter());
// entity package
entityManager.setPackagesToScan("com.example.model.ds1");
entityManager.setJtaDataSource(dataSource());
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.format_sql", "true");
//jta
properties.put("hibernate.current_session_context_class", "jta");
properties.put("hibernate.transaction.factory_class", "org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory");
// AtomikosJtaPlatfom
properties.put("hibernate.transaction.jta.platform","com.example.AtomikosJtaPlatfom");
entityManager.setJpaProperties(properties);
return entityManager;
}
}
JpaconfigDs 2: 데이터 원본 2
package com.example;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@EnableJpaRepositories(basePackages = "com.example.dao.ds2", entityManagerFactoryRef = "entityManagerFactory2", transactionManagerRef = "transactionManager")
public class JpaConfigDs2 {
@Value("${spring.datasource.driver-class-name2}")
String driverClass;
@Value("${spring.datasource.url2}")
String url;
@Value("${spring.datasource.username2}")
String userName;
@Value("${spring.datasource.password2}")
String passWord;
@Bean(name = "dataSource2", initMethod = "init", destroyMethod = "close")
public DataSource dataSource() {
System.out.println("dataSource2 init");
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
mysqlXaDataSource.setUrl(url);
mysqlXaDataSource.setPassword(passWord);
mysqlXaDataSource.setUser(userName);
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("dataSource2");
xaDataSource.setMinPoolSize(10);
xaDataSource.setPoolSize(10);
xaDataSource.setMaxPoolSize(30);
xaDataSource.setBorrowConnectionTimeout(60);
xaDataSource.setReapTimeout(20);
xaDataSource.setMaxIdleTime(60);
xaDataSource.setMaintenanceInterval(60);
return xaDataSource;
}
@Bean(name = "jpaVendorAdapter2")
public JpaVendorAdapter jpaVendorAdapter() {
System.out.println("jpaVendorAdapter2 init");
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(true);
adapter.setDatabase(Database.MYSQL);
adapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
adapter.setGenerateDdl(true);
return adapter;
}
@Bean(name = "entityManagerFactory2")
@DependsOn({"atomikosJtaPlatfom"})
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
System.out.println("entityManagerFactory2 init");
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
entityManager.setJpaVendorAdapter(jpaVendorAdapter());
entityManager.setPackagesToScan("com.example.model.ds2");// entity package
entityManager.setJtaDataSource(dataSource());
Properties properties = new Properties();
properties.put("hibernate.transaction.jta.platform","com.example.AtomikosJtaPlatfom");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.format_sql", "true");
properties.put("hibernate.current_session_context_class", "jta");
properties.put("hibernate.transaction.factory_class", "org.hibernate.engine.transaction.internal.jta.CMTTransactionFactory");
entityManager.setJpaProperties(properties);
return entityManager;
}
}
다른 면 에 서 는 단일 데이터 원본 이 JPA 를 사용 하 는 것 과 다 르 지 않 으 며, 여 기 는 코드 를 나열 하지 않 습 니 다.
JPA 확장 방법
일반적인 상황 에서 우리 의 Repository 인 터 페 이 스 는 JpaRepository 를 계승 하기 때문에 JpaRepository 가 제공 하 는 모든 방법 을 기본 으로 사용 할 수 있 습 니 다. 만약 에 제공 하 는 방법 이 수 요 를 만족 시 키 지 못 할 경우 자신의 Repository 에서 명명 규칙 이나 @ Query 주석 등 을 통 해 방법 을 확장 할 수 있 습 니 다.그렇다면 우리 가 모든 Repository 가 이 확장 기능 을 가 질 수 있 도록 공공 을 확장 하 는 방법 을 부모 클래스 에 두 고 싶다 면 어떻게 실현 해 야 합 니까?
이 예 는 예 를 들 어 조회 조건 의 페이지 별 조 회 를 받 고 조회 할 때 실체 대상 을 전달 하 는 속성 에 따라 처리 하 며 문자열 이 라면 모호 하 게 일치 하지 않 으 면 정확하게 일치 합 니 다.
부모 인터페이스 정의 -- BaseJpaRepository
@NoRepositoryBean // Repository
public interface BaseJpaRepository extends JpaRepository,JpaSpecificationExecutor {
Page findByAuto(T example, Pageable pageable);
}
구현 클래스 만 들 기 -- BaseJpaRepository Impl
public class BaseJpaRepositoryImpl extends SimpleJpaRepository implements BaseJpaRepository {
// EntityManager
private final EntityManager entityManager;
public BaseJpaRepositoryImpl(Class domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
this.entityManager = entityManager;
}
// , BaseSpecs
@Override
public Page findByAuto(T example, Pageable pageable) {
return findAll(BaseSpecs.byAuto(entityManager,example),pageable);
}
}
BaseSpecs 의 by Auto 방법 은 검색 대상 Specification 을 패키지 하고 실체 대상 을 전달 하 는 속성 에 따라 처리 합 니 다. 문자열 이 라면 모호 하 게 일치 하지 않 으 면 정확하게 일치 합 니 다.
public class BaseSpecs {
public static Specification byAuto(final EntityManager entityManager, final T example){
final Class type = (Class) example.getClass();
return new Specification() {
@Override
public Predicate toPredicate(Root root, CriteriaQuery> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List predicateList = new ArrayList<>();
EntityType entityType = entityManager.getMetamodel().entity(type);
for(Attribute attribute : entityType.getDeclaredAttributes()){
Object attrValue = getValue(example,attribute);
if(attrValue != null){
if(attribute.getJavaType() == String.class){
if(!StringUtils.isEmpty(attrValue)){
predicateList.add(criteriaBuilder.like(root.get(attribute(entityType,attribute.getName(),String.class)),pattern((String)attrValue)));
}
}else{
predicateList.add(criteriaBuilder.equal(root.get(attribute(entityType,attribute.getName(),attrValue.getClass())),attrValue));
}
}
}
return predicateList.isEmpty()?criteriaBuilder.conjunction():criteriaBuilder.and(toArray(predicateList));
}
private Object getValue(T example,Attribute attr){
return ReflectionUtils.getField((Field)attr.getJavaMember(),example);
}
private SingularAttribute attribute(EntityType entityType,String fieldName,Class fieldClass){
return entityType.getDeclaredSingularAttribute(fieldName,fieldClass);
}
private Predicate[] toArray(List predicateList){
Predicate[] array = predicateList.toArray(new Predicate[predicateList.size()]);
return array;
}
};
}
static private String pattern(String str){
return "%" + str + "%";
}
}
우리 의 Repository 가 Jpa Repository 를 실현 할 때 Spring - data - jpa 는 우리 에 게 Jpa Repository 의 실현 류 Simple Jpa Repository 를 동적 으로 사용 하 는 이 유 를 설명 합 니 다. 이것 은 우리 가 인 터 페 이 스 를 만 들 고 실현 류 를 제공 하지 않 아 도 되 는 이유 입 니 다.
여기 서 우 리 는 새로운 부모 인터페이스 BaseJpa Repository 를 만 들 었 고 실현 류 BaseJpa Repository Impl 을 제공 했다. 그래서 우 리 는 Spring - data - jpa 에 게 우리 자신의 실현 류 를 사용 해 야 하 며 Simple Jpa Repository 를 사용 해 서 는 안 된다 고 알려 야 한다. 그래서 우 리 는 Jpa Repository Factory Bean 을 바 꿔 야 한다.
Jpa Repository Factory Bean 에 계승 할 BaseRepository Factory Bean 을 만 듭 니 다:
public class BaseRepositoryFactoryBean, S, ID extends Serializable> extends JpaRepositoryFactoryBean {
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new BaseRepositoryFactory(entityManager);
}
}
class BaseRepositoryFactory extends JpaRepositoryFactory {
public BaseRepositoryFactory(EntityManager entityManager){
super(entityManager);
}
//
@Override
protected SimpleJpaRepository, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager) {
BaseJpaRepositoryImpl customRepository = new BaseJpaRepositoryImpl((Class)information.getDomainType(),entityManager);
return customRepository;
}
//
@Override
protected Class> getRepositoryBaseClass(RepositoryMetadata metadata)
return BaseJpaRepositoryImpl.class;
}
}
또한 @ EnableJpa Repositories 주석 에서 지정 합 니 다:
@EnableJpaRepositories(basePackages = "com.example.dao", entityManagerFactoryRef = "entityManagerFactory", transactionManagerRef = "transactionManager",repositoryFactoryBeanClass=BaseRepositoryFactoryBean.class)
public class JpaConfig {
//………………
}
사용자 정의 저장 소 계승 BaseJpaRepository
public interface PersonRepository extends BaseJpaRepository {
//……… ………
}
테스트
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class JpaExtendApplicationTests {
@Autowired
private PersonRepository personRepository;
@Test
public void findByAuto() {
Person person = new Person();
person.setpName(" ");
person.setpAge(18);
Sort sort = new Sort(Sort.Direction.DESC, "pId");
// ,
Pageable pageable = new PageRequest(0, 3, sort);
Page list = personRepository.findByAuto(person,pageable);
for(Person p:list){
System.out.println(p);
}
}
}
본문 예제 코드 다운로드 주소:https://github.com/hanqunfeng/SpringBootStudy
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.