"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 | ||||||
							
								
								
									
										26
									
								
								hibernate5/src/test/resources/lifecycle-init.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								hibernate5/src/test/resources/lifecycle-init.sql
									
									
									
									
									
										Normal file
									
								
							| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user