Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save thergbway/d5360cfb96d5fc76f3265027860c68ca to your computer and use it in GitHub Desktop.
Save thergbway/d5360cfb96d5fc76f3265027860c68ca to your computer and use it in GitHub Desktop.
HIBERNATE&JPA. JPA HIBERNATE ELEMENTARY MAPPING
1. Для сущностей, хранящих большие объекты, выгодно использовать @SecondaryTable,
тк такие данные будут храниться отдельно
2. Записываемый в БД первичный ключ переприсвоить нельзя
3. Возможные типы @Id первичного ключа:
- примитивы: byte, short, int, long, char
- обертки: Byte, Short, Integer, Long, Character
- массивы вышеперечисленных примитивов или оберток: int[], Integer[]
- строки, числа и даты: String, BigInteger, java.util.Date, java.sql.Date
4. Возможные значения @GenerateValue:
- SEQUENCE. Использование SQL-последовательности БД
- IDENTITY. Использование столбца идентификаторов
- TABLE. Использовать последовательность, хранимую в специальной таблице
- AUTO. Использовать вариант по умолчанию
5. Составные ключи:
- помечаются @IdClass или @EmbeddedId(с @Embeddable)
- имеют переопределенный equals() и hashCode()
- типы такие же, как и у обычного @Id поля
- @IdClass лучше подходит для legacy классов, в остальных случаях лучще @EmbeddedId
- Должны быть Serializable
6: Возможные типы атрибутов сущностей:
- примитивы и обертки
- строки, большие числа, временные типы: String, BigInteger, BigDecimal, java.util.Date,
java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.Timestamp
- enum
- пользовательские Serializable типы
- коллекции базовых и встраиваемых типов
- другие сущности и их коллекции
7. @Basic:
- fetch() default EAGER. Can be set to Lazy
- optional() default true. Будет ли колонка помечена как NOT NULL или нет. Для примитивов игнорируется
8. @Lob. Следует помечать большие по размеру атрибуты, например, byte[]. Для них будут исп. особые вызовы JDBC.
Используется вместе с @Basic или @ElementCollection
9. @Column:
- name() default ""
- unique() default false
- nullable() default true
- insertable() default true. Не влияет на схему БД
- updatable() default true. Не влияет на схему БД
- columnDefinition() default ""
- table() default ""
- length() default 255
- precision() default 0
- scale() default 0
10. @Temporal. Для указания, как отображать java.util.Date и java.util.Calendar (только эти два класса).
Значения:
- DATE. Только дата
- TIME. Только время
- TIMESTAMP. Дата и время
11. @Transient и ключевое слово transient исключает данный атрибут сущности из отображения
12. Перечисления и @Enumerated.
Без указания какой-либо аннотации перечисления отображаются в БД на их порядковые номера. Это плохо, когда мы,
например, добавляем новый элемент перечисления в его начал (значения смещаются), поэтому стоит использовать
@Enumerated:
- ORDINAL. По умолчанию. Отображение перечисления в виде числа в БД. Использовать не стоит
- STRING. Лучшее решение. Отображение перечисления в виде строки в БД.
13. Типы доступа. Необходимо придерживаться одного типа доступа: по аттрибутам или по свойствам, те аннотировать
либо поля, либо геттеры. Смешивание ведет к неопределенному поведению. Для явного указания типа поступа следует
использовать @AccessType на классе, поле, методе с возможными значениями FIELD или PROPERTY.
Их смешивать также не стоит.
14. Для отображения коллекции используй @ElementCollection(обязательно) и @CollectionTable(опционально,указывает
таблицу для сохранения элементов коллекции). С помощью @Column можно указать имя столбца в таблице
15. При отображении Map используется те же аннотации, что и для коллекции плюс можно указать @MapKeyColumn для указания
названия ключа карты, иначе будет использовано имя по умолчанию
16. Встраиваемые объекты. Помечаются @Embeddable. Атрибуты таких объектов полностью отображаются для сущностей,
их использующих. Настоятельно рекомендуется явно задавать способ доступа у встраиваемых обектов(@Access), так как
если данный встраиваемый объект используют несколько сущностей с разным типом доступа, то могут возникнуть проблемы
с конечными отображениями использующих данный встраиваемый объект сущностей.
Встраиваемые объекты не могут иметь id, что очень логично
package map;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "address")//set custom table name
//some entity fields should be mapped in different tables
@SecondaryTables({
@SecondaryTable(name = "city"),
@SecondaryTable(name = "country")
})
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String building;
private String street;
@Column(table = "city")//specify table for column
private String state;
@Column(table = "city")
private String zipcode;
@Column(table = "country")
private String country;
}
package map.collection;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.Map;
import java.util.Set;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "tag")
@Column(name = "value")
private Set<String> tags;
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "chapter")//имя таблицы для коллекции
@MapKeyColumn(name = "page_number")//имя столбца для ключа
@Column(name = "title")//имя столбца для значения
private Map<Integer, String> chapters;
}
package map.embedded_object;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
@Access(AccessType.PROPERTY)
public class Description {
private String content;
@Temporal(TemporalType.TIMESTAMP)
private Date created_date;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ABSOLUTE} %5p %c{1}:%L - %m%n"/>
</layout>
</appender>
<!--Turn on your favourite loggers-->
<logger name="org.hibernate">
<level value="WARN"/><!--or DEBUG for more verbose logging-->
</logger>
<logger name="org.hibernate.SQL">
<level value="INFO"/>
</logger>
<root>
<level value="WARN"/>
<appender-ref ref="stdout"/>
</root>
</log4j:configuration>
package map;
import map.collection.Book;
import map.embedded_key_1.News;
import map.embedded_key_1.NewsId;
import map.embedded_key_2.Post;
import map.embedded_key_2.PostId;
import map.embedded_object.Description;
import map.embedded_object.Product;
import org.apache.log4j.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import static java.util.Objects.nonNull;
public class Main {
private static final Logger log = Logger.getLogger(Main.class);
public static void main(String[] args) {
EntityManagerFactory emf = null;
EntityManager em = null;
EntityTransaction tx = null;
try {
emf = Persistence.createEntityManagerFactory("hibernate-jpa-persistence-unit");
em = emf.createEntityManager();
tx = em.getTransaction();
tx.begin();
NewsId newsId = new NewsId("title1", "EN");
News news = new News(newsId, "content1");
Post post = new Post("100", "2", "post_content");
HashMap<Integer, String> chapters = new HashMap<>();
chapters.put(3, "Chapter 1");
chapters.put(5, "Chapter 2");
Book book = new Book(null, new HashSet<>(Arrays.asList("classic", "pictures")), chapters);
Product product = new Product(null, new Description("content", new Date()));
em.persist(post);
em.persist(news);
em.persist(book);
em.persist(product);
tx.commit();
tx = em.getTransaction();
tx.begin();
news = em.find(News.class, newsId);
post = em.find(Post.class, new PostId("100", "2"));
book = em.find(Book.class, book.getId());
product = em.find(Product.class, product.getId());
System.out.println(news);
System.out.println(post);
System.out.println(book);
System.out.println(product);
tx.commit();
} catch (Exception e) {
log.error("Got error!", e);
if (nonNull(tx) && tx.isActive())
tx.rollback();
} finally {
if (nonNull(em))
em.close();
if (nonNull(emf))
emf.close();
}
}
}
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="hibernate-jpa-persistence-unit">
<description>Persistence unit for the Hibernate JPA</description>
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>map.Address</class>
<class>map.embedded_key_1.NewsId</class>
<class>map.embedded_key_1.News</class>
<class>map.embedded_key_2.PostId</class>
<class>map.embedded_key_2.Post</class>
<class>map.embedded_object.Product</class>
<class>map.embedded_object.Description</class>
<class>map.collection.Book</class>
<class>map.SimpleEntity</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
</persistence>
package map.embedded_key_1;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class News {
@EmbeddedId
private NewsId id;
private String content;
}
package map.embedded_key_1;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Embeddable;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class NewsId implements Serializable {
private String title;
private String language;
}
<?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>org.thergbway</groupId>
<artifactId>mapping_elementary</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.192</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901-1.jdbc4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.20.0-GA</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.2.3.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.11</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>auto-clean</id>
<phase>initialize</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package map.embedded_key_2;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@IdClass(PostId.class)
public class Post {
@Id
private String code;
@Id
private String revision;
private String content;
}
package map.embedded_key_2;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
//Here is no any JPA annotations
public class PostId implements Serializable {
private String code;
private String revision;
}
package map.embedded_object;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
@Embedded
private Description description;
}
package map;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Access(AccessType.FIELD)//можно явно не указывать
public class SimpleEntity {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Integer id;
@Basic(
fetch = FetchType.LAZY,//not default EAGER
optional = false//mapped to NOT NULL column
)
private String name;
@Basic(fetch = FetchType.LAZY)
@Lob
private byte[] wavFileContent;
@Column(
name = "descr",
unique = true,//mapped to UNIQUE column
nullable = false,//mapped to NOT NULL column
insertable = false,
updatable = false,
length = 300
)
private String description;
@Temporal(TemporalType.DATE)
private Date creationDate;
@Transient
private Integer age;
@Enumerated(EnumType.STRING)//much better than ORDINAL
private CreditCardType creditCardType;
public enum CreditCardType {
VISA, MAESTRO, MIR
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment