Статьи

Spring Boot, JPA, Hibernate и Oracle

В этом руководстве показано, как создать приложение Spring Boot, которое взаимодействует с источником данных Oracle через Hibernate.

Предпосылки:

  • Eclipse IDE (неоновый выпуск)
  • Maven 4
  • Java 1.8

1- Создать Maven проект

Откройте eclipse, затем создайте новый проект maven и назовите его SpringBootHibernate .

В конце этого урока мы получим следующую структуру проекта:

2- pom.xml

Настройте Spring Boot внутри pom.xml, добавив следующую родительскую зависимость:

1
2
3
4
5
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
</parent>

Затем добавьте зависимость spring-boot-starter , чтобы запустить наше приложение как отдельное jar-приложение:

1
2
3
4
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
</dependency>

Теперь, чтобы использовать Spring data jpa и hibernate, нам нужно просто добавить spring-boot-starter-data-jpa в качестве зависимости:

1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

Как только мы включим Spring Boot Starter JPA в наш проект, мы получим следующие возможности из широкого спектра зависимостей:

  • Автоматическая настройка встроенной базы данных в памяти, которая позволяет запускать ваше приложение, даже не настраивая базу данных.
  • Автоматический импорт JPA API и Hibernate, добавление этой зависимости автоматически импортирует JPA API и использует Hibernate в качестве реализации по умолчанию.
  • Автоматическое чтение источника данных и конфигурации гибернации из application.properties.
  • Автоматическое создание сущностей в виде таблиц и автоматическое выполнение import.sql.

Это целый pom.xml для справки:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.programmer.gate</groupId>
  <artifactId>SpringBootHibernate</artifactId>
  <packaging>jar</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>SpringBootHibernate</name>
   
  <properties>
       <maven.compiler.source>1.8</maven.compiler.source>
       <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
     
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
    </parent>
     
  <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>
     
  </dependencies>
   
  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
      </plugins>
  </build>
   
</project>

3- Добавить драйвер оракула в classpath

В этом руководстве мы собираемся переопределить базу данных по умолчанию в памяти, предоставляемую Spring Boot, и использовать нашу собственную базу данных Oracle.

Для этого мы добавляем «oracle-ojdbc6-11.2.0.3.jar» в WEB-INF / lib и определяем его в нашем пути к классам.

4- приложение. Свойства

Сконфигурируйте источник данных oracle и спящий режим в application.properties :

01
02
03
04
05
06
07
08
09
10
11
12
# create and drop tables and sequences, loads import.sql
spring.jpa.hibernate.ddl-auto=create-drop
  
# Oracle settings
spring.datasource.url=jdbc:oracle:thin:@localhost:1522:orcl
spring.datasource.username=HIBERNATE_TEST
spring.datasource.password=HIBERNATE_TEST
spring.datasource.driver.class=oracle.jdbc.driver.OracleDriver
  
# logging
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n
logging.level.org.hibernate.SQL=debug

5- Сущности

Наши организации представляют игрока и команду с отношениями один-ко-многим, в каждой команде может быть много игроков, в то время как игрок может играть только с одной командой одновременно.

Поэтому мы создаем наши сущности в пакете com.programmer.gate.model :

Player.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.programmer.gate.model;
  
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
  
@Entity
public class Player {
  
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "player_Sequence")
    @SequenceGenerator(name = "player_Sequence", sequenceName = "PLAYER_SEQ")
    private Long id;
  
    @Column(name = "name")
    private String name;
  
    @Column(name = "num")
    private int num;
  
    @Column(name = "position")
    private String position;
     
    @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "team_id", nullable = false)
        private Team team;
     
    public Player() {
    }
        // getters/setters
}

Team.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package com.programmer.gate.model;
  
import java.util.List;
  
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
  
@Entity
public class Team {
  
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "team_Sequence")
    @SequenceGenerator(name = "team_Sequence", sequenceName = "TEAM_SEQ")
    private Long id;
  
    @Column(name = "name")
    private String name;
  
    @OneToMany(cascade = CascadeType.ALL,
            fetch = FetchType.EAGER,
            mappedBy = "team")
    private List<Player> players;
     
    public Team() {
    }
  
        // getters/setters
}

Поскольку мы устанавливаем spring.jpa.hibernate.ddl-auto = create-drop внутри application.properties , наше приложение автоматически создает объекты Player и Team в нашей базе данных вместе с их последовательностями и ограничениями.

Наше приложение также будет искать import.sql в пути к классам и выполнит его, если найдет.

В нашем примере мы определяем import.sql в src / main / resources , чтобы заполнить наши таблицы статическими данными:

1
2
3
4
5
insert into Team (id,name) values(1,'Barcelona');
  
insert into Player (id, team_id, name, num, position) values(1,1,'Lionel Messi', 10, 'Forward');
insert into Player (id, team_id, name, num, position) values(2,1,'Andreas Inniesta', 8, 'Midfielder');
insert into Player (id, team_id, name, num, position) values(3,1,'Pique', 3, 'Defender');

6- Хранилища

Мы определяем наши интерфейсы репозиториев в com.programmer.gate.repository . Каждый репозиторий расширяет Spring CrudRepository, который обеспечивает реализацию по умолчанию для основных методов поиска, сохранения и удаления , так что нам не нужно определять классы реализации для них.

PlayerRepository

01
02
03
04
05
06
07
08
09
10
11
12
13
14
package com.programmer.gate.repository;
  
import java.util.List;
  
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
  
import com.programmer.gate.model.Player;
  
@Repository
public interface PlayerRepository extends CrudRepository<Player, Long> {
  
    List<Player> findByTeamId(long teamId);
}

TeamRepository

01
02
03
04
05
06
07
08
09
10
11
12
package com.programmer.gate.repository;
  
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
  
import com.programmer.gate.model.Team;
  
@Repository
public interface TeamRepository extends CrudRepository<Team, Long> {
  
    Team findByPlayers(long playerId);
}

7- Сервис

Теперь мы определяем наш класс обслуживания, который содержит бизнес-логику нашего приложения, наш сервис предоставляет 2 метода: getAllTeamPlayers () и addBarcelonaPlayer () ( просто переименуйте его в свой любимый клуб, если вам не нравится Барселона : D), наш уровень обслуживания напрямую связывается со слоем хранилища.

SoccerService.java

1
2
3
4
5
6
7
8
package com.programmer.gate.service;
  
import java.util.List;
  
public interface SoccerService {
    public List<String> getAllTeamPlayers(long teamId);
    public void addBarcelonaPlayer(String name, String position, int number);
}

SoccerServiceImpl

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.programmer.gate.service;
  
import java.util.ArrayList;
import java.util.List;
  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
  
import com.programmer.gate.model.Player;
import com.programmer.gate.model.Team;
import com.programmer.gate.repository.PlayerRepository;
import com.programmer.gate.repository.TeamRepository;
  
@Service
public class SoccerServiceImpl implements SoccerService {
  
    @Autowired
    private PlayerRepository playerRepository;
    @Autowired
    private TeamRepository teamRepository;
  
    public List<String> getAllTeamPlayers(long teamId) {
        List<String> result = new ArrayList<String>();
        List<Player> players = playerRepository.findByTeamId(teamId);
        for (Player player : players) {
            result.add(player.getName());
        }
  
        return result;
    }
  
    public void addBarcelonaPlayer(String name, String position, int number) {
         
        Team barcelona = teamRepository.findOne(1l);
         
        Player newPlayer = new Player();
        newPlayer.setName(name);
        newPlayer.setPosition(position);
        newPlayer.setNum(number);
        newPlayer.setTeam(barcelona);
        playerRepository.save(newPlayer);
    }
}

8- Application.java

Последний шаг — создание инициализатора Spring Boot, это точка входа нашего приложения. Мы определяем Application.java под com.programmer.gate.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.programmer.gate;
  
import java.util.List;
  
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
  
import com.programmer.gate.service.SoccerService;
  
@SpringBootApplication
public class Application implements CommandLineRunner{
     
    @Autowired
    SoccerService soccerService;
     
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
     
    @Override
    public void run(String... arg0) throws Exception {
         
        soccerService.addBarcelonaPlayer("Xavi Hernandez", "Midfielder", 6);
         
        List<String> players = soccerService.getAllTeamPlayers(1);
        for(String player : players)
        {
            System.out.println("Introducing Barca player => " + player);
        }
    }
}

PS: стоит упомянуть, что приложение Spring Boot автоматически считывает и создает сущности, репозитории и службы, определенные в том же самом или в подпакете, относительно того, где у вас есть класс инициализатора, поэтому, если мы определим Application.java в другом пакете, то нам нужно явно указать пакет модели, репозитория и сервиса.

Выход:

При запуске приложения в качестве стандартного Java-приложения мы получаем следующий вывод в консоли.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
2018-04-13 14:54:47 DEBUG org.hibernate.SQL - create sequence player_seq start with 1 increment by 1
2018-04-13 14:54:47 DEBUG org.hibernate.SQL - create sequence team_seq start with 1 increment by 1
2018-04-13 14:54:47 DEBUG org.hibernate.SQL - create table player (id number(19,0) not null, name varchar2(255 char), num number(10,0), position varchar2(255 char), team_id number(19,0) not null, primary key (id))
2018-04-13 14:54:47 DEBUG org.hibernate.SQL - create table team (id number(19,0) not null, name varchar2(255 char), primary key (id))
2018-04-13 14:54:47 DEBUG org.hibernate.SQL - alter table player add constraint FKdvd6ljes11r44igawmpm1mc5s foreign key (team_id) references team
2018-04-13 14:54:47 INFO  o.h.tool.hbm2ddl.SchemaExport - HHH000476: Executing import script '/import.sql'
2018-04-13 14:54:47 INFO  o.h.tool.hbm2ddl.SchemaExport - HHH000230: Schema export complete
2018-04-13 14:54:47 INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
2018-04-13 14:54:48 INFO  o.s.j.e.a.AnnotationMBeanExporter - Registering beans for JMX exposure on startup
2018-04-13 14:54:48 DEBUG org.hibernate.SQL - select team0_.id as id1_1_0_, team0_.name as name2_1_0_, players1_.team_id as team_id5_0_1_, players1_.id as id1_0_1_, players1_.id as id1_0_2_, players1_.name as name2_0_2_, players1_.num as num3_0_2_, players1_.position as position4_0_2_, players1_.team_id as team_id5_0_2_ from team team0_, player players1_ where team0_.id=players1_.team_id(+) and team0_.id=?
2018-04-13 14:54:48 DEBUG org.hibernate.SQL - select player_seq.nextval from dual
2018-04-13 14:54:48 DEBUG org.hibernate.SQL - insert into player (name, num, position, team_id, id) values (?, ?, ?, ?, ?)
2018-04-13 14:54:48 INFO  o.h.h.i.QueryTranslatorFactoryInitiator - HHH000397: Using ASTQueryTranslatorFactory
2018-04-13 14:54:48 DEBUG org.hibernate.SQL - select player0_.id as id1_0_, player0_.name as name2_0_, player0_.num as num3_0_, player0_.position as position4_0_, player0_.team_id as team_id5_0_ from player player0_, team team1_ where player0_.team_id=team1_.id(+) and team1_.id=?
  
Introducing Barca player => Lionel Messi
Introducing Barca player => Andreas Inniesta
Introducing Barca player => Pique
Introducing Barca player => Xavi Hernandez
  
2018-04-13 14:54:49 INFO  com.programmer.gate.Application - Started Application in 4.213 seconds (JVM running for 4.555)

9- Исходный код

Вы можете скачать исходный код из этого репозитория: spring-boot-jpa-hibernate

Опубликовано на Java Code Geeks с разрешения Хуссейна Терека, партнера нашей программы JCG . Смотреть оригинальную статью здесь: Spring Boot + JPA + Hibernate + Oracle

Мнения, высказанные участниками Java Code Geeks, являются их собственными.