"An Intro to Hibernate Entity Lifecycle"
"An Intro to Hibernate Entity Lifecycle" by Rudi
This commit is contained in:
parent
99676b1a9e
commit
413c02c078
|
@ -0,0 +1,26 @@
|
||||||
|
package com.baeldung.hibernate.lifecycle;
|
||||||
|
|
||||||
|
import org.hibernate.EmptyInterceptor;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DirtyDataInspector extends EmptyInterceptor {
|
||||||
|
private static final ArrayList<FootballPlayer> dirtyEntities = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
|
||||||
|
dirtyEntities.add((FootballPlayer) entity);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<FootballPlayer> getDirtyEntities() {
|
||||||
|
return dirtyEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearDirtyEntitites() {
|
||||||
|
dirtyEntities.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package com.baeldung.hibernate.lifecycle;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "Football_Player")
|
||||||
|
public class FootballPlayer {
|
||||||
|
@Id @GeneratedValue private long id;
|
||||||
|
|
||||||
|
@Column private String name;
|
||||||
|
|
||||||
|
@Column private String team;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTeam() {
|
||||||
|
return team;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTeam(String team) {
|
||||||
|
this.team = team;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return "FootballPlayer{" + "id=" + id + ", name='" + name + '\'' + ", team='" + team + '\'' + '}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
package com.baeldung.hibernate.lifecycle;
|
||||||
|
|
||||||
|
import org.h2.tools.RunScript;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.boot.Metadata;
|
||||||
|
import org.hibernate.boot.MetadataSources;
|
||||||
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
|
import org.hibernate.engine.spi.EntityEntry;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class HibernateUtil {
|
||||||
|
private static SessionFactory sessionFactory;
|
||||||
|
private static Connection connection;
|
||||||
|
|
||||||
|
public static void init() throws Exception {
|
||||||
|
Connection dbConnection = null;
|
||||||
|
Class.forName("org.h2.Driver");
|
||||||
|
|
||||||
|
connection = connection = DriverManager.getConnection("jdbc:h2:mem:lifecycledb;DB_CLOSE_DELAY=-1;", "sa", "");
|
||||||
|
File initFile = new File("src/test/resources/lifecycle-init.sql");
|
||||||
|
try(FileReader reader = new FileReader(initFile);) {
|
||||||
|
RunScript.execute(connection, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceRegistry serviceRegistry = configureServiceRegistry();
|
||||||
|
sessionFactory = getSessionFactoryBuilder(serviceRegistry).applyInterceptor(new DirtyDataInspector()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
sessionFactory.close();
|
||||||
|
connection.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SessionFactory getSessionFactory() {
|
||||||
|
return sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SessionFactoryBuilder getSessionFactoryBuilder(ServiceRegistry serviceRegistry) {
|
||||||
|
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
|
||||||
|
metadataSources.addAnnotatedClass(FootballPlayer.class);
|
||||||
|
|
||||||
|
Metadata metadata = metadataSources.buildMetadata();
|
||||||
|
return metadata.getSessionFactoryBuilder();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ServiceRegistry configureServiceRegistry() throws IOException {
|
||||||
|
Properties properties = getProperties();
|
||||||
|
return new StandardServiceRegistryBuilder().applySettings(properties).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Properties getProperties() throws IOException {
|
||||||
|
Properties properties = new Properties();
|
||||||
|
URL propertiesURL = Thread.currentThread().getContextClassLoader().getResource("hibernate-lifecycle.properties");
|
||||||
|
try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) {
|
||||||
|
properties.load(inputStream);
|
||||||
|
}
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<EntityEntry> getManagedEntities(Session session) {
|
||||||
|
Map.Entry<Object, EntityEntry>[] entries = ((SessionImplementor)session).getPersistenceContext().reentrantSafeEntityEntries();
|
||||||
|
return Arrays.asList(entries).stream().map(e -> e.getValue()).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Connection getDBConnection() throws Exception {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Transaction startTransaction(Session s) {
|
||||||
|
Transaction tx = s.getTransaction();
|
||||||
|
tx.begin();
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int queryCount(String query) throws Exception {
|
||||||
|
try(ResultSet rs = connection.createStatement().executeQuery(query);) {
|
||||||
|
rs.next();
|
||||||
|
return rs.getInt(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,166 @@
|
||||||
|
package com.baeldung.hibernate.lifecycle;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.engine.spi.Status;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static com.baeldung.hibernate.lifecycle.DirtyDataInspector.getDirtyEntities;
|
||||||
|
import static com.baeldung.hibernate.lifecycle.HibernateUtil.*;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class HibernateLifecycleUnitTest {
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setup() throws Exception {
|
||||||
|
HibernateUtil.init();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() throws Exception {
|
||||||
|
HibernateUtil.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void beforeMethod() {
|
||||||
|
DirtyDataInspector.clearDirtyEntitites();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenEntityLoaded_thenEntityManaged() throws Exception {
|
||||||
|
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||||
|
try(Session session = sessionFactory.openSession()) {
|
||||||
|
Transaction transaction = startTransaction(session);
|
||||||
|
|
||||||
|
assertThat(getManagedEntities(session)).isEmpty();
|
||||||
|
|
||||||
|
List<FootballPlayer> players = session.createQuery("from FootballPlayer").getResultList();
|
||||||
|
assertThat(getManagedEntities(session)).size().isEqualTo(3);
|
||||||
|
|
||||||
|
assertThat(getDirtyEntities()).isEmpty();
|
||||||
|
|
||||||
|
FootballPlayer gigiBuffon = players.stream()
|
||||||
|
.filter(p -> p.getId()==3)
|
||||||
|
.findFirst()
|
||||||
|
.get();
|
||||||
|
|
||||||
|
gigiBuffon.setName("Gianluigi Buffon");
|
||||||
|
transaction.commit();
|
||||||
|
|
||||||
|
assertThat(getDirtyEntities()).size().isEqualTo(1);
|
||||||
|
assertThat(getDirtyEntities().get(0).getId()).isEqualTo(3);
|
||||||
|
assertThat(getDirtyEntities().get(0).getName()).isEqualTo("Gianluigi Buffon");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenDetached_thenNotTracked() throws Exception {
|
||||||
|
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||||
|
try(Session session = sessionFactory.openSession()) {
|
||||||
|
Transaction transaction = startTransaction(session);
|
||||||
|
|
||||||
|
FootballPlayer cr7 = session.get(FootballPlayer.class, Long.valueOf(1));
|
||||||
|
assertThat(getManagedEntities(session)).size().isEqualTo(1);
|
||||||
|
assertThat(getManagedEntities(session).get(0).getId()).isEqualTo(cr7.getId());
|
||||||
|
|
||||||
|
session.evict(cr7);
|
||||||
|
assertThat(getManagedEntities(session)).size().isEqualTo(0);
|
||||||
|
|
||||||
|
cr7.setName("CR7");
|
||||||
|
transaction.commit();
|
||||||
|
|
||||||
|
assertThat(getDirtyEntities()).isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void whenReattached_thenTrackedAgain() throws Exception {
|
||||||
|
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||||
|
try(Session session = sessionFactory.openSession()) {
|
||||||
|
Transaction transaction = startTransaction(session);
|
||||||
|
|
||||||
|
FootballPlayer messi = session.get(FootballPlayer.class, Long.valueOf(2));
|
||||||
|
|
||||||
|
session.evict(messi);
|
||||||
|
messi.setName("Leo Messi");
|
||||||
|
transaction.commit();
|
||||||
|
assertThat(getDirtyEntities()).isEmpty();
|
||||||
|
|
||||||
|
transaction = startTransaction(session);
|
||||||
|
session.update(messi);
|
||||||
|
transaction.commit();
|
||||||
|
assertThat(getDirtyEntities()).size().isEqualTo(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenNewEntityWithID_whenReattached_thenManaged() throws Exception {
|
||||||
|
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Transaction transaction = startTransaction(session);
|
||||||
|
|
||||||
|
FootballPlayer gigi = new FootballPlayer();
|
||||||
|
gigi.setId(3);
|
||||||
|
gigi.setName("Gigi the Legend");
|
||||||
|
|
||||||
|
session.update(gigi);
|
||||||
|
assertThat(getManagedEntities(session)).size().isEqualTo(1);
|
||||||
|
|
||||||
|
transaction.commit();
|
||||||
|
assertThat(getDirtyEntities()).size().isEqualTo(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenTransientEntity_whenSave_thenManaged() throws Exception {
|
||||||
|
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Transaction transaction = startTransaction(session);
|
||||||
|
|
||||||
|
FootballPlayer neymar = new FootballPlayer();
|
||||||
|
neymar.setName("Neymar");
|
||||||
|
|
||||||
|
session.save(neymar);
|
||||||
|
assertThat(getManagedEntities(session)).size().isEqualTo(1);
|
||||||
|
assertThat(neymar.getId()).isNotNull();
|
||||||
|
|
||||||
|
int count = queryCount("select count(*) from Football_Player where name='Neymar'");
|
||||||
|
assertThat(count).isEqualTo(0);
|
||||||
|
|
||||||
|
transaction.commit();
|
||||||
|
|
||||||
|
count = queryCount("select count(*) from Football_Player where name='Neymar'");
|
||||||
|
assertThat(count).isEqualTo(1);
|
||||||
|
|
||||||
|
transaction = startTransaction(session);
|
||||||
|
session.delete(neymar);
|
||||||
|
transaction.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test()
|
||||||
|
public void whenDelete_thenMarkDeleted() throws Exception {
|
||||||
|
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
|
||||||
|
try (Session session = sessionFactory.openSession()) {
|
||||||
|
Transaction transaction = startTransaction(session);
|
||||||
|
|
||||||
|
FootballPlayer neymar = new FootballPlayer();
|
||||||
|
neymar.setName("Neymar");
|
||||||
|
|
||||||
|
session.save(neymar);
|
||||||
|
transaction.commit();
|
||||||
|
|
||||||
|
transaction = startTransaction(session);
|
||||||
|
session.delete(neymar);
|
||||||
|
assertThat(getManagedEntities(session).get(0).getStatus()).isEqualTo(Status.DELETED);
|
||||||
|
transaction.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
hibernate.connection.driver_class=org.h2.Driver
|
||||||
|
hibernate.connection.url=jdbc:h2:mem:lifecycledb;DB_CLOSE_DELAY=-1;
|
||||||
|
hibernate.connection.username=sa
|
||||||
|
hibernate.connection.autocommit=true
|
||||||
|
jdbc.password=
|
||||||
|
|
||||||
|
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
||||||
|
hibernate.show_sql=true
|
||||||
|
hibernate.hbm2ddl.auto=validate
|
|
@ -0,0 +1,26 @@
|
||||||
|
create sequence hibernate_sequence start with 1 increment by 1;
|
||||||
|
|
||||||
|
create table Football_Player (
|
||||||
|
id bigint not null,
|
||||||
|
team varchar(255),
|
||||||
|
name varchar(255),
|
||||||
|
primary key (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
insert into
|
||||||
|
Football_Player
|
||||||
|
(team, name, id)
|
||||||
|
values
|
||||||
|
('Juventus', 'Cristiano Ronaldo', next value for hibernate_sequence);
|
||||||
|
|
||||||
|
insert into
|
||||||
|
Football_Player
|
||||||
|
(team, name, id)
|
||||||
|
values
|
||||||
|
('Barcelona', 'Lionel Messi', next value for hibernate_sequence);
|
||||||
|
|
||||||
|
insert into
|
||||||
|
Football_Player
|
||||||
|
(team, name, id)
|
||||||
|
values
|
||||||
|
('PSG', 'Gigi Buffon', next value for hibernate_sequence);
|
Loading…
Reference in New Issue