Skip to content

Commit 1c41bd2

Browse files
committed
Batch inserts (including associations)
1 parent e11d4f7 commit 1c41bd2

16 files changed

+389
-359
lines changed

HibernateSpringBootBatchInsertOrder/pom.xml

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44
<modelVersion>4.0.0</modelVersion>
55

66
<groupId>com.jpa</groupId>
7-
<artifactId>jpa</artifactId>
7+
<artifactId>HibernateSpringBootBatchInsertOrder</artifactId>
88
<version>1.0</version>
99
<packaging>jar</packaging>
1010

11-
<name>jpa</name>
11+
<name>HibernateSpringBootBatchInsertOrder</name>
1212
<description>JPA project for Spring Boot</description>
1313

1414
<parent>
1515
<groupId>org.springframework.boot</groupId>
1616
<artifactId>spring-boot-starter-parent</artifactId>
17-
<version>2.0.5.RELEASE</version>
17+
<version>2.1.4.RELEASE</version>
1818
<relativePath/> <!-- lookup parent from repository -->
1919
</parent>
2020

@@ -37,12 +37,7 @@
3737
<dependency>
3838
<groupId>org.springframework.boot</groupId>
3939
<artifactId>spring-boot-starter-web</artifactId>
40-
</dependency>
41-
<dependency>
42-
<groupId>net.ttddyy</groupId>
43-
<artifactId>datasource-proxy</artifactId>
44-
<version>${datasource-proxy.version}</version>
45-
</dependency>
40+
</dependency>
4641
<dependency>
4742
<groupId>mysql</groupId>
4843
<artifactId>mysql-connector-java</artifactId>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.bookstore;
2+
3+
import com.bookstore.impl.BatchRepositoryImpl;
4+
import com.bookstore.service.BookstoreService;
5+
import org.springframework.boot.ApplicationRunner;
6+
import org.springframework.boot.SpringApplication;
7+
import org.springframework.boot.autoconfigure.SpringBootApplication;
8+
import org.springframework.context.annotation.Bean;
9+
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
10+
11+
@SpringBootApplication
12+
@EnableJpaRepositories(repositoryBaseClass = BatchRepositoryImpl.class)
13+
public class MainApplication {
14+
15+
private final BookstoreService authorService;
16+
17+
public MainApplication(BookstoreService authorService) {
18+
this.authorService = authorService;
19+
}
20+
21+
public static void main(String[] args) {
22+
SpringApplication.run(MainApplication.class, args);
23+
}
24+
25+
@Bean
26+
public ApplicationRunner init() {
27+
return args -> {
28+
authorService.batchAuthorsAndBooks();
29+
};
30+
}
31+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.bookstore.entity;
2+
3+
import java.io.Serializable;
4+
import java.util.ArrayList;
5+
import java.util.Iterator;
6+
import java.util.List;
7+
import javax.persistence.CascadeType;
8+
import javax.persistence.Entity;
9+
import javax.persistence.Id;
10+
import javax.persistence.OneToMany;
11+
12+
@Entity
13+
public class Author implements Serializable {
14+
15+
private static final long serialVersionUID = 1L;
16+
17+
@Id
18+
private Long id;
19+
20+
private String name;
21+
private String genre;
22+
private int age;
23+
24+
@OneToMany(cascade = CascadeType.ALL,
25+
mappedBy = "author", orphanRemoval = true)
26+
private List<Book> books = new ArrayList<>();
27+
28+
public void addBook(Book book) {
29+
this.books.add(book);
30+
book.setAuthor(this);
31+
}
32+
33+
public void removeBook(Book book) {
34+
book.setAuthor(null);
35+
this.books.remove(book);
36+
}
37+
38+
public void removeBooks() {
39+
Iterator<Book> iterator = this.books.iterator();
40+
41+
while (iterator.hasNext()) {
42+
Book book = iterator.next();
43+
44+
book.setAuthor(null);
45+
iterator.remove();
46+
}
47+
}
48+
49+
public Long getId() {
50+
return id;
51+
}
52+
53+
public void setId(Long id) {
54+
this.id = id;
55+
}
56+
57+
public String getName() {
58+
return name;
59+
}
60+
61+
public void setName(String name) {
62+
this.name = name;
63+
}
64+
65+
public String getGenre() {
66+
return genre;
67+
}
68+
69+
public void setGenre(String genre) {
70+
this.genre = genre;
71+
}
72+
73+
public int getAge() {
74+
return age;
75+
}
76+
77+
public void setAge(int age) {
78+
this.age = age;
79+
}
80+
81+
public List<Book> getBooks() {
82+
return books;
83+
}
84+
85+
public void setBooks(List<Book> books) {
86+
this.books = books;
87+
}
88+
89+
@Override
90+
public String toString() {
91+
return "Author{" + "id=" + id + ", name=" + name
92+
+ ", genre=" + genre + ", age=" + age + '}';
93+
}
94+
95+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.bookstore.entity;
2+
3+
import java.io.Serializable;
4+
import javax.persistence.Entity;
5+
import javax.persistence.FetchType;
6+
import javax.persistence.Id;
7+
import javax.persistence.JoinColumn;
8+
import javax.persistence.ManyToOne;
9+
10+
@Entity
11+
public class Book implements Serializable {
12+
13+
private static final long serialVersionUID = 1L;
14+
15+
@Id
16+
private Long id;
17+
18+
private String title;
19+
private String isbn;
20+
21+
@ManyToOne(fetch = FetchType.LAZY)
22+
@JoinColumn(name = "author_id")
23+
private Author author;
24+
25+
public Long getId() {
26+
return id;
27+
}
28+
29+
public void setId(Long id) {
30+
this.id = id;
31+
}
32+
33+
public String getTitle() {
34+
return title;
35+
}
36+
37+
public void setTitle(String title) {
38+
this.title = title;
39+
}
40+
41+
public String getIsbn() {
42+
return isbn;
43+
}
44+
45+
public void setIsbn(String isbn) {
46+
this.isbn = isbn;
47+
}
48+
49+
public Author getAuthor() {
50+
return author;
51+
}
52+
53+
public void setAuthor(Author author) {
54+
this.author = author;
55+
}
56+
57+
@Override
58+
public boolean equals(Object obj) {
59+
60+
if (this == obj) {
61+
return true;
62+
}
63+
64+
if (getClass() != obj.getClass()) {
65+
return false;
66+
}
67+
68+
return id != null && id.equals(((Book) obj).id);
69+
}
70+
71+
@Override
72+
public int hashCode() {
73+
return 2021;
74+
}
75+
76+
@Override
77+
public String toString() {
78+
return "Book{" + "id=" + id + ", title=" + title + ", isbn=" + isbn + '}';
79+
}
80+
81+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.bookstore.impl;
2+
3+
import java.io.Serializable;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.data.repository.NoRepositoryBean;
6+
7+
@NoRepositoryBean
8+
public interface BatchRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
9+
10+
<S extends T> S persist(S entity);
11+
<S extends T> Iterable<S> saveInBatch(Iterable<S> entites);
12+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.bookstore.impl;
2+
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.io.Serializable;
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.Properties;
9+
import java.util.logging.Level;
10+
import java.util.logging.Logger;
11+
import javax.persistence.EntityManager;
12+
import org.hibernate.dialect.Dialect;
13+
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
14+
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
15+
import org.springframework.transaction.annotation.Transactional;
16+
17+
@Transactional(readOnly = true)
18+
public class BatchRepositoryImpl<T, ID extends Serializable>
19+
extends SimpleJpaRepository<T, ID> implements BatchRepository<T, ID> {
20+
21+
private static final Logger logger = Logger.getLogger(BatchRepositoryImpl.class.getName());
22+
23+
private final EntityManager entityManager;
24+
25+
public BatchRepositoryImpl(JpaEntityInformation entityInformation,
26+
EntityManager entityManager) {
27+
super(entityInformation, entityManager);
28+
29+
this.entityManager = entityManager;
30+
}
31+
32+
@Override
33+
@Transactional
34+
public <S extends T> S persist(S entity) {
35+
entityManager.persist(entity);
36+
37+
return entity;
38+
}
39+
40+
@Override
41+
@Transactional
42+
public <S extends T> Iterable<S> saveInBatch(Iterable<S> entities) {
43+
44+
if (entities == null) {
45+
throw new IllegalArgumentException("The given Iterable of entities cannot be null!");
46+
}
47+
48+
int i = 0;
49+
List<S> result = new ArrayList<>();
50+
for (S entity : entities) {
51+
result.add(persist(entity));
52+
53+
i++;
54+
55+
// Flush a batch of inserts and release memory
56+
if (i % batchSize() == 0 && i > 0) {
57+
logger.log(Level.INFO,
58+
"Flushing the EntityManager containing {0} entities ...", i);
59+
60+
entityManager.flush();
61+
entityManager.clear();
62+
i = 0;
63+
}
64+
}
65+
66+
if (i > 0) {
67+
logger.log(Level.INFO,
68+
"Flushing the remaining {0} entities ...", i);
69+
70+
entityManager.flush();
71+
entityManager.clear();
72+
}
73+
74+
return result;
75+
}
76+
77+
private static int batchSize() {
78+
79+
int batchsize = Integer.valueOf(Dialect.DEFAULT_BATCH_SIZE); // default batch size
80+
81+
Properties configuration = new Properties();
82+
try ( InputStream inputStream = BatchRepositoryImpl.class.getClassLoader()
83+
.getResourceAsStream("application.properties")) {
84+
configuration.load(inputStream);
85+
} catch (IOException ex) {
86+
logger.log(Level.SEVERE,
87+
"Cannot fetch batch size. Using further Dialect.DEFAULT_BATCH_SIZE{0}", ex);
88+
return batchsize;
89+
}
90+
91+
String batchsizestr = configuration.getProperty(
92+
"spring.jpa.properties.hibernate.jdbc.batch_size");
93+
if (batchsizestr != null) {
94+
batchsize = Integer.valueOf(batchsizestr);
95+
}
96+
97+
return batchsize;
98+
}
99+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.bookstore.repository;
2+
3+
import com.bookstore.impl.BatchRepository;
4+
import com.bookstore.entity.Author;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface AuthorRepository extends BatchRepository<Author, Long> {
9+
}
10+

0 commit comments

Comments
 (0)