Spring Data JPA. Работа с БД. Часть 1 – Devcolibri – Android для начинающих

Spring Data JPA. Работа с БД. Часть 1

→ Spring Data JPA. Пишем DAO и Services. Часть 2
→ Spring Data JPA. JUnit тесты для Services. Часть 3

Spring – достаточно многофункциональный framework, и если вы надумали делать enterprise проект, то вам не обойтись без возможности работать с базами данных. В этой серии уроков, мы научимся работать с БД используя возможности Spring Data.

Шаг 0. Постановка задачи

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

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

Давайте посмотри на рисунок ниже:

Примерно так выглядит облегченная модель банковской системы.

Шаг 1. Моделируем ERD

Теперь нужно на основании построенной модели выше на изображении, смоделировать ERD диаграмму.

ERD (Entity-Relationship Diagram) – это отображение модели сущностей в базе данных. Попросту мы моделируем сущности (таблицы) базы данных для определенной модели.

Вот такая ERD получилась у меня для нашей модели Банковской Системы.

Для построения ERD я использую сервис lucidchart.com

Теперь немного разберем нашу ERD:

worker – таблица, которая будет хранить все сотрудников определенного банка.

bank – таблица, которая будет хранить банки системы.

client – таблица клиентов банка, или нескольких банков.

bank_of_account – таблица, которая будет хранить счета клиентов банка.

Как вы видите между таблицами есть связи, о них вы можете почитать тут – Как связать Entity в JPA?

Шаг 2. Создание проекта и добавление Dependencies

Создаем новый проект и называем его com.devcolibri.dataexam.

И 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.devcolibri.dataexam</groupId>
    <artifactId>com.devcolibri.dataexam</artifactId>
    <version>1.0</version>
    <packaging>war</packaging>

    <properties>
        <java.version>1.7</java.version>
        <spring.mvc>4.0.3.RELEASE</spring.mvc>
        <spring.data>1.3.4.RELEASE</spring.data>
        <javax.servlet>3.0.1</javax.servlet>
        <mysql.version>5.1.29</mysql.version>
        <hb.manager>4.2.5.Final</hb.manager>
        <spring.test>3.2.4.RELEASE</spring.test>
        <junit.version>4.11</junit.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.mvc}</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${javax.servlet}</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>${spring.data}</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hb.manager}</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.test}</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <finalName>devcolibri-dataexam</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Как вы уже могли заметить использую я MySQL поэтому и зависимость подключил именно для этой БД.

Если вы захотите использовать другую БД, то ничего вам не мешает поменять зависимость и данные в файле свойств.

Профессия Android разработчика Думаете, с какой профессией связать свою жизнь? Сделайте несколько шагов в сторону мобильной разработки бесплатно, а затем со скидкой 50% пройдите этот путь до конца.

Шаг 3. Конфигурация проекта

Теперь нам нужно сконфигурировать проект, а именно Spring Configuration.

Для начало посмотрите на текущую структуру проекта ниже и создайте себе такую же.

В resources есть файл app.properties в нем хранятся все свойства, необходимые проекта, в нашем случае это доступ к БД и т.п.

#DB properties:
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/testdb
db.username=root
db.password=root

#Hibernate Configuration:
db.hibernate.dialect=org.hibernate.dialect.MySQLDialect
db.hibernate.show_sql=true
db.entitymanager.packages.to.scan=com.devcolibri.dataexam.entity
db.hibernate.hbm2ddl.auto = create

Данные свойства мы будем использовать в конфигурации EntityManager ниже.

Теперь обратите своё внимание на пакет configuration, в класс AppInitializer добавим следующее содержимое:

package com.devcolibri.dataexam.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{
                DataConfig.class
        };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[0];
    }

    @Override
    protected String[] getServletMappings() {
        return new String[0];
    }
}

Я выделил 9-ю строку, так как в ней мы регистрируем конфигурацию необходимых нам бинов для работы с БД.

А теперь давайте создадим саму конфигурацию DataConfig, которая будет инлдектить JPA бины:

package com.devcolibri.dataexam.config;

import org.hibernate.ejb.HibernatePersistence;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
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.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.Properties;

@Configuration
@EnableTransactionManagement
@ComponentScan("com.devcolibri.dataexam")
@PropertySource("classpath:app.properties")
@EnableJpaRepositories("com.devcolibri.dataexam.repository")
public class DataConfig {

    private static final String PROP_DATABASE_DRIVER = "db.driver";
    private static final String PROP_DATABASE_PASSWORD = "db.password";
    private static final String PROP_DATABASE_URL = "db.url";
    private static final String PROP_DATABASE_USERNAME = "db.username";
    private static final String PROP_HIBERNATE_DIALECT = "db.hibernate.dialect";
    private static final String PROP_HIBERNATE_SHOW_SQL = "db.hibernate.show_sql";
    private static final String PROP_ENTITYMANAGER_PACKAGES_TO_SCAN = "db.entitymanager.packages.to.scan";
    private static final String PROP_HIBERNATE_HBM2DDL_AUTO = "db.hibernate.hbm2ddl.auto";

    @Resource
    private Environment env;

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(env.getRequiredProperty(PROP_DATABASE_DRIVER));
        dataSource.setUrl(env.getRequiredProperty(PROP_DATABASE_URL));
        dataSource.setUsername(env.getRequiredProperty(PROP_DATABASE_USERNAME));
        dataSource.setPassword(env.getRequiredProperty(PROP_DATABASE_PASSWORD));

        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource());
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistence.class);
        entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROP_ENTITYMANAGER_PACKAGES_TO_SCAN));

        entityManagerFactoryBean.setJpaProperties(getHibernateProperties());

        return entityManagerFactoryBean;
    }

    @Bean
    public JpaTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());

        return transactionManager;
    }

    private Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put(PROP_HIBERNATE_DIALECT, env.getRequiredProperty(PROP_HIBERNATE_DIALECT));
        properties.put(PROP_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROP_HIBERNATE_SHOW_SQL));
        properties.put(PROP_HIBERNATE_HBM2DDL_AUTO, env.getRequiredProperty(PROP_HIBERNATE_HBM2DDL_AUTO));

        return properties;
    }

}

В дальнейшем я еще буду ссылаться на конфигурацию выше, для разъяснения некоторых вещей с этой конфигурации.

Разберем аннотации:

@Configuration – говорит, что данный класс является Spring конфигурацией;

@EnableTransactionManagement – включает TransactionManager для управления транзакциями БД;

@ComponentScan(“com.devcolibri.dataexam”) – указываем Spring где нужно искать Entity, DAO, Service и т.п.;

@PropertySource(“classpath:app.properties”) – подключаем файл свойств созданный выше;

@EnableJpaRepositories(“com.devcolibri.dataexam.repository”) – включаем возможность использования JPARepository и говорим, где их искать. (будем рассматривать позже детальней).

private Environment env;

В нашем случае нужен для возможности получать свойства из property файла.

Шаг 4. Создаем Entity на основе нашей ERD диаграммы

Начнем с Банка (Bank):

package com.devcolibri.dataexam.entity;

import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;

@Entity
@Table(name = "bank")
public class Bank {

    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name= "increment", strategy= "increment")
    @Column(name = "id", length = 6, nullable = false)
    private long id;

    @Column(name = "name")
    private String name;

    public Bank() {
    }

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

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Подробней о JPA можно почитать тут.

Теперь создаем BankAccount:

package com.devcolibri.dataexam.entity;

import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;

@Entity
@Table(name = "bank_account")
public class BankAccount {

    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name= "increment", strategy= "increment")
    @Column(name = "id", length = 6, nullable = false)
    private long id;

    @Column(name = "currency")
    private double currency;

    @Column(name = "amount")
    private double amount;

    @Column(name = "amount_of_credit")
    private double amountOfCredit;

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    @JoinColumn(name = "client_id", nullable = false)
    private Client client;

    public BankAccount() {
    }

    public BankAccount(double currency, double amount, double amountOfCredit, Client client) {
        this.currency = currency;
        this.amount = amount;
        this.amountOfCredit = amountOfCredit;
        this.client = client;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public double getCurrency() {
        return currency;
    }

    public void setCurrency(double currency) {
        this.currency = currency;
    }

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    public double getAmountOfCredit() {
        return amountOfCredit;
    }

    public void setAmountOfCredit(double amountOfCredit) {
        this.amountOfCredit = amountOfCredit;
    }

    public Client getClient() {
        return client;
    }

    public void setClient(Client client) {
        this.client = client;
    }

}

Как вы уже заметили BankAccount использует Client, поэтому создаем Client entity:

package com.devcolibri.dataexam.entity;

import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;

@Entity
@Table(name = "client")
public class Client {

    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name= "increment", strategy= "increment")
    @Column(name = "id", length = 6, nullable = false)
    private long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "phone_number")
    private String phoneNumber;

    @Column(name = "address")
    private String address;

    @Column(name = "email")
    private String email;

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    @JoinColumn(name = "bank_id", nullable = false)
    private Bank bank;

    public Client(String firstName, String lastName, String phoneNumber,
                  String address, String email, Bank bank) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.phoneNumber = phoneNumber;
        this.address = address;
        this.email = email;
        this.bank = bank;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Bank getBank() {
        return bank;
    }

    public void setBank(Bank bank) {
        this.bank = bank;
    }
}

Ну и рабочие (Worker):

package com.devcolibri.dataexam.entity;

import com.devcolibri.dataexam.entity.enums.WorkerStatus;
import org.hibernate.annotations.GenericGenerator;

import javax.persistence.*;

@Entity
@Table(name = "worker")
public class Worker {

    @Id
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name= "increment", strategy= "increment")
    @Column(name = "id", length = 6, nullable = false)
    private long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "status")
    private WorkerStatus status;

    @Column(name = "phone_number")
    private String phoneNumber;

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST})
    @JoinColumn(name = "bank_id", nullable = false)
    private Bank bank;

    public Worker() {
    }

    public Worker(String firstName, String lastName, WorkerStatus status, String phoneNumber, Bank bank) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.status = status;
        this.phoneNumber = phoneNumber;
        this.bank = bank;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public WorkerStatus getStatus() {
        return status;
    }

    public void setStatus(WorkerStatus status) {
        this.status = status;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public Bank getBank() {
        return bank;
    }

    public void setBank(Bank bank) {
        this.bank = bank;
    }

}

У каждого рабочего есть своя должность, эти должности мы положим в enum WorkerStatus:

package com.devcolibri.dataexam.entity.enums;

public enum WorkerStatus {
    MANAGER;
}

Как работать с Enums в JPA я показывал тут.

Профессия Android разработчика Думаете, с какой профессией связать свою жизнь? Сделайте несколько шагов в сторону мобильной разработки бесплатно, а затем со скидкой 50% пройдите этот путь до конца.

Дальше мы будем создавать DAO и Сервисы.

→ Spring Data JPA. Пишем DAO и Services. Часть 2
→ Spring Data JPA. JUnit тесты для Services. Часть 3

Также читайте: «Быстрый старт в Spring Security»

ПОХОЖИЕ ПУБЛИКАЦИИ

    None Found

166536
22/03/2014

18 комментариев к статье "Spring Data JPA. Работа с БД. Часть 1"

Добавить комментарий

Сайт использует cookie-файлы для того, чтобы вам было удобнее им пользоваться. Для продолжения работы с сайтом, вам необходимо принять использование cookie-файлов.

Я ознакомлен(а)