├── .gitignore ├── LICENSE ├── README.md ├── ant-bytecode-enhance ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── vladmihalcea │ │ └── hibernate │ │ └── masterclass │ │ └── laboratory │ │ └── flushing │ │ └── EnhancedOrderLine.java │ └── test │ ├── java │ └── com │ │ └── vladmihalcea │ │ └── hibernate │ │ └── masterclass │ │ └── laboratory │ │ └── flushing │ │ └── AntBytecodeEnhancedTest.java │ └── resources │ └── logback.xml ├── core ├── pom.xml └── src │ └── test │ ├── java │ └── com │ │ └── vladmihalcea │ │ └── hibernate │ │ └── masterclass │ │ └── laboratory │ │ ├── batch │ │ ├── CustomFetchSizeFetchingTest.java │ │ ├── DefaultDialectBatchingTest.java │ │ ├── DefaultDialectOrderedBatchingTest.java │ │ ├── DefaultDialectOrderedVersionedBatchingTest.java │ │ ├── NoBatchingTest.java │ │ ├── NoFetchingTest.java │ │ ├── SqlCascadeDeleteBatchingTest.java │ │ └── TunedBatchInsertTest.java │ │ ├── cache │ │ ├── CollectionCacheTest.java │ │ ├── L2InheritanceTest.java │ │ ├── NonStrictReadWriteCacheConcurrencyStrategyWithConcurrentUpdateTest.java │ │ ├── QueryCacheTest.java │ │ ├── ReadOnlyCacheConcurrencyStrategyCollectionsTest.java │ │ ├── ReadOnlyCacheConcurrencyStrategyReferenceEntitiesTest.java │ │ ├── ReadOnlyCacheConcurrencyStrategyTest.java │ │ ├── ReadWriteCacheConcurrencyStrategyTest.java │ │ └── ReadWriteCacheConcurrencyStrategyWithLockTimeoutTest.java │ │ ├── cascade │ │ ├── ManyToManyCascadeAllBothSidesTest.java │ │ ├── ManyToManyCascadeAllParentSideTest.java │ │ ├── ManyToManyCascadeDissociationTest.java │ │ ├── OneToManyCascadeTest.java │ │ └── OneToOneCascadeTest.java │ │ ├── concurrency │ │ ├── AbstractEntityOptimisticLockingCollectionTest.java │ │ ├── AbstractLockModeOptimisticTest.java │ │ ├── CascadeLockTest.java │ │ ├── EntityFirstLevelCacheReuseTest.java │ │ ├── EntityOptimisticLockingOnBidirectionalChildOwningCollectionTest.java │ │ ├── EntityOptimisticLockingOnBidirectionalParentOwningCollectionTest.java │ │ ├── EntityOptimisticLockingOnComponentCollectionTest.java │ │ ├── EntityOptimisticLockingOnUnidirectionalCollectionTest.java │ │ ├── EntityOptimisticLockingOverruleOnBidirectionalParentOwningCollectionTest.java │ │ ├── LockModeOptimisticForceIncrementTest.java │ │ ├── LockModeOptimisticRaceConditionTest.java │ │ ├── LockModeOptimisticTest.java │ │ ├── LockModeOptimisticWithPessimisticLockUpgradeTest.java │ │ ├── LockModePessimisticForceIncrementTest.java │ │ ├── LockModePessimisticReadWriteIntegrationTest.java │ │ ├── OptimisticLockingOneRootDirtyVersioningTest.java │ │ ├── OptimisticLockingOneRootEntityMultipleVersionsTest.java │ │ ├── OptimisticLockingOneRootOneVersionTest.java │ │ └── OptimisticLockingVersionlessTest.java │ │ ├── entityidentifier │ │ ├── EntityAttribute.java │ │ ├── EntityEvent.java │ │ ├── EntityIdentifier.java │ │ ├── EntityIdentifierTest.java │ │ └── Product.java │ │ ├── fetch │ │ ├── HibernateApiFetchStrategyTest.java │ │ └── HibernateApiMultiEagerCollectionFetchStrategyTest.java │ │ ├── flushing │ │ ├── AutoDirtyCheckingTest.java │ │ ├── CustomEntityDirtinessStrategyTest.java │ │ ├── DirtyAware.java │ │ ├── FlushTypeTest.java │ │ ├── InterceptorDirtyCheckingTest.java │ │ ├── MergeWithTransientOnInverseSideTest.java │ │ ├── OrderLine.java │ │ ├── Product.java │ │ ├── SelfDirtyCheckingEntity.java │ │ ├── User.java │ │ └── package-info.java │ │ ├── idgenerator │ │ ├── AbstractPooledSequenceIdentifierTest.java │ │ ├── AssignedTableGenerator.java │ │ ├── AutoIdentifierMySQLTest.java │ │ ├── EnhancedSequenceVsTableGeneratorTest.java │ │ ├── HiloIdentifierTest.java │ │ ├── Identifiable.java │ │ ├── IdentityVsSequenceIdentifierTest.java │ │ ├── PooledLoSequenceIdentifierTest.java │ │ ├── PooledSequenceIdentifierTest.java │ │ ├── PostgreSQLAutoTest.java │ │ ├── SequenceVsTableGeneratorTest.java │ │ └── UUIDIdentifierTest.java │ │ ├── inheritance │ │ ├── InheritanceGroupByTest.java │ │ ├── OverrideIdentifierDefinitionTest.java │ │ └── TreeTest.java │ │ ├── jpa │ │ ├── EntityGraphMapperTest.java │ │ └── RuntimeProxyDirtyCheckingTest.java │ │ ├── mapping │ │ ├── BidirectionalOneToOneMapsIdTest.java │ │ ├── CompositeIdWithManyToOneTest.java │ │ ├── ElementCollectionTest.java │ │ ├── IndexOverrideTest.java │ │ ├── ManyToManyWithElementCollectionTest.java │ │ └── OneTableMultipleEntitiesTest.java │ │ ├── testenv │ │ ├── AbstractConnectionProviderTest.java │ │ ├── DriverConnectionProviderTest.java │ │ ├── ExternalDataSourceConnectionProviderTest.java │ │ ├── InternalDataSourceConnectionProviderTest.java │ │ ├── SecurityId.java │ │ ├── TransactionIsolationDriverConnectionProviderTest.java │ │ ├── TransactionIsolationExternalDataSourceConnectionProviderTest.java │ │ ├── TransactionIsolationExternalDataSourceExternalconfgiurationConnectionProviderTest.java │ │ └── TransactionIsolationInternalC3P0ConnectionProviderTest.java │ │ ├── type │ │ └── PostgreQuoteStringTest.java │ │ └── util │ │ ├── AbstractJPATest.java │ │ ├── AbstractMySQLIntegrationTest.java │ │ ├── AbstractOracleXEIntegrationTest.java │ │ ├── AbstractPostgreSQLIntegrationTest.java │ │ ├── AbstractSQLServerIntegrationTest.java │ │ ├── AbstractTest.java │ │ ├── DataSourceProviderIntegrationTest.java │ │ ├── EntityProvider.java │ │ ├── PersistenceUnitInfoImpl.java │ │ └── providers │ │ └── BlogEntityProvider.java │ └── resources │ ├── META-INF │ └── persistence.xml │ ├── OracleLog.properties │ └── logback.xml ├── docs └── draw │ ├── CacheAside.graphml │ ├── CacheAside.png │ ├── CacheReadThrough.graphml │ ├── CacheReadThrough.png │ ├── CacheWriteBehind.graphml │ ├── CacheWriteBehind.png │ ├── CacheWriteThrough.graphml │ ├── CacheWriteThrough.png │ ├── CollectionCacheRepositoryCommitChange.png │ ├── DefaultFlushEventFlow.graphml │ ├── DefaultFlushEventFlow.png │ ├── DistributedCacheNodes.graphml │ ├── DistributedCacheNodes.png │ ├── EllementCollectionPatchChange.png │ ├── FlexyPoolConnectionProxyDecorator.png │ ├── FlushAUTOEntities.png │ ├── HibernateEntityStates.png │ ├── HibernateJDBCBatchBenchmark.png │ ├── MultipleCacheNodes.graphml │ ├── MultipleCacheNodes.png │ ├── NonStrictReadWriteCacheConcurrencyStrategy.graphml │ ├── NonStrictReadWriteCacheConcurrencyStrategy.png │ ├── PooledLoOptimizer.graphml │ ├── PooledLoOptimizer.png │ ├── PooledOptimizer.graphml │ ├── PooledOptimizer.png │ ├── PostAuthorQueryCache.png │ ├── PostCommentDetailsBatchDelete.png │ ├── PostCommentDetailsLockCascade.png │ ├── PostCommentDetailsSecondLevelCache.png │ ├── PostCommentFetchSize.png │ ├── PostCommentJdbcBatch.png │ ├── ProductOrderLineOptimisticLockMode.png │ ├── ReadWriteCacheConcurrencyStrategy_Delete.graphml │ ├── ReadWriteCacheConcurrencyStrategy_Delete.png │ ├── ReadWriteCacheConcurrencyStrategy_Update.graphml │ ├── ReadWriteCacheConcurrencyStrategy_Update.png │ ├── RepositoryCommitChangeOptimisticForceIncrement.png │ ├── RepositoryCommitChangeReadOnlyCacheConcurrencyStrategy.png │ ├── SingleCacheNode.graphml │ ├── SingleCacheNode.png │ ├── TransactionalXACacheConcurrencyStrategy.graphml │ ├── TransactionalXACacheConcurrencyStrategy.png │ ├── TransactionalXAStrictCacheConcurrencyStrategy.graphml │ ├── TransactionalXAStrictCacheConcurrencyStrategy.png │ ├── entityStates.graphml │ ├── entityStates.png │ ├── hi-lo.graphml │ ├── hi_lo_algorithm.png │ ├── hibernate-entity-states.graphml │ ├── hibernate-entity-states.png │ ├── jpa-entity-states.graphml │ ├── jpa-entity-states.jpg │ └── jpa-entity-states.png ├── maven-bytecode-enhance ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── vladmihalcea │ │ └── hibernate │ │ └── masterclass │ │ └── laboratory │ │ └── flushing │ │ └── EnhancedOrderLine.java │ └── test │ ├── java │ └── com │ │ └── vladmihalcea │ │ └── hibernate │ │ └── masterclass │ │ └── laboratory │ │ └── flushing │ │ └── BytecodeEnhancedTest.java │ └── resources │ └── logback.xml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | *.iml 11 | .idea/ 12 | target/ 13 | 14 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 15 | hs_err_pid* 16 | 17 | # Eclipse IDE 18 | .project 19 | .classpath 20 | .settings/ 21 | -------------------------------------------------------------------------------- /ant-bytecode-enhance/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | com.vladmihalcea 8 | hibernate-master-class-parent 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 4.0.0 13 | 14 | hibernate-master-class-ant-bytecode-enhance 15 | 16 | 17 | 18 | 19 | org.hibernate.javax.persistence 20 | hibernate-jpa-2.1-api 21 | 1.0.0.Final 22 | 23 | 24 | 25 | 26 | com.vladmihalcea 27 | hibernate-master-class-core 28 | 1.0-SNAPSHOT 29 | test-jar 30 | test 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | maven-antrun-plugin 39 | 40 | 41 | Instrument domain classes 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | process-classes 59 | 60 | run 61 | 62 | 63 | 64 | 65 | 66 | org.hibernate 67 | hibernate-core 68 | ${hibernate.version} 69 | 70 | 71 | 72 | org.javassist 73 | javassist 74 | ${javassist.version} 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /ant-bytecode-enhance/src/main/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/EnhancedOrderLine.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import javax.persistence.*; 4 | import java.util.Date; 5 | 6 | /** 7 | * Order - Order 8 | * 9 | * @author Vlad Mihalcea 10 | */ 11 | @Entity 12 | public class EnhancedOrderLine { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.AUTO) 16 | private Long id; 17 | 18 | private Long number; 19 | 20 | private String orderedBy; 21 | 22 | private Date orderedOn; 23 | 24 | public Long getId() { 25 | return id; 26 | } 27 | 28 | public Long getNumber() { 29 | return number; 30 | } 31 | 32 | public void setNumber(Long number) { 33 | this.number = number; 34 | } 35 | 36 | public String getOrderedBy() { 37 | return orderedBy; 38 | } 39 | 40 | public void setOrderedBy(String orderedBy) { 41 | this.orderedBy = orderedBy; 42 | } 43 | 44 | public Date getOrderedOn() { 45 | return orderedOn; 46 | } 47 | 48 | public void setOrderedOn(Date orderedOn) { 49 | this.orderedOn = orderedOn; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ant-bytecode-enhance/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/AntBytecodeEnhancedTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.junit.Test; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * AntBytecodeEnhancedTest - Test to check auto dirty checking capabilities 11 | * 12 | * @author Vlad Mihalcea 13 | */ 14 | public class AntBytecodeEnhancedTest 15 | extends AbstractTest { 16 | 17 | @Override 18 | protected Class[] entities() { 19 | return new Class[] { 20 | EnhancedOrderLine.class 21 | }; 22 | } 23 | 24 | @Test 25 | public void testDirtyChecking() { 26 | doInTransaction(session -> { 27 | EnhancedOrderLine orderLine = new EnhancedOrderLine(); 28 | orderLine.setNumber(987L); 29 | orderLine.setOrderedBy("System"); 30 | orderLine.setOrderedOn(new Date()); 31 | session.persist(orderLine); 32 | session.flush(); 33 | orderLine.setNumber(123L); 34 | orderLine.setOrderedBy("Vlad"); 35 | orderLine.setOrderedOn(new Date()); 36 | session.flush(); 37 | orderLine.setOrderedBy("Alex"); 38 | return null; 39 | 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ant-bytecode-enhance/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DEBUG 5 | 6 | target/test.log 7 | false 8 | 9 | %-5p [%t]: %c{1} - %m%n 10 | UTF-8 11 | 12 | 13 | 14 | 15 | DEBUG 16 | 17 | 18 | %-5p [%t]: %c{1} - %m%n 19 | UTF-8 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | com.vladmihalcea 8 | hibernate-master-class-parent 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 4.0.0 13 | 14 | hibernate-master-class-core 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | org.apache.maven.plugins 24 | maven-jar-plugin 25 | 2.4 26 | 27 | 28 | 29 | test-jar 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/batch/CustomFetchSizeFetchingTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.batch; 2 | 3 | import java.util.Properties; 4 | 5 | /** 6 | * CustomFetchSizeFetchingTest - Test to check custom fetch_size 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | public class CustomFetchSizeFetchingTest extends NoFetchingTest { 11 | 12 | @Override 13 | protected Properties getProperties() { 14 | Properties properties = super.getProperties(); 15 | properties.put("hibernate.jdbc.fetch_size", fetchSize()); 16 | return properties; 17 | } 18 | 19 | protected int fetchSize() { 20 | return 10; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/batch/DefaultDialectBatchingTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.batch; 2 | 3 | import java.util.Properties; 4 | 5 | /** 6 | * DefaultDialectBatchingTest - Test to check the default dialect hibernate.jdbc.batch_size 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | public class DefaultDialectBatchingTest extends NoBatchingTest { 11 | 12 | @Override 13 | protected Properties getProperties() { 14 | Properties properties = super.getProperties(); 15 | properties.put("hibernate.jdbc.batch_size", String.valueOf(batchSize())); 16 | return properties; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/batch/DefaultDialectOrderedBatchingTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.batch; 2 | 3 | import java.util.Properties; 4 | 5 | /** 6 | * DefaultDialectOrderedBatchingTest - Test to check ordered inserts and updates batching 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | public class DefaultDialectOrderedBatchingTest extends DefaultDialectBatchingTest { 11 | 12 | @Override 13 | protected Properties getProperties() { 14 | Properties properties = super.getProperties(); 15 | properties.put("hibernate.order_inserts", "true"); 16 | properties.put("hibernate.order_updates", "true"); 17 | return properties; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/batch/DefaultDialectOrderedVersionedBatchingTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.batch; 2 | 3 | import java.util.Properties; 4 | 5 | /** 6 | * DefaultDialectOrderedVersionedBatchingTest - Test to check ordered inserts and updates and data versioned batching 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | public class DefaultDialectOrderedVersionedBatchingTest extends DefaultDialectOrderedBatchingTest { 11 | 12 | @Override 13 | protected Properties getProperties() { 14 | Properties properties = super.getProperties(); 15 | properties.put("hibernate.jdbc.batch_versioned_data", "true"); 16 | return properties; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/batch/TunedBatchInsertTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.batch; 2 | 3 | import java.util.Properties; 4 | 5 | /** 6 | * TunedBatchSizeTest - Test to check hibernate.jdbc.batch_size 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | public class TunedBatchInsertTest extends DefaultDialectOrderedVersionedBatchingTest { 11 | 12 | protected int batchSize() { 13 | return 50; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/cache/L2InheritanceTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.cache; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.annotations.Proxy; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | /** 12 | * L2InheritanceTest - Test to prove the solution for http://stackoverflow.com/questions/32829276/hibernate-inheritance-and-l2-cache/32902873#32902873 13 | * 14 | * @author Vlad Mihalcea 15 | */ 16 | public class L2InheritanceTest extends AbstractTest { 17 | 18 | @Override 19 | protected Class[] entities() { 20 | return new Class[]{ 21 | EntityBase.class, 22 | EntityA.class, 23 | EntityB.class, 24 | HolderEntity.class, 25 | }; 26 | } 27 | 28 | @Test 29 | public void testSequenceIdentifierGenerator() { 30 | doInTransaction(session -> { 31 | EntityA entityA = new EntityA(); 32 | session.persist(entityA); 33 | HolderEntity holderEntity = new HolderEntity(); 34 | holderEntity.setHoldedEntity(entityA); 35 | session.persist(holderEntity); 36 | session.flush(); 37 | }); 38 | 39 | doInTransaction(session -> { 40 | HolderEntity o = (HolderEntity) session.get(HolderEntity.class, 1);// loads from L2 cache 41 | assertEquals(EntityA.class, o.getHoldedEntity().getClass()); 42 | }); 43 | } 44 | 45 | @Entity(name = "EntityBase") 46 | @Inheritance(strategy = InheritanceType.SINGLE_TABLE) 47 | @DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING) 48 | @Proxy(lazy = false) 49 | static abstract class EntityBase { 50 | @Id 51 | @GeneratedValue(strategy = GenerationType.AUTO) 52 | @Column 53 | private int id; 54 | } 55 | 56 | @Entity 57 | @DiscriminatorValue("EntityA") 58 | @Cacheable 59 | static class EntityA extends EntityBase { 60 | @Column 61 | private int aColumn; 62 | 63 | public int getAColumn() { 64 | return aColumn; 65 | } 66 | 67 | public void setAColumn(int aColumn) { 68 | this.aColumn = aColumn; 69 | } 70 | } 71 | 72 | @Entity 73 | @DiscriminatorValue("EntityB") 74 | @Cacheable 75 | static class EntityB extends EntityBase { 76 | @Column 77 | private int bColumn; 78 | 79 | public int getBColumn() { 80 | return bColumn; 81 | } 82 | 83 | public void setBColumn(int bColumn) { 84 | this.bColumn = bColumn; 85 | } 86 | } 87 | 88 | @Entity(name = "HolderEntity") 89 | @Cacheable 90 | static class HolderEntity { 91 | @Id 92 | @GeneratedValue(strategy = GenerationType.AUTO) 93 | @Column 94 | private int id; 95 | 96 | @ManyToOne(fetch = FetchType.LAZY) 97 | EntityBase holdedEntity; 98 | 99 | public EntityBase getHoldedEntity() { 100 | return holdedEntity; 101 | } 102 | 103 | public void setHoldedEntity(EntityBase holdedEntity) { 104 | this.holdedEntity = holdedEntity; 105 | } 106 | 107 | public int getId() { 108 | return id; 109 | } 110 | 111 | public void setId(int id) { 112 | this.id = id; 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/cache/NonStrictReadWriteCacheConcurrencyStrategyWithConcurrentUpdateTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.cache; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractPostgreSQLIntegrationTest; 4 | import org.hibernate.EmptyInterceptor; 5 | import org.hibernate.Interceptor; 6 | import org.hibernate.Session; 7 | import org.hibernate.Transaction; 8 | import org.hibernate.annotations.CacheConcurrencyStrategy; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import javax.persistence.Entity; 13 | import javax.persistence.GeneratedValue; 14 | import javax.persistence.GenerationType; 15 | import javax.persistence.Id; 16 | import java.util.Properties; 17 | import java.util.concurrent.CountDownLatch; 18 | import java.util.concurrent.atomic.AtomicBoolean; 19 | 20 | import static org.junit.Assert.assertFalse; 21 | import static org.junit.Assert.assertTrue; 22 | 23 | 24 | /** 25 | * NonStrictReadWriteCacheConcurrencyStrategyWithConcurrentUpdateTest - Test to check CacheConcurrencyStrategy.NONSTRICT_READ_WRITE 26 | * 27 | * @author Vlad Mihalcea 28 | */ 29 | public class NonStrictReadWriteCacheConcurrencyStrategyWithConcurrentUpdateTest extends AbstractPostgreSQLIntegrationTest { 30 | 31 | @Override 32 | protected Class[] entities() { 33 | return new Class[] { 34 | Repository.class 35 | }; 36 | } 37 | 38 | private AtomicBoolean applyInterceptor = new AtomicBoolean(); 39 | 40 | private final CountDownLatch endLatch = new CountDownLatch(1); 41 | 42 | private class BobTransaction extends EmptyInterceptor { 43 | @Override 44 | public void beforeTransactionCompletion(Transaction tx) { 45 | if(applyInterceptor.get()) { 46 | LOGGER.info("Fetch Repository from another transaction"); 47 | assertFalse(getSessionFactory().getCache() 48 | .containsEntity(Repository.class, 1L)); 49 | executeSync(() -> { 50 | Session _session = getSessionFactory().openSession(); 51 | Repository repository = (Repository) 52 | _session.get(Repository.class, 1L); 53 | LOGGER.info("Cached Repository from Bob's transaction {}", 54 | repository); 55 | _session.close(); 56 | endLatch.countDown(); 57 | }); 58 | assertTrue(getSessionFactory().getCache() 59 | .containsEntity(Repository.class, 1L)); 60 | } 61 | } 62 | } 63 | 64 | @Override 65 | protected Interceptor interceptor() { 66 | return new BobTransaction(); 67 | } 68 | 69 | @Override 70 | protected Properties getProperties() { 71 | Properties properties = super.getProperties(); 72 | properties.put("hibernate.cache.use_second_level_cache", Boolean.TRUE.toString()); 73 | properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory"); 74 | return properties; 75 | } 76 | 77 | @Before 78 | public void init() { 79 | super.init(); 80 | doInTransaction(session -> { 81 | Repository repository = new Repository("Hibernate-Master-Class"); 82 | session.persist(repository); 83 | }); 84 | } 85 | 86 | @Test 87 | public void testRepositoryEntityUpdate() throws InterruptedException { 88 | doInTransaction(session -> { 89 | LOGGER.info("Load and modify Repository"); 90 | Repository repository = (Repository) 91 | session.get(Repository.class, 1L); 92 | assertTrue(getSessionFactory().getCache() 93 | .containsEntity(Repository.class, 1L)); 94 | repository.setName("High-Performance Hibernate"); 95 | applyInterceptor.set(true); 96 | }); 97 | endLatch.await(); 98 | assertFalse(getSessionFactory().getCache() 99 | .containsEntity(Repository.class, 1L)); 100 | doInTransaction(session -> { 101 | applyInterceptor.set(false); 102 | Repository repository = (Repository) 103 | session.get(Repository.class, 1L); 104 | LOGGER.info("Cached Repository {}", repository); 105 | }); 106 | } 107 | 108 | /** 109 | * Repository - Repository 110 | * 111 | * @author Vlad Mihalcea 112 | */ 113 | @Entity(name = "repository") 114 | @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) 115 | public static class Repository { 116 | 117 | @Id 118 | @GeneratedValue(strategy = GenerationType.AUTO) 119 | private Long id; 120 | 121 | private String name; 122 | 123 | public Repository() { 124 | } 125 | 126 | public Repository(String name) { 127 | this.name = name; 128 | } 129 | 130 | public String getName() { 131 | return name; 132 | } 133 | 134 | public void setName(String name) { 135 | this.name = name; 136 | } 137 | 138 | public Long getId() { 139 | return id; 140 | } 141 | 142 | public void setId(Long id) { 143 | this.id = id; 144 | } 145 | 146 | @Override 147 | public String toString() { 148 | return "Repository{" + 149 | "id=" + id + 150 | ", name='" + name + '\'' + 151 | '}'; 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/cache/ReadOnlyCacheConcurrencyStrategyReferenceEntitiesTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.cache; 2 | 3 | import java.util.Properties; 4 | 5 | 6 | /** 7 | * ReadOnlyCacheConcurrencyStrategyTest - Test to check CacheConcurrencyStrategy.READ_ONLY 8 | * with hibernate.cache.use_reference_entries doesn't work because Commit has a collection of CommitChanges 9 | * 10 | * @author Vlad Mihalcea 11 | */ 12 | public class ReadOnlyCacheConcurrencyStrategyReferenceEntitiesTest extends ReadOnlyCacheConcurrencyStrategyTest { 13 | 14 | @Override 15 | protected Properties getProperties() { 16 | Properties properties = super.getProperties(); 17 | properties.put("hibernate.cache.use_second_level_cache", Boolean.TRUE.toString()); 18 | properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory"); 19 | properties.put("hibernate.cache.use_reference_entries", Boolean.TRUE.toString()); 20 | return properties; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/cascade/ManyToManyCascadeAllBothSidesTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.cascade; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertNull; 13 | 14 | 15 | /** 16 | * OneToOneCascadeTest - Test to check @OneToOne Cascading 17 | * 18 | * @author Vlad Mihalcea 19 | */ 20 | public class ManyToManyCascadeAllBothSidesTest extends AbstractTest { 21 | 22 | @Override 23 | protected Class[] entities() { 24 | return new Class[]{ 25 | Book.class, 26 | Author.class 27 | }; 28 | } 29 | 30 | public void addBooks() { 31 | doInTransaction(session -> { 32 | Author _John_Smith = new Author("John Smith"); 33 | Author _Michelle_Diangello = new Author("Michelle Diangello"); 34 | Author _Mark_Armstrong = new Author("Mark Armstrong"); 35 | 36 | Book _Day_Dreaming = new Book("Day Dreaming"); 37 | Book _Day_Dreaming_2nd = new Book("Day Dreaming, Second Edition"); 38 | 39 | _John_Smith.addBook(_Day_Dreaming); 40 | _Michelle_Diangello.addBook(_Day_Dreaming); 41 | 42 | _John_Smith.addBook(_Day_Dreaming_2nd); 43 | _Michelle_Diangello.addBook(_Day_Dreaming_2nd); 44 | _Mark_Armstrong.addBook(_Day_Dreaming_2nd); 45 | 46 | session.persist(_John_Smith); 47 | session.persist(_Michelle_Diangello); 48 | session.persist(_Mark_Armstrong); 49 | }); 50 | } 51 | 52 | @Test 53 | public void testCascadeTypeDelete() { 54 | LOGGER.info("Test CascadeType.DELETE"); 55 | 56 | addBooks(); 57 | 58 | doInTransaction(session -> { 59 | Author _Mark_Armstrong = getByName(session, "Mark Armstrong"); 60 | session.delete(_Mark_Armstrong); 61 | Author _John_Smith = getByName(session, "John Smith"); 62 | assertNull(_John_Smith); 63 | }); 64 | 65 | } 66 | 67 | private Author getByName(Session session, String fullName) { 68 | @SuppressWarnings("unchecked") 69 | List authors = (List) session 70 | .createQuery("select a from Author a where a.fullName = :fullName") 71 | .setParameter("fullName", fullName) 72 | .list(); 73 | return authors.isEmpty() ? null : authors.get(0); 74 | } 75 | 76 | 77 | 78 | @Entity(name = "Author") 79 | public static class Author { 80 | 81 | @Id 82 | @GeneratedValue(strategy=GenerationType.AUTO) 83 | private Long id; 84 | 85 | @Column(name = "full_name", nullable = false) 86 | private String fullName; 87 | 88 | @ManyToMany(mappedBy = "authors", cascade = CascadeType.ALL) 89 | private List books = new ArrayList<>(); 90 | 91 | private Author() {} 92 | 93 | public Author(String fullName) { 94 | this.fullName = fullName; 95 | } 96 | 97 | public Long getId() { 98 | return id; 99 | } 100 | 101 | public void addBook(Book book) { 102 | books.add(book); 103 | book.authors.add(this); 104 | } 105 | 106 | public void removeBook(Book book) { 107 | books.remove(book); 108 | book.authors.remove(this); 109 | } 110 | } 111 | 112 | @Entity(name = "Book") 113 | public static class Book { 114 | 115 | @Id 116 | @GeneratedValue(strategy=GenerationType.AUTO) 117 | private Long id; 118 | 119 | @Column(name = "title", nullable = false) 120 | private String title; 121 | 122 | @ManyToMany(cascade = CascadeType.ALL) 123 | @JoinTable(name = "Book_Author", 124 | joinColumns = {@JoinColumn(name = "book_id", referencedColumnName = "id")}, 125 | inverseJoinColumns = {@JoinColumn(name = "author_id", referencedColumnName = "id")} 126 | ) 127 | private List authors = new ArrayList<>(); 128 | 129 | private Book() {} 130 | 131 | public Book(String title) { 132 | this.title = title; 133 | } 134 | } 135 | 136 | 137 | 138 | } 139 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/cascade/ManyToManyCascadeAllParentSideTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.cascade; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | import static org.junit.Assert.assertTrue; 13 | 14 | 15 | /** 16 | * OneToOneCascadeTest - Test to check @OneToOne Cascading 17 | * 18 | * @author Vlad Mihalcea 19 | */ 20 | public class ManyToManyCascadeAllParentSideTest extends AbstractTest { 21 | 22 | @Override 23 | protected Class[] entities() { 24 | return new Class[]{ 25 | Book.class, 26 | Author.class 27 | }; 28 | } 29 | 30 | public void addBooks() { 31 | doInTransaction(session -> { 32 | Author _John_Smith = new Author("John Smith"); 33 | Author _Michelle_Diangello = new Author("Michelle Diangello"); 34 | Author _Mark_Armstrong = new Author("Mark Armstrong"); 35 | 36 | Book _Day_Dreaming = new Book("Day Dreaming"); 37 | Book _Day_Dreaming_2nd = new Book("Day Dreaming, Second Edition"); 38 | 39 | _John_Smith.addBook(_Day_Dreaming); 40 | _Michelle_Diangello.addBook(_Day_Dreaming); 41 | 42 | _John_Smith.addBook(_Day_Dreaming_2nd); 43 | _Michelle_Diangello.addBook(_Day_Dreaming_2nd); 44 | _Mark_Armstrong.addBook(_Day_Dreaming_2nd); 45 | 46 | session.persist(_John_Smith); 47 | session.persist(_Michelle_Diangello); 48 | session.persist(_Mark_Armstrong); 49 | }); 50 | } 51 | 52 | @Test 53 | public void testCascadeTypeDelete() { 54 | LOGGER.info("Test CascadeType.DELETE"); 55 | 56 | addBooks(); 57 | 58 | doInTransaction(session -> { 59 | Author _Mark_Armstrong = getByName(session, "Mark Armstrong"); 60 | session.delete(_Mark_Armstrong); 61 | Author _John_Smith = getByName(session, "John Smith"); 62 | assertEquals(1, _John_Smith.books.size()); 63 | }); 64 | 65 | } 66 | 67 | private Author getByName(Session session, String fullName) { 68 | return (Author) session 69 | .createQuery("select a from Author a where a.fullName = :fullName") 70 | .setParameter("fullName", fullName) 71 | .uniqueResult(); 72 | } 73 | 74 | 75 | 76 | @Entity(name = "Author") 77 | public static class Author { 78 | 79 | @Id 80 | @GeneratedValue(strategy=GenerationType.AUTO) 81 | private Long id; 82 | 83 | @Column(name = "full_name", nullable = false) 84 | private String fullName; 85 | 86 | @ManyToMany(mappedBy = "authors", cascade = CascadeType.ALL) 87 | private List books = new ArrayList<>(); 88 | 89 | private Author() {} 90 | 91 | public Author(String fullName) { 92 | this.fullName = fullName; 93 | } 94 | 95 | public Long getId() { 96 | return id; 97 | } 98 | 99 | public void addBook(Book book) { 100 | books.add(book); 101 | book.authors.add(this); 102 | } 103 | 104 | public void removeBook(Book book) { 105 | books.remove(book); 106 | book.authors.remove(this); 107 | } 108 | } 109 | 110 | @Entity(name = "Book") 111 | public static class Book { 112 | 113 | @Id 114 | @GeneratedValue(strategy=GenerationType.AUTO) 115 | private Long id; 116 | 117 | @Column(name = "title", nullable = false) 118 | private String title; 119 | 120 | @ManyToMany 121 | @JoinTable(name = "Book_Author", 122 | joinColumns = {@JoinColumn(name = "book_id", referencedColumnName = "id")}, 123 | inverseJoinColumns = {@JoinColumn(name = "author_id", referencedColumnName = "id")} 124 | ) 125 | private List authors = new ArrayList<>(); 126 | 127 | private Book() {} 128 | 129 | public Book(String title) { 130 | this.title = title; 131 | } 132 | } 133 | 134 | 135 | 136 | } 137 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/cascade/ManyToManyCascadeDissociationTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.cascade; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | 14 | /** 15 | * OneToOneCascadeTest - Test to check @OneToOne Cascading 16 | * 17 | * @author Vlad Mihalcea 18 | */ 19 | public class ManyToManyCascadeDissociationTest extends AbstractTest { 20 | 21 | @Override 22 | protected Class[] entities() { 23 | return new Class[]{ 24 | Book.class, 25 | Author.class 26 | }; 27 | } 28 | 29 | public void addBooks() { 30 | doInTransaction(session -> { 31 | Author _John_Smith = new Author("John Smith"); 32 | Author _Michelle_Diangello = new Author("Michelle Diangello"); 33 | Author _Mark_Armstrong = new Author("Mark Armstrong"); 34 | 35 | Book _Day_Dreaming = new Book("Day Dreaming"); 36 | Book _Day_Dreaming_2nd = new Book("Day Dreaming, Second Edition"); 37 | 38 | _John_Smith.addBook(_Day_Dreaming); 39 | _Michelle_Diangello.addBook(_Day_Dreaming); 40 | 41 | _John_Smith.addBook(_Day_Dreaming_2nd); 42 | _Michelle_Diangello.addBook(_Day_Dreaming_2nd); 43 | _Mark_Armstrong.addBook(_Day_Dreaming_2nd); 44 | 45 | session.persist(_John_Smith); 46 | session.persist(_Michelle_Diangello); 47 | session.persist(_Mark_Armstrong); 48 | }); 49 | } 50 | 51 | @Test 52 | public void testCascadeTypeDelete() { 53 | LOGGER.info("Test CascadeType.DELETE"); 54 | 55 | addBooks(); 56 | 57 | doInTransaction(session -> { 58 | Author _Mark_Armstrong = getByName(session, "Mark Armstrong"); 59 | _Mark_Armstrong.remove(); 60 | session.delete(_Mark_Armstrong); 61 | session.flush(); 62 | Author _John_Smith = getByName(session, "John Smith"); 63 | assertEquals(2, _John_Smith.books.size()); 64 | }); 65 | 66 | } 67 | 68 | private Author getByName(Session session, String fullName) { 69 | return (Author) session 70 | .createQuery("select a from Author a join fetch a.books where a.fullName = :fullName") 71 | .setParameter("fullName", fullName) 72 | .uniqueResult(); 73 | } 74 | 75 | @Entity(name = "Author") 76 | public static class Author { 77 | 78 | @Id 79 | @GeneratedValue(strategy=GenerationType.AUTO) 80 | private Long id; 81 | 82 | @Column(name = "full_name", nullable = false) 83 | private String fullName; 84 | 85 | @ManyToMany(mappedBy = "authors", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) 86 | private List books = new ArrayList<>(); 87 | 88 | private Author() {} 89 | 90 | public Author(String fullName) { 91 | this.fullName = fullName; 92 | } 93 | 94 | public Long getId() { 95 | return id; 96 | } 97 | 98 | public void addBook(Book book) { 99 | books.add(book); 100 | book.authors.add(this); 101 | } 102 | 103 | public void removeBook(Book book) { 104 | books.remove(book); 105 | book.authors.remove(this); 106 | } 107 | 108 | public void remove() { 109 | for(Book book : new ArrayList<>(books)) { 110 | removeBook(book); 111 | } 112 | } 113 | } 114 | 115 | @Entity(name = "Book") 116 | public static class Book { 117 | 118 | @Id 119 | @GeneratedValue(strategy=GenerationType.AUTO) 120 | private Long id; 121 | 122 | @Column(name = "title", nullable = false) 123 | private String title; 124 | 125 | @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) 126 | @JoinTable(name = "Book_Author", 127 | joinColumns = {@JoinColumn(name = "book_id", referencedColumnName = "id")}, 128 | inverseJoinColumns = {@JoinColumn(name = "author_id", referencedColumnName = "id")} 129 | ) 130 | private List authors = new ArrayList<>(); 131 | 132 | private Book() {} 133 | 134 | public Book(String title) { 135 | this.title = title; 136 | } 137 | } 138 | 139 | 140 | 141 | } 142 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/cascade/OneToManyCascadeTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.cascade; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.junit.Test; 5 | 6 | import javax.persistence.*; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | 11 | /** 12 | * OneToOneCascadeTest - Test to check @OneToOne Cascading 13 | * 14 | * @author Vlad Mihalcea 15 | */ 16 | public class OneToManyCascadeTest extends AbstractTest { 17 | 18 | @Override 19 | protected Class[] entities() { 20 | return new Class[]{ 21 | Post.class, 22 | Comment.class 23 | }; 24 | } 25 | 26 | public Post newPost() { 27 | return doInTransaction(session -> { 28 | Post post = new Post(); 29 | post.setName("Hibernate Master Class"); 30 | 31 | Comment comment1 = new Comment(); 32 | comment1.setReview("Good post!"); 33 | Comment comment2 = new Comment(); 34 | comment2.setReview("Nice post!"); 35 | 36 | post.addComment(comment1); 37 | post.addComment(comment2); 38 | 39 | session.persist(post); 40 | 41 | return post; 42 | }); 43 | } 44 | 45 | @Test 46 | public void testCascadeTypeMerge() { 47 | LOGGER.info("Test CascadeType.MERGE"); 48 | 49 | Post post = newPost(); 50 | post.setName("Hibernate Master Class Training Material"); 51 | 52 | post.getComments() 53 | .stream() 54 | .filter(comment -> comment.getReview().toLowerCase().contains("nice")) 55 | .findAny() 56 | .ifPresent(comment -> comment.setReview("Keep up the good work!")); 57 | 58 | doInTransaction(session -> { 59 | session.merge(post); 60 | }); 61 | } 62 | 63 | @Test 64 | public void testOrphanRemoval() { 65 | LOGGER.info("Test orphan removal"); 66 | 67 | newPost(); 68 | 69 | doInTransaction(session -> { 70 | Post post = (Post) session.createQuery( 71 | "select p " + 72 | "from Post p " + 73 | "join fetch p.comments " + 74 | "where p.id = :id") 75 | .setParameter("id", 1L) 76 | .uniqueResult(); 77 | post.removeComment(post.getComments().get(0)); 78 | }); 79 | } 80 | 81 | @Test 82 | public void testCascadeTypeDelete() { 83 | LOGGER.info("Test CascadeType.DELETE"); 84 | 85 | Post post = newPost(); 86 | 87 | doInTransaction(session -> { 88 | session.delete(post); 89 | }); 90 | } 91 | 92 | @Entity(name = "Post") 93 | public static class Post { 94 | 95 | @Id 96 | @GeneratedValue(strategy = GenerationType.AUTO) 97 | private Long id; 98 | 99 | private String name; 100 | 101 | @OneToMany(cascade = CascadeType.ALL, mappedBy = "post", orphanRemoval = true) 102 | private List comments = new ArrayList<>(); 103 | 104 | public void setName(String name) { 105 | this.name = name; 106 | } 107 | 108 | public List getComments() { 109 | return comments; 110 | } 111 | 112 | public void addComment(Comment comment) { 113 | comments.add(comment); 114 | comment.setPost(this); 115 | } 116 | 117 | public void removeComment(Comment comment) { 118 | comment.setPost(null); 119 | this.comments.remove(comment); 120 | } 121 | } 122 | 123 | @Entity(name = "Comment") 124 | public static class Comment { 125 | 126 | @Id 127 | @GeneratedValue(strategy = GenerationType.AUTO) 128 | private Long id; 129 | 130 | @ManyToOne 131 | private Post post; 132 | 133 | private String review; 134 | 135 | public void setPost(Post post) { 136 | this.post = post; 137 | } 138 | 139 | public String getReview() { 140 | return review; 141 | } 142 | 143 | public void setReview(String review) { 144 | this.review = review; 145 | } 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/AbstractEntityOptimisticLockingCollectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | 5 | import java.util.List; 6 | 7 | import static org.junit.Assert.assertEquals; 8 | import static org.junit.Assert.assertNotSame; 9 | 10 | /** 11 | * AbstractEntityOptimisticLockingCollectionTest - Abstract Test to check optimistic locking collection versioning 12 | * 13 | * @author Vlad Mihalcea 14 | */ 15 | public abstract class AbstractEntityOptimisticLockingCollectionTest

, C extends AbstractEntityOptimisticLockingCollectionTest.IComment

> extends AbstractTest { 16 | 17 | public interface IPost { 18 | Long getId(); 19 | 20 | void setId(Long id); 21 | 22 | public String getName(); 23 | 24 | public void setName(String name); 25 | 26 | public List getComments(); 27 | 28 | public int getVersion(); 29 | 30 | public void addComment(C comment); 31 | } 32 | 33 | public interface IComment

{ 34 | 35 | String getReview(); 36 | 37 | void setReview(String review); 38 | } 39 | 40 | private final Class

postClass; 41 | 42 | private final Class commentClass; 43 | 44 | protected AbstractEntityOptimisticLockingCollectionTest(Class

postClass, Class commentClass) { 45 | this.postClass = postClass; 46 | this.commentClass = commentClass; 47 | } 48 | 49 | protected void simulateConcurrentTransactions(final boolean shouldIncrementParentVersion) { 50 | doInTransaction(session -> { 51 | try { 52 | P post = postClass.newInstance(); 53 | post.setId(1L); 54 | post.setName("Hibernate training"); 55 | session.persist(post); 56 | } catch (Exception e) { 57 | throw new IllegalArgumentException(e); 58 | } 59 | }); 60 | 61 | doInTransaction(session -> { 62 | final P post = (P) session.get(postClass, 1L); 63 | try { 64 | executeSync(() -> { 65 | doInTransaction(_session -> { 66 | try { 67 | P otherThreadPost = (P) _session.get(postClass, 1L); 68 | int loadTimeVersion = otherThreadPost.getVersion(); 69 | assertNotSame(post, otherThreadPost); 70 | assertEquals(0L, otherThreadPost.getVersion()); 71 | C comment = commentClass.newInstance(); 72 | comment.setReview("Good post!"); 73 | otherThreadPost.addComment(comment); 74 | _session.flush(); 75 | if (shouldIncrementParentVersion) { 76 | assertEquals(otherThreadPost.getVersion(), loadTimeVersion + 1); 77 | } else { 78 | assertEquals(otherThreadPost.getVersion(), loadTimeVersion); 79 | } 80 | } catch (Exception e) { 81 | throw new IllegalArgumentException(e); 82 | } 83 | }); 84 | }); 85 | } catch (Exception e) { 86 | throw new IllegalArgumentException(e); 87 | } 88 | post.setName("Hibernate Master Class"); 89 | session.flush(); 90 | }); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/AbstractLockModeOptimisticTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.LockMode; 5 | import org.hibernate.LockOptions; 6 | import org.hibernate.Session; 7 | import org.hibernate.dialect.lock.OptimisticEntityLockException; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | 11 | import javax.persistence.*; 12 | import java.math.BigDecimal; 13 | import java.util.concurrent.Callable; 14 | 15 | import static org.junit.Assert.assertNotSame; 16 | import static org.junit.Assert.fail; 17 | 18 | /** 19 | * AbstractLockModeOptimisticTest - Base Test to check LockMode.OPTIMISTIC 20 | * 21 | * @author Vlad Mihalcea 22 | */ 23 | public abstract class AbstractLockModeOptimisticTest extends AbstractTest { 24 | 25 | @Override 26 | protected Class[] entities() { 27 | return new Class[] { 28 | Product.class, 29 | OrderLine.class 30 | }; 31 | } 32 | 33 | @Before 34 | public void init() { 35 | super.init(); 36 | doInTransaction(session -> { 37 | Product product = new Product(); 38 | product.setId(1L); 39 | product.setDescription("USB Flash Drive"); 40 | product.setPrice(BigDecimal.valueOf(12.99)); 41 | session.persist(product); 42 | }); 43 | } 44 | 45 | /** 46 | * Product - Product 47 | * 48 | * @author Vlad Mihalcea 49 | */ 50 | @Entity(name = "product") 51 | @Table(name = "product") 52 | public static class Product { 53 | 54 | @Id 55 | private Long id; 56 | 57 | private String description; 58 | 59 | private BigDecimal price; 60 | 61 | @Version 62 | private int version; 63 | 64 | public Long getId() { 65 | return id; 66 | } 67 | 68 | public void setId(Long id) { 69 | this.id = id; 70 | } 71 | 72 | public String getDescription() { 73 | return description; 74 | } 75 | 76 | public void setDescription(String description) { 77 | this.description = description; 78 | } 79 | 80 | public BigDecimal getPrice() { 81 | return price; 82 | } 83 | 84 | public void setPrice(BigDecimal price) { 85 | this.price = price; 86 | } 87 | } 88 | 89 | /** 90 | * OrderLine - Order Line 91 | * 92 | * @author Vlad Mihalcea 93 | */ 94 | @Entity(name = "OrderLine") 95 | @Table(name = "order_line") 96 | public static class OrderLine { 97 | 98 | @Id 99 | @GeneratedValue(strategy = GenerationType.AUTO) 100 | private Long id; 101 | 102 | @ManyToOne 103 | private Product product; 104 | 105 | private BigDecimal unitPrice; 106 | 107 | @Version 108 | private int version; 109 | 110 | public OrderLine(Product product) { 111 | this.product = product; 112 | this.unitPrice = product.getPrice(); 113 | } 114 | 115 | public Long getId() { 116 | return id; 117 | } 118 | 119 | public Product getProduct() { 120 | return product; 121 | } 122 | 123 | public BigDecimal getUnitPrice() { 124 | return unitPrice; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/EntityFirstLevelCacheReuseTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.Entity; 8 | import javax.persistence.Id; 9 | import javax.persistence.Table; 10 | import java.util.concurrent.Callable; 11 | 12 | import static org.junit.Assert.*; 13 | 14 | /** 15 | * OptimisticLockingTest - Test to check optimistic checking 16 | * 17 | * @author Vlad Mihalcea 18 | */ 19 | public class EntityFirstLevelCacheReuseTest extends AbstractTest { 20 | 21 | @Override 22 | protected Class[] entities() { 23 | return new Class[] { 24 | Product.class 25 | }; 26 | } 27 | 28 | @Test 29 | public void testOptimisticLocking() { 30 | doInTransaction(session -> { 31 | Product product = new Product(); 32 | product.setId(1L); 33 | product.setQuantity(7L); 34 | session.persist(product); 35 | }); 36 | doInTransaction(session -> { 37 | final Product product = (Product) session.get(Product.class, 1L); 38 | try { 39 | executeSync( () -> doInTransaction(_session -> { 40 | Product otherThreadProduct = (Product) _session.get(Product.class, 1L); 41 | assertNotSame(product, otherThreadProduct); 42 | otherThreadProduct.setQuantity(6L); 43 | })); 44 | Product reloadedProduct = (Product) session.createQuery("from product").uniqueResult(); 45 | assertEquals(7L, reloadedProduct.getQuantity()); 46 | assertEquals(6L, 47 | ((Number) session 48 | .createSQLQuery("select quantity from product where id = :id") 49 | .setParameter("id", product.getId()) 50 | .uniqueResult()) 51 | .longValue() 52 | ); 53 | } catch (Exception e) { 54 | fail(e.getMessage()); 55 | } 56 | }); 57 | } 58 | 59 | /** 60 | * Product - Product 61 | * 62 | * @author Vlad Mihalcea 63 | */ 64 | @Entity(name = "product") 65 | @Table(name = "product") 66 | public static class Product { 67 | 68 | @Id 69 | private Long id; 70 | 71 | private long quantity; 72 | 73 | private int likes; 74 | 75 | public Product() { 76 | } 77 | 78 | public Long getId() { 79 | return id; 80 | } 81 | 82 | public void setId(Long id) { 83 | this.id = id; 84 | } 85 | 86 | public long getQuantity() { 87 | return quantity; 88 | } 89 | 90 | public void setQuantity(long quantity) { 91 | this.quantity = quantity; 92 | } 93 | 94 | public int getLikes() { 95 | return likes; 96 | } 97 | 98 | public int incrementLikes() { 99 | return ++likes; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/EntityOptimisticLockingOnBidirectionalChildOwningCollectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import org.junit.Test; 4 | 5 | import javax.persistence.*; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * EntityOptimisticLockingOnBidirectionalChildOwningCollectionTest - Test to check optimistic locking on bidirectional child owning collections 11 | * 12 | * @author Vlad Mihalcea 13 | */ 14 | public class EntityOptimisticLockingOnBidirectionalChildOwningCollectionTest 15 | extends AbstractEntityOptimisticLockingCollectionTest 16 | { 17 | 18 | @Entity(name = "post") 19 | public static class Post implements AbstractEntityOptimisticLockingCollectionTest.IPost { 20 | 21 | @Id 22 | private Long id; 23 | 24 | private String name; 25 | 26 | @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "post") 27 | private List comments = new ArrayList(); 28 | 29 | @Version 30 | private int version; 31 | 32 | public Long getId() { 33 | return id; 34 | } 35 | 36 | public void setId(Long id) { 37 | this.id = id; 38 | } 39 | 40 | public String getName() { 41 | return name; 42 | } 43 | 44 | public void setName(String name) { 45 | this.name = name; 46 | } 47 | 48 | public List getComments() { 49 | return comments; 50 | } 51 | 52 | public final int getVersion() { 53 | return version; 54 | } 55 | 56 | public void addComment(Comment comment) { 57 | comment.setPost(this); 58 | comments.add(comment); 59 | } 60 | } 61 | 62 | @Entity(name = "comment") 63 | public static class Comment implements AbstractEntityOptimisticLockingCollectionTest.IComment { 64 | 65 | @Id 66 | @GeneratedValue(strategy=GenerationType.IDENTITY) 67 | private Long id; 68 | 69 | private String review; 70 | 71 | @ManyToOne 72 | private Post post; 73 | 74 | public Long getId() { 75 | return id; 76 | } 77 | 78 | public String getReview() { 79 | return review; 80 | } 81 | 82 | public void setReview(String review) { 83 | this.review = review; 84 | } 85 | 86 | 87 | public Post getPost() { 88 | return post; 89 | } 90 | 91 | public void setPost(Post post) { 92 | this.post = post; 93 | } 94 | } 95 | 96 | public EntityOptimisticLockingOnBidirectionalChildOwningCollectionTest() { 97 | super(Post.class, Comment.class); 98 | } 99 | 100 | @Override 101 | protected Class[] entities() { 102 | return new Class[] { 103 | Post.class, 104 | Comment.class 105 | }; 106 | } 107 | 108 | @Test 109 | public void testCollectionOptimisticLocking() { 110 | simulateConcurrentTransactions(false); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/EntityOptimisticLockingOnBidirectionalParentOwningCollectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import org.hibernate.StaleObjectStateException; 4 | import org.junit.Test; 5 | 6 | import javax.persistence.*; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import static org.junit.Assert.assertTrue; 11 | 12 | /** 13 | * EntityOptimisticLockingOnBidirectionalParentOwningCollectionTest - Test to check optimistic locking on bidirectional parent owning collections 14 | * 15 | * @author Vlad Mihalcea 16 | */ 17 | public class EntityOptimisticLockingOnBidirectionalParentOwningCollectionTest 18 | extends AbstractEntityOptimisticLockingCollectionTest 19 | { 20 | 21 | @Entity(name = "post") 22 | public static class Post implements AbstractEntityOptimisticLockingCollectionTest.IPost { 23 | 24 | @Id 25 | private Long id; 26 | 27 | private String name; 28 | 29 | @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) 30 | private List comments = new ArrayList(); 31 | 32 | @Version 33 | private int version; 34 | 35 | public Long getId() { 36 | return id; 37 | } 38 | 39 | public void setId(Long id) { 40 | this.id = id; 41 | } 42 | 43 | public String getName() { 44 | return name; 45 | } 46 | 47 | public void setName(String name) { 48 | this.name = name; 49 | } 50 | 51 | public List getComments() { 52 | return comments; 53 | } 54 | 55 | public final int getVersion() { 56 | return version; 57 | } 58 | 59 | public void addComment(Comment comment) { 60 | comment.setPost(this); 61 | comments.add(comment); 62 | } 63 | } 64 | 65 | @Entity(name = "comment") 66 | public static class Comment implements AbstractEntityOptimisticLockingCollectionTest.IComment { 67 | 68 | @Id 69 | @GeneratedValue(strategy=GenerationType.IDENTITY) 70 | private Long id; 71 | 72 | private String review; 73 | 74 | @ManyToOne 75 | @JoinColumn(name = "post_id", insertable = false, updatable = false) 76 | private Post post; 77 | 78 | public Long getId() { 79 | return id; 80 | } 81 | 82 | public String getReview() { 83 | return review; 84 | } 85 | 86 | public void setReview(String review) { 87 | this.review = review; 88 | } 89 | 90 | 91 | public Post getPost() { 92 | return post; 93 | } 94 | 95 | public void setPost(Post post) { 96 | this.post = post; 97 | } 98 | } 99 | 100 | public EntityOptimisticLockingOnBidirectionalParentOwningCollectionTest() { 101 | super(EntityOptimisticLockingOnBidirectionalParentOwningCollectionTest.Post.class, EntityOptimisticLockingOnBidirectionalParentOwningCollectionTest.Comment.class); 102 | } 103 | 104 | @Override 105 | protected Class[] entities() { 106 | return new Class[] { 107 | Post.class, 108 | Comment.class 109 | }; 110 | } 111 | 112 | @Test 113 | public void testOptimisticLocking() { 114 | try { 115 | simulateConcurrentTransactions(true); 116 | } catch (Exception e) { 117 | LOGGER.info("Expected", e); 118 | assertTrue(e instanceof StaleObjectStateException); 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/EntityOptimisticLockingOnComponentCollectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import org.hibernate.StaleObjectStateException; 4 | import org.hibernate.annotations.Parent; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import static org.junit.Assert.assertTrue; 12 | 13 | /** 14 | * EntityOptimisticLockingOnComponentCollectionTest - Test to check optimistic locking on component collections 15 | * 16 | * @author Vlad Mihalcea 17 | */ 18 | public class EntityOptimisticLockingOnComponentCollectionTest 19 | extends AbstractEntityOptimisticLockingCollectionTest 20 | { 21 | 22 | @Entity(name = "post") 23 | public static class Post implements AbstractEntityOptimisticLockingCollectionTest.IPost { 24 | 25 | @Id 26 | private Long id; 27 | 28 | private String name; 29 | 30 | @ElementCollection 31 | @JoinTable(name = "post_comments", joinColumns = @JoinColumn(name = "post_id")) 32 | @OrderColumn(name = "comment_index") 33 | private List comments = new ArrayList(); 34 | 35 | @Version 36 | private int version; 37 | 38 | public Long getId() { 39 | return id; 40 | } 41 | 42 | public void setId(Long id) { 43 | this.id = id; 44 | } 45 | 46 | public String getName() { 47 | return name; 48 | } 49 | 50 | public void setName(String name) { 51 | this.name = name; 52 | } 53 | 54 | public List getComments() { 55 | return comments; 56 | } 57 | 58 | public final int getVersion() { 59 | return version; 60 | } 61 | 62 | public void addComment(Comment comment) { 63 | comment.setPost(this); 64 | comments.add(comment); 65 | } 66 | } 67 | 68 | @Embeddable 69 | public static class Comment implements AbstractEntityOptimisticLockingCollectionTest.IComment { 70 | 71 | @Parent 72 | private Post post; 73 | 74 | @Column(name = "review") 75 | private String review; 76 | 77 | public Post getPost() { 78 | return post; 79 | } 80 | 81 | public void setPost(Post post) { 82 | this.post = post; 83 | } 84 | 85 | public String getReview() { 86 | return review; 87 | } 88 | 89 | public void setReview(String review) { 90 | this.review = review; 91 | } 92 | } 93 | 94 | public EntityOptimisticLockingOnComponentCollectionTest() { 95 | super(Post.class, Comment.class); 96 | } 97 | 98 | @Override 99 | protected Class[] entities() { 100 | return new Class[] { 101 | Post.class 102 | }; 103 | } 104 | 105 | @Test 106 | public void testOptimisticLocking() { 107 | try { 108 | simulateConcurrentTransactions(true); 109 | } catch (Exception e) { 110 | LOGGER.info("Expected", e); 111 | assertTrue(e instanceof StaleObjectStateException); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/EntityOptimisticLockingOnUnidirectionalCollectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import org.hibernate.StaleObjectStateException; 4 | import org.junit.Test; 5 | 6 | import javax.persistence.*; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import static org.junit.Assert.assertTrue; 11 | 12 | /** 13 | * EntityOptimisticLockingOnUnidirectionalCollectionTest - Test to check optimistic locking on unidirectional collections 14 | * 15 | * @author Vlad Mihalcea 16 | */ 17 | public class EntityOptimisticLockingOnUnidirectionalCollectionTest 18 | extends AbstractEntityOptimisticLockingCollectionTest 19 | { 20 | 21 | @Entity(name = "post") 22 | public static class Post implements AbstractEntityOptimisticLockingCollectionTest.IPost { 23 | 24 | @Id 25 | private Long id; 26 | 27 | private String name; 28 | 29 | @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) 30 | @OrderColumn(name = "comment_index") 31 | private List comments = new ArrayList(); 32 | 33 | @Version 34 | private int version; 35 | 36 | public Long getId() { 37 | return id; 38 | } 39 | 40 | public void setId(Long id) { 41 | this.id = id; 42 | } 43 | 44 | public String getName() { 45 | return name; 46 | } 47 | 48 | public void setName(String name) { 49 | this.name = name; 50 | } 51 | 52 | public List getComments() { 53 | return comments; 54 | } 55 | 56 | public final int getVersion() { 57 | return version; 58 | } 59 | 60 | public void addComment(Comment comment) { 61 | comments.add(comment); 62 | } 63 | } 64 | 65 | @Entity(name = "comment") 66 | public static class Comment implements AbstractEntityOptimisticLockingCollectionTest.IComment { 67 | 68 | @Id 69 | @GeneratedValue(strategy=GenerationType.IDENTITY) 70 | private Long id; 71 | 72 | private String review; 73 | 74 | public Long getId() { 75 | return id; 76 | } 77 | 78 | public String getReview() { 79 | return review; 80 | } 81 | 82 | public void setReview(String review) { 83 | this.review = review; 84 | } 85 | } 86 | 87 | public EntityOptimisticLockingOnUnidirectionalCollectionTest() { 88 | super(Post.class, Comment.class); 89 | } 90 | 91 | @Override 92 | protected Class[] entities() { 93 | return new Class[] { 94 | Post.class, 95 | Comment.class 96 | }; 97 | } 98 | 99 | @Test 100 | public void testOptimisticLocking() { 101 | try { 102 | simulateConcurrentTransactions(true); 103 | } catch (Exception e) { 104 | LOGGER.info("Expected", e); 105 | assertTrue(e instanceof StaleObjectStateException); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/EntityOptimisticLockingOverruleOnBidirectionalParentOwningCollectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import org.hibernate.annotations.OptimisticLock; 4 | import org.junit.Test; 5 | 6 | import javax.persistence.*; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * EntityOptimisticLockingOnBidirectionalParentOwningCollectionTest - Test to check optimistic locking overruling on bidirectional parent owning collections 12 | * 13 | * @author Vlad Mihalcea 14 | */ 15 | public class EntityOptimisticLockingOverruleOnBidirectionalParentOwningCollectionTest 16 | extends AbstractEntityOptimisticLockingCollectionTest 17 | { 18 | 19 | @Entity(name = "post") 20 | public static class Post implements AbstractEntityOptimisticLockingCollectionTest.IPost { 21 | 22 | @Id 23 | private Long id; 24 | 25 | private String name; 26 | 27 | @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) 28 | @OptimisticLock(excluded = true) 29 | private List comments = new ArrayList(); 30 | 31 | @Version 32 | private int version; 33 | 34 | public Long getId() { 35 | return id; 36 | } 37 | 38 | public void setId(Long id) { 39 | this.id = id; 40 | } 41 | 42 | public String getName() { 43 | return name; 44 | } 45 | 46 | public void setName(String name) { 47 | this.name = name; 48 | } 49 | 50 | public List getComments() { 51 | return comments; 52 | } 53 | 54 | public final int getVersion() { 55 | return version; 56 | } 57 | 58 | public void addComment(Comment comment) { 59 | comment.setPost(this); 60 | comments.add(comment); 61 | } 62 | } 63 | 64 | @Entity(name = "comment") 65 | public static class Comment implements AbstractEntityOptimisticLockingCollectionTest.IComment { 66 | 67 | @Id 68 | @GeneratedValue(strategy=GenerationType.IDENTITY) 69 | private Long id; 70 | 71 | private String review; 72 | 73 | @ManyToOne 74 | @JoinColumn(name = "post_id", insertable = false, updatable = false) 75 | private Post post; 76 | 77 | public Long getId() { 78 | return id; 79 | } 80 | 81 | public String getReview() { 82 | return review; 83 | } 84 | 85 | public void setReview(String review) { 86 | this.review = review; 87 | } 88 | 89 | 90 | public Post getPost() { 91 | return post; 92 | } 93 | 94 | public void setPost(Post post) { 95 | this.post = post; 96 | } 97 | } 98 | 99 | public EntityOptimisticLockingOverruleOnBidirectionalParentOwningCollectionTest() { 100 | super(Post.class, Comment.class); 101 | } 102 | 103 | @Override 104 | protected Class[] entities() { 105 | return new Class[] { 106 | Post.class, 107 | Comment.class 108 | }; 109 | } 110 | 111 | @Test 112 | public void testOptimisticLocking() { 113 | simulateConcurrentTransactions(false); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/LockModeOptimisticRaceConditionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import org.hibernate.*; 4 | import org.hibernate.dialect.lock.OptimisticEntityLockException; 5 | import org.junit.Test; 6 | 7 | import java.sql.PreparedStatement; 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.atomic.AtomicBoolean; 10 | 11 | /** 12 | * LockModeOptimisticWithPessimisticLockUpgradeTest - Test to check LockMode.OPTIMISTIC with pessimistic lock upgrade 13 | * 14 | * @author Vlad Mihalcea 15 | */ 16 | public class LockModeOptimisticRaceConditionTest extends AbstractLockModeOptimisticTest { 17 | 18 | private AtomicBoolean ready = new AtomicBoolean(); 19 | private final CountDownLatch endLatch = new CountDownLatch(1); 20 | 21 | @Override 22 | protected Interceptor interceptor() { 23 | return new EmptyInterceptor() { 24 | @Override 25 | public void beforeTransactionCompletion(Transaction tx) { 26 | if(ready.get()) { 27 | LOGGER.info("Overwrite product price asynchronously"); 28 | 29 | executeAsync(() -> { 30 | Session _session = getSessionFactory().openSession(); 31 | _session.doWork(connection -> { 32 | try (PreparedStatement ps = connection.prepareStatement("UPDATE product set price = 14.49 WHERE id = 1")) { 33 | ps.executeUpdate(); 34 | } 35 | }); 36 | _session.close(); 37 | endLatch.countDown(); 38 | }); 39 | try { 40 | LOGGER.info("Wait 500 ms for lock to be acquired!"); 41 | Thread.sleep(500); 42 | } catch (InterruptedException e) { 43 | throw new IllegalStateException(e); 44 | } 45 | } 46 | } 47 | }; 48 | } 49 | 50 | @Test 51 | public void testExplicitOptimisticLocking() throws InterruptedException { 52 | try { 53 | doInTransaction(session -> { 54 | try { 55 | final Product product = (Product) session.get(Product.class, 1L, new LockOptions(LockMode.OPTIMISTIC)); 56 | OrderLine orderLine = new OrderLine(product); 57 | session.persist(orderLine); 58 | lockUpgrade(session, product); 59 | ready.set(true); 60 | } catch (Exception e) { 61 | throw new IllegalStateException(e); 62 | } 63 | }); 64 | } catch (OptimisticEntityLockException expected) { 65 | LOGGER.info("Failure: ", expected); 66 | } 67 | endLatch.await(); 68 | } 69 | 70 | protected void lockUpgrade(Session session, Product product) {} 71 | } 72 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/LockModeOptimisticTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import org.hibernate.LockMode; 4 | import org.hibernate.LockOptions; 5 | import org.hibernate.dialect.lock.OptimisticEntityLockException; 6 | import org.junit.Test; 7 | 8 | import java.math.BigDecimal; 9 | 10 | import static org.junit.Assert.assertNotSame; 11 | import static org.junit.Assert.fail; 12 | 13 | /** 14 | * LockModeOptimisticTest - Test to check LockMode.OPTIMISTIC 15 | * 16 | * @author Vlad Mihalcea 17 | */ 18 | public class LockModeOptimisticTest extends AbstractLockModeOptimisticTest { 19 | 20 | @Test 21 | public void testImplicitOptimisticLocking() { 22 | 23 | doInTransaction(session -> { 24 | final Product product = (Product) session.get(Product.class, 1L); 25 | try { 26 | executeSync(() -> doInTransaction(_session -> { 27 | Product _product = (Product) _session.get(Product.class, 1L); 28 | assertNotSame(product, _product); 29 | _product.setPrice(BigDecimal.valueOf(14.49)); 30 | })); 31 | } catch (Exception e) { 32 | fail(e.getMessage()); 33 | } 34 | OrderLine orderLine = new OrderLine(product); 35 | session.persist(orderLine); 36 | }); 37 | } 38 | 39 | @Test 40 | public void testExplicitOptimisticLocking() { 41 | 42 | try { 43 | doInTransaction(session -> { 44 | final Product product = (Product) session.get(Product.class, 1L, new LockOptions(LockMode.OPTIMISTIC)); 45 | 46 | executeSync(() -> { 47 | doInTransaction(_session -> { 48 | Product _product = (Product) _session.get(Product.class, 1L); 49 | assertNotSame(product, _product); 50 | _product.setPrice(BigDecimal.valueOf(14.49)); 51 | }); 52 | }); 53 | 54 | OrderLine orderLine = new OrderLine(product); 55 | session.persist(orderLine); 56 | }); 57 | fail("It should have thrown OptimisticEntityLockException!"); 58 | } catch (OptimisticEntityLockException expected) { 59 | LOGGER.info("Failure: ", expected); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/LockModeOptimisticWithPessimisticLockUpgradeTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import org.hibernate.*; 4 | import org.hibernate.dialect.lock.OptimisticEntityLockException; 5 | import org.hibernate.jdbc.Work; 6 | import org.junit.Test; 7 | 8 | import java.util.concurrent.Callable; 9 | import java.util.concurrent.CountDownLatch; 10 | 11 | /** 12 | * LockModeOptimisticWithPessimisticLockUpgradeTest - Test to check LockMode.OPTIMISTIC with pessimistic lock upgrade 13 | * 14 | * @author Vlad Mihalcea 15 | */ 16 | public class LockModeOptimisticWithPessimisticLockUpgradeTest extends LockModeOptimisticRaceConditionTest { 17 | 18 | @Override 19 | protected void lockUpgrade(Session session, Product product) { 20 | session.buildLockRequest(new LockOptions(LockMode.PESSIMISTIC_READ)).lock(product); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/concurrency/OptimisticLockingVersionlessTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.concurrency; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.hibernate.annotations.DynamicUpdate; 6 | import org.hibernate.annotations.OptimisticLockType; 7 | import org.hibernate.annotations.OptimisticLocking; 8 | import org.hibernate.annotations.SelectBeforeUpdate; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import javax.persistence.Column; 13 | import javax.persistence.Entity; 14 | import javax.persistence.Id; 15 | import java.math.BigDecimal; 16 | 17 | /** 18 | * OptimisticLockingVersionlessTest - Test to check optimistic checking using the dirty properties instead of a synthetic version column 19 | * 20 | * @author Vlad Mihalcea 21 | */ 22 | public class OptimisticLockingVersionlessTest extends AbstractTest { 23 | 24 | private Product product; 25 | 26 | @Before 27 | public void init() { 28 | super.init(); 29 | product = doInTransaction(session -> { 30 | session.createQuery("delete from Product").executeUpdate(); 31 | Product _product = new Product(); 32 | _product.setId(1L); 33 | _product.setName("TV"); 34 | _product.setDescription("Plasma TV"); 35 | _product.setPrice(BigDecimal.valueOf(199.99)); 36 | _product.setQuantity(7L); 37 | session.persist(_product); 38 | return _product; 39 | }); 40 | } 41 | 42 | @Test 43 | public void testVersionlessOptimisticLockingWhenMerging() { 44 | 45 | doInTransaction(session -> { 46 | Product _product = (Product) session.get(Product.class, 1L); 47 | _product.setPrice(BigDecimal.valueOf(21.22)); 48 | LOGGER.info("Updating product price to {}", _product.getPrice()); 49 | }); 50 | 51 | product.setPrice(BigDecimal.ONE); 52 | doInTransaction(session -> { 53 | LOGGER.info("Merging product, price to be saved is {}", product.getPrice()); 54 | session.merge(product); 55 | session.flush(); 56 | }); 57 | } 58 | 59 | @Test 60 | public void testVersionlessOptimisticLockingWhenReattaching() { 61 | 62 | doInTransaction(session -> { 63 | Product _product = (Product) session.get(Product.class, 1L); 64 | _product.setPrice(BigDecimal.valueOf(21.22)); 65 | LOGGER.info("Updating product price to {}", _product.getPrice()); 66 | }); 67 | 68 | product.setPrice(BigDecimal.TEN); 69 | doInTransaction(session -> { 70 | LOGGER.info("Reattaching product, price to be saved is {}", product.getPrice()); 71 | session.saveOrUpdate(product); 72 | session.flush(); 73 | }); 74 | } 75 | 76 | @Override 77 | protected Class[] entities() { 78 | return new Class[]{ 79 | Product.class 80 | }; 81 | } 82 | 83 | @Entity(name = "Product") 84 | @OptimisticLocking(type = OptimisticLockType.DIRTY) 85 | @DynamicUpdate 86 | @SelectBeforeUpdate(value = false) 87 | public static class Product { 88 | 89 | @Id 90 | private Long id; 91 | 92 | @Column(unique = true, nullable = false) 93 | private String name; 94 | 95 | @Column(nullable = false) 96 | private String description; 97 | 98 | @Column(nullable = false) 99 | private BigDecimal price; 100 | 101 | private long quantity; 102 | 103 | private int likes; 104 | 105 | public Long getId() { 106 | return id; 107 | } 108 | 109 | public void setId(Long id) { 110 | this.id = id; 111 | } 112 | 113 | public String getName() { 114 | return name; 115 | } 116 | 117 | public void setName(String name) { 118 | this.name = name; 119 | } 120 | 121 | public String getDescription() { 122 | return description; 123 | } 124 | 125 | public void setDescription(String description) { 126 | this.description = description; 127 | } 128 | 129 | public BigDecimal getPrice() { 130 | return price; 131 | } 132 | 133 | public void setPrice(BigDecimal price) { 134 | this.price = price; 135 | } 136 | 137 | public long getQuantity() { 138 | return quantity; 139 | } 140 | 141 | public void setQuantity(long quantity) { 142 | this.quantity = quantity; 143 | } 144 | 145 | public int getLikes() { 146 | return likes; 147 | } 148 | 149 | public int incrementLikes() { 150 | return ++likes; 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/entityidentifier/EntityAttribute.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.entityidentifier; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | /** 9 | * EntityAttribute - Entity Attribute 10 | * 11 | * @author Vlad Mihalcea 12 | */ 13 | @Entity 14 | @Table(name = "entity_attribute") 15 | public class EntityAttribute { 16 | 17 | @Id 18 | @GeneratedValue 19 | private Long id; 20 | 21 | private String name; 22 | 23 | private String value; 24 | 25 | private EntityIdentifier entityIdentifier; 26 | 27 | public Long getId() { 28 | return id; 29 | } 30 | 31 | public String getName() { 32 | return name; 33 | } 34 | 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | 39 | public String getValue() { 40 | return value; 41 | } 42 | 43 | public void setValue(String value) { 44 | this.value = value; 45 | } 46 | 47 | public EntityIdentifier getEntityIdentifier() { 48 | return entityIdentifier; 49 | } 50 | 51 | public void setEntityIdentifier(EntityIdentifier entityIdentifier) { 52 | this.entityIdentifier = entityIdentifier; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/entityidentifier/EntityEvent.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.entityidentifier; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | /** 9 | * EntityEvent - Entity Event 10 | * 11 | * @author Vlad Mihalcea 12 | */ 13 | @Entity 14 | @Table(name = "entity_event") 15 | public class EntityEvent { 16 | 17 | @Id 18 | @GeneratedValue 19 | private Long id; 20 | 21 | private String message; 22 | 23 | private EntityIdentifier entityIdentifier; 24 | 25 | public Long getId() { 26 | return id; 27 | } 28 | 29 | public String getMessage() { 30 | return message; 31 | } 32 | 33 | public void setMessage(String message) { 34 | this.message = message; 35 | } 36 | 37 | public EntityIdentifier getEntityIdentifier() { 38 | return entityIdentifier; 39 | } 40 | 41 | public void setEntityIdentifier(EntityIdentifier entityIdentifier) { 42 | this.entityIdentifier = entityIdentifier; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/entityidentifier/EntityIdentifier.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.entityidentifier; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Embeddable; 5 | import java.io.Serializable; 6 | 7 | /** 8 | * EntityLocator - Uniquely identifies an entity 9 | * 10 | * @author Vlad Mihalcea 11 | */ 12 | @Embeddable 13 | public class EntityIdentifier implements Serializable { 14 | 15 | @Column(name = "entity_id", nullable = true) 16 | private Long entityId; 17 | 18 | @Column(name = "entity_class", nullable = true) 19 | private Class entityClass; 20 | 21 | public EntityIdentifier() { 22 | } 23 | 24 | public EntityIdentifier(Class entityClass, Long entityId) { 25 | this.entityClass = entityClass; 26 | this.entityId = entityId; 27 | } 28 | 29 | public Class getEntityClass() { 30 | return entityClass; 31 | } 32 | 33 | public void setEntityClass(Class entityClass) { 34 | this.entityClass = entityClass; 35 | } 36 | 37 | public Long getEntityId() { 38 | return entityId; 39 | } 40 | 41 | public void setEntityId(Long entityId) { 42 | this.entityId = entityId; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/entityidentifier/EntityIdentifierTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.entityidentifier; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.assertSame; 7 | 8 | public class EntityIdentifierTest extends AbstractTest { 9 | 10 | @Override 11 | protected Class[] entities() { 12 | return new Class[] { 13 | Product.class, 14 | EntityEvent.class, 15 | EntityAttribute.class, 16 | }; 17 | } 18 | 19 | @Test 20 | public void testEntityIdentifier() { 21 | doInTransaction(session -> { 22 | Product product = new Product("LCD"); 23 | session.persist(product); 24 | EntityEvent productEvent = new EntityEvent(); 25 | productEvent.setMessage(String.format( 26 | "Product %s added", product.getName())); 27 | productEvent.setEntityIdentifier( 28 | new EntityIdentifier( 29 | product.getClass(), 30 | product.getId() 31 | )); 32 | session.persist(productEvent); 33 | EntityAttribute productAttribute = 34 | new EntityAttribute(); 35 | productAttribute.setName("AD_CAMPAIGN"); 36 | productAttribute.setValue("LCD_Sales"); 37 | productAttribute.setEntityIdentifier( 38 | new EntityIdentifier( 39 | product.getClass(), 40 | product.getId() 41 | )); 42 | session.persist(productAttribute); 43 | assertSame(1, session.createQuery( 44 | "select ea " + 45 | "from EntityAttribute ea " + 46 | "where " + 47 | " ea.entityIdentifier = :entityIdentifier") 48 | .setParameter("entityIdentifier", 49 | new EntityIdentifier( 50 | product.getClass(), product.getId())) 51 | .list().size()); 52 | return null; 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/entityidentifier/Product.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.entityidentifier; 2 | 3 | import javax.persistence.*; 4 | 5 | /** 6 | * Product - Product 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | @Entity 11 | @Table(name = "product") 12 | public class Product { 13 | 14 | @Id 15 | @GeneratedValue 16 | private Long id; 17 | 18 | private String name; 19 | 20 | public Product() { 21 | } 22 | 23 | public Product(String name) { 24 | this.name = name; 25 | } 26 | 27 | public Long getId() { 28 | return id; 29 | } 30 | 31 | public String getName() { 32 | return name; 33 | } 34 | 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/AutoDirtyCheckingTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.junit.Test; 6 | 7 | import java.util.Date; 8 | 9 | /** 10 | * AutoDirtyCheckingTest - Test to check auto dirty checking capabilities 11 | * 12 | * @author Vlad Mihalcea 13 | */ 14 | public class AutoDirtyCheckingTest extends AbstractTest { 15 | 16 | @Override 17 | protected Class[] entities() { 18 | return new Class[] { 19 | OrderLine.class 20 | }; 21 | } 22 | 23 | @Test 24 | public void testDirtyChecking() { 25 | doInTransaction(session -> { 26 | OrderLine orderLine = new OrderLine(); 27 | session.persist(orderLine); 28 | session.flush(); 29 | orderLine.setNumber(123L); 30 | orderLine.setOrderedBy("Vlad"); 31 | orderLine.setOrderedOn(new Date()); 32 | session.flush(); 33 | orderLine.setOrderedBy("Alex"); 34 | }); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/CustomEntityDirtinessStrategyTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import org.hibernate.CustomEntityDirtinessStrategy; 4 | import org.hibernate.Session; 5 | import org.hibernate.persister.entity.EntityPersister; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.util.Properties; 10 | 11 | /** 12 | * InterceptorDirtyCheckingTest - Test to check CustomEntityDirtinessStrategy dirty checking capabilities 13 | * 14 | * @author Vlad Mihalcea 15 | */ 16 | public class CustomEntityDirtinessStrategyTest extends AutoDirtyCheckingTest { 17 | 18 | private static final Logger LOGGER = LoggerFactory.getLogger(CustomEntityDirtinessStrategyTest.class); 19 | 20 | public static class EntityDirtinessStrategy implements CustomEntityDirtinessStrategy { 21 | 22 | @Override 23 | public boolean canDirtyCheck(Object entity, EntityPersister persister, Session session) { 24 | return entity instanceof DirtyAware; 25 | } 26 | 27 | @Override 28 | public boolean isDirty(Object entity, EntityPersister persister, Session session) { 29 | return !cast(entity).getDirtyProperties().isEmpty(); 30 | } 31 | 32 | @Override 33 | public void resetDirty(Object entity, EntityPersister persister, Session session) { 34 | cast(entity).clearDirtyProperties(); 35 | } 36 | 37 | @Override 38 | public void findDirty(Object entity, EntityPersister persister, Session session, DirtyCheckContext dirtyCheckContext) { 39 | final DirtyAware dirtyAware = cast(entity); 40 | dirtyCheckContext.doDirtyChecking( 41 | new AttributeChecker() { 42 | @Override 43 | public boolean isDirty(AttributeInformation attributeInformation) { 44 | String propertyName = attributeInformation.getName(); 45 | boolean dirty = dirtyAware.getDirtyProperties().contains( propertyName ); 46 | if (dirty) { 47 | LOGGER.info("The {} property is dirty", propertyName); 48 | } 49 | return dirty; 50 | } 51 | } 52 | ); 53 | } 54 | 55 | private DirtyAware cast(Object entity) { 56 | return DirtyAware.class.cast(entity); 57 | } 58 | } 59 | 60 | @Override 61 | protected Properties getProperties() { 62 | Properties properties = super.getProperties(); 63 | properties.setProperty("hibernate.entity_dirtiness_strategy", EntityDirtinessStrategy.class.getName()); 64 | return properties; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/DirtyAware.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * DirtyAware - Dirty Aware 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | public interface DirtyAware { 11 | 12 | Set getDirtyProperties(); 13 | 14 | void clearDirtyProperties(); 15 | } 16 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/FlushTypeTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.FlushMode; 5 | import org.hibernate.Session; 6 | import org.junit.Test; 7 | 8 | import java.math.BigInteger; 9 | 10 | import static org.junit.Assert.assertEquals; 11 | import static org.junit.Assert.assertNull; 12 | 13 | /** 14 | * FlushTypeTest - Test to prove flushing capabilities 15 | * 16 | * @author Vlad Mihalcea 17 | */ 18 | public class FlushTypeTest extends AbstractTest { 19 | 20 | @Override 21 | protected Class[] entities() { 22 | return new Class[] { 23 | Product.class, 24 | User.class, 25 | }; 26 | } 27 | 28 | @Override 29 | protected String[] packages() { 30 | return new String[] { 31 | getClass().getPackage().getName() 32 | }; 33 | } 34 | 35 | @Test 36 | public void testAutoFlushHQL() { 37 | doInTransaction(session -> { 38 | Product product = new Product(); 39 | session.persist(product); 40 | LOGGER.info("Check if Product is flushed when selecting Users using HQL"); 41 | assertEquals(0L, session.createQuery("select count(id) from User").uniqueResult()); 42 | assertEquals(product.getId(), session.createQuery("select p.id from Product p").uniqueResult()); 43 | return null; 44 | 45 | }); 46 | } 47 | 48 | @Test 49 | public void testAutoFlushHQLSubSelect() { 50 | doInTransaction(session -> { 51 | Product product = new Product(); 52 | product.setColor("Blue"); 53 | session.persist(product); 54 | LOGGER.info("Check if Product is flushed, HQL + sub-select"); 55 | assertEquals(0L, session.createQuery( 56 | "select count(*) " + 57 | "from User u " + 58 | "where u.favoriteColor in (select distinct(p.color) from Product p)" 59 | ).uniqueResult()); 60 | return null; 61 | 62 | }); 63 | } 64 | 65 | @Test 66 | public void testAutoFlushHQLThetaJoinSelect() { 67 | doInTransaction(session -> { 68 | Product product = new Product(); 69 | product.setColor("Blue"); 70 | session.persist(product); 71 | LOGGER.info("Check if Product is flushed, HQL + theta style join"); 72 | assertEquals(0L, session.createQuery( 73 | "select count(*) " + 74 | "from User u, Product p " + 75 | "where u.favoriteColor = p.color" 76 | ).uniqueResult()); 77 | return null; 78 | 79 | }); 80 | } 81 | 82 | @Test 83 | public void testAutoFlushSQLQuery() { 84 | doInTransaction(session -> { 85 | Product product = new Product(); 86 | session.persist(product); 87 | LOGGER.info("Check if Product is flushed when selecting Users using SQL"); 88 | assertEquals(BigInteger.ZERO, session.createSQLQuery("select count(id) from user").uniqueResult()); 89 | assertNull(session.createSQLQuery("select id from product").uniqueResult()); 90 | return null; 91 | 92 | }); 93 | } 94 | 95 | @Test 96 | public void testAutoFlushSQLAlwaysFlush() { 97 | doInTransaction(session -> { 98 | Product product = new Product(); 99 | session.persist(product); 100 | LOGGER.info("Check if Product is flushed when selecting Users using SQL with ALWAYS flush mode"); 101 | assertEquals(BigInteger.ZERO, session.createSQLQuery("select count(id) from user").uniqueResult()); 102 | assertEquals(product.getId(), session.createSQLQuery("select id from product").setFlushMode(FlushMode.ALWAYS).uniqueResult()); 103 | return null; 104 | 105 | }); 106 | } 107 | 108 | @Test 109 | public void testAutoFlushSQLAddSynchronization() { 110 | doInTransaction(session -> { 111 | Product product = new Product(); 112 | session.persist(product); 113 | LOGGER.info("Check if Product is flushed when selecting Users using SQL with synchronization"); 114 | assertEquals(BigInteger.ZERO, session.createSQLQuery("select count(id) from user").uniqueResult()); 115 | assertEquals(product.getId(), session.createSQLQuery("select id from product").addSynchronizedEntityClass(Product.class).uniqueResult()); 116 | return null; 117 | 118 | }); 119 | } 120 | 121 | 122 | 123 | @Test 124 | public void testAutoFlushSQLNamedQuery() { 125 | doInTransaction(session -> { 126 | Product product = new Product(); 127 | session.persist(product); 128 | LOGGER.info("Check if Product is flushed when selecting Users using SQL with named query"); 129 | assertEquals(BigInteger.ZERO, session.createSQLQuery("select count(id) from user").uniqueResult()); 130 | assertNull(session.getNamedQuery("product_ids").uniqueResult()); 131 | return null; 132 | }); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/InterceptorDirtyCheckingTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import org.hibernate.EmptyInterceptor; 4 | import org.hibernate.Interceptor; 5 | import org.hibernate.type.Type; 6 | 7 | import java.io.Serializable; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | /** 13 | * InterceptorDirtyCheckingTest - Test to check interceptor dirty checking capabilities 14 | * 15 | * @author Vlad Mihalcea 16 | */ 17 | public class InterceptorDirtyCheckingTest extends AutoDirtyCheckingTest { 18 | 19 | public class DirtyCheckingInterceptor extends EmptyInterceptor { 20 | @Override 21 | public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) { 22 | if(entity instanceof DirtyAware) { 23 | DirtyAware dirtyAware = (DirtyAware) entity; 24 | Set dirtyProperties = dirtyAware.getDirtyProperties(); 25 | int[] dirtyPropertiesIndices = new int[dirtyProperties.size()]; 26 | List propertyNamesList = Arrays.asList(propertyNames); 27 | int i = 0; 28 | for(String dirtyProperty : dirtyProperties) { 29 | LOGGER.info("The {} property is dirty", dirtyProperty); 30 | dirtyPropertiesIndices[i++] = propertyNamesList.indexOf(dirtyProperty); 31 | } 32 | dirtyAware.clearDirtyProperties(); 33 | return dirtyPropertiesIndices; 34 | } 35 | return super.findDirty(entity, id, currentState, previousState, propertyNames, types); 36 | } 37 | } 38 | 39 | @Override 40 | protected Interceptor interceptor() { 41 | return new DirtyCheckingInterceptor(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/MergeWithTransientOnInverseSideTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractPostgreSQLIntegrationTest; 4 | import org.junit.Test; 5 | 6 | import javax.persistence.*; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | /** 11 | * SqlCascadeDeleteBatchingTest - Test to check the SQL cascade delete 12 | * 13 | * @author Vlad Mihalcea 14 | */ 15 | public class MergeWithTransientOnInverseSideTest extends AbstractPostgreSQLIntegrationTest { 16 | 17 | @Override 18 | protected Class[] entities() { 19 | return new Class[]{ 20 | Post.class, 21 | Comment.class 22 | }; 23 | } 24 | 25 | @Test 26 | public void testMergeDetached() { 27 | 28 | final Post post = doInTransaction(session -> { 29 | Post _post = new Post("Post"); 30 | session.persist(_post); 31 | return _post; 32 | }); 33 | 34 | doInTransaction(session -> { 35 | post.getComments().add(new Comment()); 36 | session.merge(post); 37 | }); 38 | } 39 | 40 | @Test 41 | public void testMergeTransient() { 42 | 43 | doInTransaction(session -> { 44 | Post _post = new Post("Post"); 45 | _post.getComments().add(new Comment()); 46 | session.persist(_post); 47 | return _post; 48 | }); 49 | } 50 | 51 | @Entity(name = "Post") 52 | public static class Post { 53 | 54 | @Id 55 | @GeneratedValue 56 | private Long id; 57 | 58 | private String title; 59 | 60 | @Version 61 | private int version; 62 | 63 | private Post() { 64 | } 65 | 66 | public Post(String title) { 67 | this.title = title; 68 | } 69 | 70 | @OneToMany(mappedBy = "post") 71 | private List comments = new ArrayList<>(); 72 | 73 | public void setTitle(String title) { 74 | this.title = title; 75 | } 76 | 77 | public List getComments() { 78 | return comments; 79 | } 80 | 81 | public void addComment(Comment comment) { 82 | comments.add(comment); 83 | comment.setPost(this); 84 | } 85 | } 86 | 87 | @Entity(name = "Comment") 88 | public static class Comment { 89 | 90 | @Id 91 | @GeneratedValue 92 | private Long id; 93 | 94 | @ManyToOne(fetch = FetchType.LAZY) 95 | @JoinColumn(name = "post_id", nullable = false) 96 | private Post post; 97 | 98 | @Version 99 | private int version; 100 | 101 | private Comment() {} 102 | 103 | public Comment(String review) { 104 | this.review = review; 105 | } 106 | 107 | private String review; 108 | 109 | public Long getId() { 110 | return id; 111 | } 112 | 113 | public void setPost(Post post) { 114 | this.post = post; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/OrderLine.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import javax.persistence.*; 4 | import java.util.Date; 5 | 6 | /** 7 | * Order - Order 8 | * 9 | * @author Vlad Mihalcea 10 | */ 11 | @Entity 12 | @Table(name = "ORDER_LINE") 13 | public class OrderLine extends SelfDirtyCheckingEntity { 14 | 15 | @Id 16 | @GeneratedValue(strategy = GenerationType.AUTO) 17 | private Long id; 18 | 19 | private Long number; 20 | 21 | private String orderedBy; 22 | 23 | private Date orderedOn; 24 | 25 | public Long getId() { 26 | return id; 27 | } 28 | 29 | public Long getNumber() { 30 | return number; 31 | } 32 | 33 | public void setNumber(Long number) { 34 | this.number = number; 35 | markDirtyProperty(); 36 | } 37 | 38 | public String getOrderedBy() { 39 | return orderedBy; 40 | } 41 | 42 | public void setOrderedBy(String orderedBy) { 43 | this.orderedBy = orderedBy; 44 | markDirtyProperty(); 45 | } 46 | 47 | public Date getOrderedOn() { 48 | return orderedOn; 49 | } 50 | 51 | public void setOrderedOn(Date orderedOn) { 52 | this.orderedOn = orderedOn; 53 | markDirtyProperty(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/Product.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import javax.persistence.*; 4 | 5 | /** 6 | * Product - Product 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | @Entity 11 | @Table(name = "product") 12 | @NamedNativeQueries( 13 | @NamedNativeQuery(name = "product_ids", query = "select id from product") 14 | ) 15 | public class Product { 16 | 17 | @Id 18 | @GeneratedValue(generator = "uuid2") 19 | private String id; 20 | 21 | private String color; 22 | 23 | public Product() { 24 | } 25 | 26 | public String getId() { 27 | return id; 28 | } 29 | 30 | public String getColor() { 31 | return color; 32 | } 33 | 34 | public void setColor(String color) { 35 | this.color = color; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/SelfDirtyCheckingEntity.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import javax.persistence.Transient; 4 | import java.beans.BeanInfo; 5 | import java.beans.IntrospectionException; 6 | import java.beans.Introspector; 7 | import java.beans.PropertyDescriptor; 8 | import java.lang.reflect.Method; 9 | import java.util.HashMap; 10 | import java.util.LinkedHashSet; 11 | import java.util.Map; 12 | import java.util.Set; 13 | 14 | /** 15 | * SelfDirtyCheckingEntity - Manual dirty checking mechanism 16 | * 17 | * @author Vlad Mihalcea 18 | */ 19 | public abstract class SelfDirtyCheckingEntity implements DirtyAware { 20 | 21 | private final Map setterToPropertyMap = new HashMap(); 22 | 23 | @Transient 24 | private Set dirtyProperties = new LinkedHashSet(); 25 | 26 | public SelfDirtyCheckingEntity() { 27 | try { 28 | BeanInfo beanInfo = Introspector.getBeanInfo(getClass()); 29 | PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); 30 | for (PropertyDescriptor descriptor : descriptors) { 31 | Method setter = descriptor.getWriteMethod(); 32 | if (setter != null) { 33 | setterToPropertyMap.put(setter.getName(), descriptor.getName()); 34 | } 35 | } 36 | } catch (IntrospectionException e) { 37 | throw new IllegalStateException(e); 38 | } 39 | 40 | } 41 | 42 | @Override 43 | public Set getDirtyProperties() { 44 | return dirtyProperties; 45 | } 46 | 47 | @Override 48 | public void clearDirtyProperties() { 49 | dirtyProperties.clear(); 50 | } 51 | 52 | protected void markDirtyProperty() { 53 | String methodName = Thread.currentThread().getStackTrace()[2].getMethodName(); 54 | dirtyProperties.add(setterToPropertyMap.get(methodName)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/User.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | /** 9 | * User - User 10 | * 11 | * @author Vlad Mihalcea 12 | */ 13 | @Entity 14 | @Table(name = "user") 15 | public class User { 16 | 17 | @Id 18 | @GeneratedValue(generator = "uuid2") 19 | private String id; 20 | 21 | private String favoriteColor; 22 | 23 | public User() { 24 | } 25 | 26 | public String getId() { 27 | return id; 28 | } 29 | 30 | public String getFavoriteColor() { 31 | return favoriteColor; 32 | } 33 | 34 | public void setFavoriteColor(String favoriteColor) { 35 | this.favoriteColor = favoriteColor; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/package-info.java: -------------------------------------------------------------------------------- 1 | @GenericGenerators( 2 | { 3 | @GenericGenerator( 4 | name = "uuid2", 5 | strategy = "uuid2" 6 | ) 7 | } 8 | ) 9 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 10 | 11 | import org.hibernate.annotations.GenericGenerator; 12 | import org.hibernate.annotations.GenericGenerators; -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/AbstractPooledSequenceIdentifierTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.hibernate.jdbc.Work; 6 | 7 | import java.math.BigDecimal; 8 | import java.sql.Connection; 9 | import java.sql.SQLException; 10 | import java.sql.Statement; 11 | import java.util.List; 12 | import java.util.Properties; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | 16 | public abstract class AbstractPooledSequenceIdentifierTest extends AbstractTest { 17 | 18 | protected abstract Object newEntityInstance(); 19 | 20 | @Override 21 | protected Properties getProperties() { 22 | Properties properties = super.getProperties(); 23 | properties.put("hibernate.id.new_generator_mappings", "true"); 24 | return properties; 25 | } 26 | 27 | protected void insertSequences() { 28 | LOGGER.debug("testSequenceIdentifierGenerator"); 29 | doInTransaction(session -> { 30 | for (int i = 0; i < 8; i++) { 31 | session.persist(newEntityInstance()); 32 | } 33 | session.flush(); 34 | assertEquals(8, ((Number) session.createSQLQuery("SELECT COUNT(*) FROM sequenceIdentifier").uniqueResult()).intValue()); 35 | insertNewRow(session); 36 | insertNewRow(session); 37 | insertNewRow(session); 38 | assertEquals(11, ((Number) session.createSQLQuery("SELECT COUNT(*) FROM sequenceIdentifier").uniqueResult()).intValue()); 39 | List ids = session.createSQLQuery("SELECT id FROM sequenceIdentifier").list(); 40 | for (Number id : ids) { 41 | LOGGER.debug("Found id: {}", id); 42 | } 43 | for (int i = 0; i < 3; i++) { 44 | session.persist(newEntityInstance()); 45 | } 46 | session.flush(); 47 | }); 48 | } 49 | 50 | private void insertNewRow(Session session) { 51 | session.doWork(new Work() { 52 | @Override 53 | public void execute(Connection connection) throws SQLException { 54 | Statement statement = null; 55 | try { 56 | statement = connection.createStatement(); 57 | statement.executeUpdate("INSERT INTO sequenceIdentifier VALUES NEXT VALUE FOR hibernate_sequence"); 58 | } finally { 59 | if (statement != null) { 60 | statement.close(); 61 | } 62 | } 63 | } 64 | }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/AssignedTableGenerator.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import org.hibernate.engine.spi.SessionImplementor; 4 | import org.hibernate.id.enhanced.TableGenerator; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * AssignedTableGenerator - Assigned TableGenerator 10 | * 11 | * @author Vlad Mihalcea 12 | */ 13 | public class AssignedTableGenerator extends TableGenerator { 14 | 15 | @Override 16 | public Serializable generate(SessionImplementor session, Object obj) { 17 | if(obj instanceof Identifiable) { 18 | Identifiable identifiable = (Identifiable) obj; 19 | Serializable id = identifiable.getId(); 20 | if(id != null) { 21 | return id; 22 | } 23 | } 24 | return super.generate(session, obj); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/AutoIdentifierMySQLTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.GenerationType; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | 9 | import org.junit.Test; 10 | 11 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractMySQLIntegrationTest; 12 | 13 | public class AutoIdentifierMySQLTest extends AbstractMySQLIntegrationTest { 14 | 15 | @Override 16 | protected Class[] entities() { 17 | return new Class[] { 18 | Post.class, 19 | }; 20 | } 21 | 22 | @Override 23 | protected boolean nativeHibernateSessionFactoryBootstrap() { 24 | return false; 25 | } 26 | 27 | @Test 28 | public void test() { 29 | doInJPA(entityManager -> { 30 | for ( int i = 1; i <= 3; i++ ) { 31 | entityManager.persist( 32 | new Post( 33 | String.format( 34 | "High-Performance Java Persistence, Part %d", i 35 | ) 36 | ) 37 | ); 38 | } 39 | }); 40 | } 41 | 42 | @Entity(name = "Post") 43 | @Table(name = "post") 44 | public static class Post { 45 | 46 | @Id 47 | @GeneratedValue(strategy = GenerationType.AUTO) 48 | private Long id; 49 | 50 | private String title; 51 | 52 | public Post() {} 53 | 54 | public Post(String title) { 55 | this.title = title; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/EnhancedSequenceVsTableGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import java.util.Properties; 4 | 5 | public class EnhancedSequenceVsTableGeneratorTest extends SequenceVsTableGeneratorTest { 6 | 7 | @Override 8 | protected Properties getProperties() { 9 | Properties properties = super.getProperties(); 10 | properties.put("hibernate.id.new_generator_mappings", "true"); 11 | return properties; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/HiloIdentifierTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.annotations.GenericGenerator; 5 | import org.hibernate.annotations.Parameter; 6 | import org.junit.Test; 7 | 8 | import javax.persistence.Entity; 9 | import javax.persistence.GeneratedValue; 10 | import javax.persistence.GenerationType; 11 | import javax.persistence.Id; 12 | 13 | public class HiloIdentifierTest extends AbstractTest { 14 | 15 | @Override 16 | protected Class[] entities() { 17 | return new Class[] { 18 | HiloIdentifierTest.Hilo.class 19 | }; 20 | } 21 | 22 | @Test 23 | public void testHiloIdentifierGenerator() { 24 | doInTransaction(session -> { 25 | for(int i = 0; i < 8; i++) { 26 | Hilo hilo = new Hilo(); 27 | session.persist(hilo); 28 | } 29 | }); 30 | } 31 | 32 | /** 33 | * Hilo - Hilo 34 | * 35 | * @author Vlad Mihalcea 36 | */ 37 | @Entity(name = "hilo") 38 | public static class Hilo { 39 | 40 | @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "hilo_sequence_generator") 41 | @GenericGenerator( 42 | name = "hilo_sequence_generator", 43 | strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", 44 | parameters = { 45 | @Parameter(name = "sequence_name", value = "hilo_seqeunce"), 46 | @Parameter(name = "initial_value", value = "1"), 47 | @Parameter(name = "increment_size", value = "3"), 48 | @Parameter(name = "optimizer", value = "hilo") 49 | }) 50 | @Id 51 | private Long id; 52 | 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/Identifiable.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Identifiable - Identifiable 7 | * 8 | * @author Vlad Mihalcea 9 | */ 10 | public interface Identifiable { 11 | 12 | T getId(); 13 | } 14 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/IdentityVsSequenceIdentifierTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import java.util.Properties; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.GenerationType; 7 | import javax.persistence.Id; 8 | 9 | import org.hibernate.annotations.GenericGenerator; 10 | 11 | import org.junit.Test; 12 | 13 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 14 | 15 | public class IdentityVsSequenceIdentifierTest extends AbstractTest { 16 | 17 | @Override 18 | protected Class[] entities() { 19 | return new Class[] { 20 | IdentityIdentifier.class, 21 | SequenceIdentifier.class, 22 | TableSequenceIdentifier.class, 23 | AssignTableSequenceIdentifier.class 24 | }; 25 | } 26 | 27 | @Override 28 | protected Properties getProperties() { 29 | Properties properties = super.getProperties(); 30 | properties.put("hibernate.order_inserts", "true"); 31 | properties.put("hibernate.order_updates", "true"); 32 | properties.put("hibernate.jdbc.batch_size", "2"); 33 | return properties; 34 | } 35 | 36 | @Test 37 | public void testIdentityIdentifierGenerator() { 38 | LOGGER.debug("testIdentityIdentifierGenerator"); 39 | doInTransaction(session -> { 40 | for (int i = 0; i < 5; i++) { 41 | session.persist(new IdentityIdentifier()); 42 | } 43 | session.flush(); 44 | return null; 45 | 46 | }); 47 | } 48 | 49 | @Test 50 | public void testSequenceIdentifierGenerator() { 51 | LOGGER.debug("testSequenceIdentifierGenerator"); 52 | doInTransaction(session -> { 53 | for (int i = 0; i < 5; i++) { 54 | session.persist(new SequenceIdentifier()); 55 | } 56 | session.flush(); 57 | return null; 58 | 59 | }); 60 | } 61 | 62 | @Test 63 | public void testTableSequenceIdentifierGenerator() { 64 | LOGGER.debug("testTableSequenceIdentifierGenerator"); 65 | doInTransaction(session -> { 66 | for (int i = 0; i < 5; i++) { 67 | session.persist(new TableSequenceIdentifier()); 68 | } 69 | session.flush(); 70 | return null; 71 | 72 | }); 73 | } 74 | 75 | @Test 76 | public void testAssignTableSequenceIdentifierGenerator() { 77 | LOGGER.debug("testAssignTableSequenceIdentifierGenerator"); 78 | doInTransaction(session -> { 79 | for (int i = 0; i < 5; i++) { 80 | session.persist(new AssignTableSequenceIdentifier()); 81 | } 82 | AssignTableSequenceIdentifier tableSequenceIdentifier = new AssignTableSequenceIdentifier(); 83 | tableSequenceIdentifier.id = -1L; 84 | session.merge(tableSequenceIdentifier); 85 | session.flush(); 86 | }); 87 | } 88 | 89 | @Entity(name = "identityIdentifier") 90 | public static class IdentityIdentifier { 91 | 92 | @Id 93 | @GeneratedValue(strategy = GenerationType.IDENTITY) 94 | private Long id; 95 | } 96 | 97 | @Entity(name = "sequenceIdentifier") 98 | public static class SequenceIdentifier { 99 | 100 | @Id 101 | @GenericGenerator(name = "sequence", strategy = "sequence", parameters = { 102 | @org.hibernate.annotations.Parameter(name = "sequence", value = "sequence") 103 | }) 104 | @GeneratedValue(generator = "sequence") 105 | private Long id; 106 | } 107 | 108 | @Entity(name = "tableIdentifier") 109 | public static class TableSequenceIdentifier { 110 | 111 | @Id 112 | @GenericGenerator(name = "table", strategy = "enhanced-table", parameters = { 113 | @org.hibernate.annotations.Parameter(name = "table_name", value = "sequence_table") 114 | }) 115 | @GeneratedValue(generator = "table", strategy=GenerationType.TABLE) 116 | private Long id; 117 | } 118 | 119 | @Entity(name = "assigneTableIdentifier") 120 | public static class AssignTableSequenceIdentifier implements Identifiable { 121 | 122 | @Id 123 | @GenericGenerator(name = "table", strategy = "com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator.AssignedTableGenerator", 124 | parameters = { 125 | @org.hibernate.annotations.Parameter(name = "table_name", value = "sequence_table") 126 | }) 127 | @GeneratedValue(generator = "table", strategy=GenerationType.TABLE) 128 | private Long id; 129 | 130 | @Override 131 | public Long getId() { 132 | return id; 133 | } 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/PooledLoSequenceIdentifierTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import org.hibernate.annotations.GenericGenerator; 4 | import org.junit.Test; 5 | 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.GenerationType; 9 | import javax.persistence.Id; 10 | 11 | public class PooledLoSequenceIdentifierTest extends AbstractPooledSequenceIdentifierTest { 12 | 13 | @Override 14 | protected Class[] entities() { 15 | return new Class[] { 16 | PooledLoSequenceIdentifier.class 17 | }; 18 | } 19 | 20 | @Override 21 | protected Object newEntityInstance() { 22 | return new PooledLoSequenceIdentifier(); 23 | } 24 | 25 | @Test 26 | public void testPooledOptimizerSuccess() { 27 | insertSequences(); 28 | } 29 | 30 | @Entity(name = "sequenceIdentifier") 31 | public static class PooledLoSequenceIdentifier { 32 | 33 | @Id 34 | @GenericGenerator(name = "sequenceGenerator", strategy = "enhanced-sequence", 35 | parameters = { 36 | @org.hibernate.annotations.Parameter(name = "optimizer", 37 | value = "pooled-lo" 38 | ), 39 | @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"), 40 | @org.hibernate.annotations.Parameter(name = "increment_size", value = "5") 41 | } 42 | ) 43 | @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") 44 | private Long id; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/PooledSequenceIdentifierTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.GenerationType; 6 | import javax.persistence.Id; 7 | 8 | import org.hibernate.annotations.GenericGenerator; 9 | import org.hibernate.exception.ConstraintViolationException; 10 | 11 | import org.junit.Ignore; 12 | import org.junit.Test; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.fail; 16 | 17 | public class PooledSequenceIdentifierTest extends AbstractPooledSequenceIdentifierTest { 18 | 19 | @Override 20 | protected Class[] entities() { 21 | return new Class[] { 22 | PooledSequenceIdentifier.class, 23 | }; 24 | } 25 | 26 | protected Object newEntityInstance() { 27 | return new PooledSequenceIdentifier(); 28 | } 29 | 30 | @Test 31 | @Ignore 32 | public void testPooledOptimizerThrowsException() { 33 | try { 34 | insertSequences(); 35 | fail("Expecting ConstraintViolationException!"); 36 | } catch (Exception e) { 37 | assertEquals(ConstraintViolationException.class, e.getClass()); 38 | LOGGER.error("Pooled optimizer threw", e); 39 | } 40 | } 41 | 42 | @Entity(name = "sequenceIdentifier") 43 | public static class PooledSequenceIdentifier { 44 | 45 | @Id 46 | @GenericGenerator(name = "sequenceGenerator", strategy = "enhanced-sequence", 47 | parameters = { 48 | @org.hibernate.annotations.Parameter(name = "optimizer", 49 | value = "pooled" 50 | ), 51 | @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"), 52 | @org.hibernate.annotations.Parameter(name = "increment_size", value = "5") 53 | } 54 | ) 55 | @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") 56 | private Long id; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/PostgreSQLAutoTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import java.util.Properties; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.GenerationType; 7 | import javax.persistence.Id; 8 | 9 | import org.junit.Test; 10 | 11 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractPostgreSQLIntegrationTest; 12 | 13 | public class PostgreSQLAutoTest extends AbstractPostgreSQLIntegrationTest { 14 | 15 | @Override 16 | protected Class[] entities() { 17 | return new Class[] { 18 | Post.class, 19 | }; 20 | } 21 | 22 | @Override 23 | protected Properties getProperties() { 24 | Properties properties = super.getProperties(); 25 | properties.put("hibernate.order_inserts", "true"); 26 | properties.put("hibernate.order_updates", "true"); 27 | properties.put("hibernate.jdbc.batch_size", "5"); 28 | return properties; 29 | } 30 | 31 | @Test 32 | public void testBatch() { 33 | doInTransaction(session -> { 34 | for (int i = 0; i < 3; i++) { 35 | Post post = new Post(); 36 | post.setTitle( 37 | String.format("High-Performance Java Persistence, Part %d", i + 1) 38 | ); 39 | 40 | session.persist(post); 41 | } 42 | }); 43 | } 44 | 45 | @Entity(name = "Post") 46 | public static class Post { 47 | 48 | @Id 49 | @GeneratedValue(strategy = GenerationType.AUTO) 50 | private Long id; 51 | 52 | private String title; 53 | 54 | public Long getId() { 55 | return id; 56 | } 57 | 58 | public void setId(Long id) { 59 | this.id = id; 60 | } 61 | 62 | public String getTitle() { 63 | return title; 64 | } 65 | 66 | public void setTitle(String title) { 67 | this.title = title; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/SequenceVsTableGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.util.Properties; 9 | 10 | public class SequenceVsTableGeneratorTest extends AbstractTest { 11 | 12 | @Override 13 | protected Class[] entities() { 14 | return new Class[] { 15 | SequenceIdentifier.class, 16 | TableSequenceIdentifier.class 17 | }; 18 | } 19 | 20 | @Override 21 | protected Properties getProperties() { 22 | Properties properties = super.getProperties(); 23 | return properties; 24 | } 25 | 26 | @Test 27 | public void testSequenceIdentifierGenerator() { 28 | LOGGER.debug("testSequenceIdentifierGenerator"); 29 | doInTransaction(session -> { 30 | for (int i = 0; i < 5; i++) { 31 | session.persist(new SequenceIdentifier()); 32 | } 33 | session.flush(); 34 | }); 35 | } 36 | 37 | @Test 38 | public void testTableSequenceIdentifierGenerator() { 39 | LOGGER.debug("testTableSequenceIdentifierGenerator"); 40 | doInTransaction(session -> { 41 | for (int i = 0; i < 5; i++) { 42 | session.persist(new TableSequenceIdentifier()); 43 | } 44 | session.flush(); 45 | }); 46 | } 47 | 48 | @Entity(name = "sequenceIdentifier") 49 | public static class SequenceIdentifier { 50 | 51 | @Id 52 | @GeneratedValue(generator = "sequence", strategy=GenerationType.SEQUENCE) 53 | @SequenceGenerator(name = "sequence", allocationSize = 10) 54 | private Long id; 55 | } 56 | 57 | @Entity(name = "tableIdentifier") 58 | public static class TableSequenceIdentifier { 59 | 60 | @Id 61 | @GeneratedValue(generator = "table", strategy=GenerationType.TABLE) 62 | @TableGenerator(name = "table", allocationSize = 10) 63 | private Long id; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/idgenerator/UUIDIdentifierTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.idgenerator; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.annotations.GenericGenerator; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.Column; 8 | import javax.persistence.Entity; 9 | import javax.persistence.GeneratedValue; 10 | import javax.persistence.Id; 11 | import java.util.UUID; 12 | 13 | import static org.junit.Assert.assertSame; 14 | 15 | public class UUIDIdentifierTest extends AbstractTest { 16 | 17 | @Override 18 | protected Class[] entities() { 19 | return new Class[] { 20 | AssignedUUIDIdentifier.class, 21 | UUIDIdentifier.class, 22 | UUID2Identifier.class 23 | }; 24 | } 25 | 26 | @Test 27 | public void testAssignedIdentifierGenerator() { 28 | LOGGER.debug("testAssignedIdentifierGenerator"); 29 | doInTransaction(session -> { 30 | AssignedUUIDIdentifier assignedUUIDIdentifier = new AssignedUUIDIdentifier(); 31 | LOGGER.debug("persist AssignedUUIDIdentifier"); 32 | session.persist(assignedUUIDIdentifier); 33 | session.flush(); 34 | assertSame(assignedUUIDIdentifier, session 35 | .createQuery("from AssignedUUIDIdentifier where uuid = :uuid") 36 | .setParameter("uuid", assignedUUIDIdentifier.uuid) 37 | .uniqueResult()); 38 | byte[] uuid = (byte[]) session.createSQLQuery("select uuid from AssignedUUIDIdentifier").uniqueResult(); 39 | LOGGER.debug("merge AssignedUUIDIdentifier"); 40 | session.merge(new AssignedUUIDIdentifier()); 41 | }); 42 | } 43 | 44 | @Test 45 | public void testUUIDIdentifierGenerator() { 46 | LOGGER.debug("testUUIDIdentifierGenerator"); 47 | doInTransaction(session -> { 48 | session.persist(new UUIDIdentifier()); 49 | session.flush(); 50 | session.merge(new UUIDIdentifier()); 51 | }); 52 | } 53 | 54 | @Test 55 | public void testUUID2IdentifierGenerator() { 56 | LOGGER.debug("testUUID2IdentifierGenerator"); 57 | doInTransaction(session -> { 58 | session.persist(new UUID2Identifier()); 59 | session.flush(); 60 | session.merge(new UUID2Identifier()); 61 | }); 62 | } 63 | 64 | @Entity(name = "AssignedUUIDIdentifier") 65 | public static class AssignedUUIDIdentifier { 66 | 67 | @Id 68 | @Column(columnDefinition = "BINARY(16)") 69 | private UUID uuid; 70 | 71 | public AssignedUUIDIdentifier() { 72 | this.uuid = UUID.randomUUID(); 73 | } 74 | } 75 | 76 | @Entity(name = "UUIDIdentifier") 77 | public static class UUIDIdentifier { 78 | 79 | @GeneratedValue(generator = "uuid") 80 | @GenericGenerator(name = "uuid", strategy = "uuid") 81 | @Column(columnDefinition = "CHAR(32)") 82 | @Id 83 | private String uuidHex; 84 | } 85 | 86 | @Entity(name = "UUID2Identifier") 87 | public static class UUID2Identifier { 88 | 89 | @GeneratedValue(generator = "uuid2") 90 | @GenericGenerator(name = "uuid2", strategy = "uuid2") 91 | @Column(columnDefinition = "BINARY(16)") 92 | @Id 93 | private UUID uuid; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/inheritance/InheritanceGroupByTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.inheritance; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Criteria; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.util.Date; 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | /** 15 | * InheritanceGroupByTest - Inheritance GroupBy Test 16 | * 17 | * @author Vlad Mihalcea 18 | */ 19 | public class InheritanceGroupByTest extends AbstractTest { 20 | 21 | @Override 22 | protected Class[] entities() { 23 | return new Class[]{ 24 | FirmUser.class 25 | }; 26 | } 27 | 28 | @Test 29 | public void testTree() { 30 | doInTransaction(session -> { 31 | session.save(new FirmUser()); 32 | //List result = session.createQuery("select distinct a from FirmUser a order by a.id").list(); 33 | List result1 = (List) session.createQuery("from FirmUser order by id").list(); 34 | List result2 = (List) session.createQuery("select distinct a, a.id from FirmUser a order by id").list(); 35 | List result3 = (List) session.createSQLQuery( 36 | "select * " + 37 | "from FIRM_USER a " + 38 | "LEFT JOIN BASE_USER b ON a.id = b.id " + 39 | "order by a.id" 40 | ) 41 | .addEntity("a", FirmUser.class) 42 | .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) 43 | .list(); 44 | assertEquals(1, result1.size()); 45 | assertEquals(1, result2.size()); 46 | assertEquals(1, result3.size()); 47 | }); 48 | } 49 | 50 | @MappedSuperclass 51 | public static abstract class GenericHierarchicalDictionary { 52 | 53 | public abstract GenericHierarchicalDictionary getParent(); 54 | 55 | public abstract Set getChildren(); 56 | 57 | } 58 | 59 | @MappedSuperclass 60 | public static abstract class BaseEntity implements java.io.Serializable { 61 | 62 | 63 | private Integer id; 64 | 65 | private Date createdDate = new Date(); 66 | 67 | 68 | public Integer getId() { 69 | return id; 70 | } 71 | 72 | public void setId(Integer id) { 73 | this.id = id; 74 | } 75 | 76 | @Temporal(TemporalType.TIMESTAMP) 77 | @Column(name = "CREATED_DATE", nullable = true) 78 | public Date getCreatedDate() { 79 | return createdDate; 80 | } 81 | 82 | public void setCreatedDate(Date createdDate) { 83 | this.createdDate = createdDate; 84 | } 85 | 86 | } 87 | 88 | @Entity 89 | @Table(name = "BASE_USER") 90 | @Inheritance(strategy = InheritanceType.JOINED) 91 | @AttributeOverride(name = "id", column = @Column(name = "ID", nullable = false, insertable = false, updatable = false)) 92 | public static abstract class BaseUser extends BaseEntity { 93 | 94 | 95 | @Id 96 | @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq") 97 | @SequenceGenerator(name = "seq", sequenceName = "USER_SEQ", allocationSize = 1) 98 | public Integer getId() { 99 | return super.getId(); 100 | } 101 | 102 | } 103 | 104 | @Entity(name = "FirmUser") 105 | @Table(name = "FIRM_USER") 106 | public static class FirmUser extends BaseUser { 107 | 108 | private String name; 109 | 110 | @Column(name = "name") 111 | public String getName() { 112 | return name; 113 | } 114 | 115 | public void setName(String name) { 116 | this.name = name; 117 | } 118 | 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/inheritance/TreeTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.inheritance; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.Session; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.util.HashSet; 9 | import java.util.Set; 10 | 11 | /** 12 | * TreeTest - Tree Test 13 | * 14 | * @author Vlad Mihalcea 15 | */ 16 | public class TreeTest extends AbstractTest { 17 | 18 | @Override 19 | protected Class[] entities() { 20 | return new Class[]{ 21 | LocalFolder.class, 22 | RemoteFolder.class, 23 | }; 24 | } 25 | 26 | @Test 27 | public void testTree() { 28 | LOGGER.debug("testAddWebResource"); 29 | doInTransaction(session -> { 30 | LocalFolder rootLocalFolder = new LocalFolder(); 31 | session.persist(rootLocalFolder); 32 | LocalFolder localFolder1 = new LocalFolder(); 33 | rootLocalFolder.addChild(localFolder1); 34 | session.persist(localFolder1); 35 | LocalFolder localFolder11 = new LocalFolder(); 36 | localFolder1.addChild(localFolder11); 37 | session.persist(localFolder11); 38 | 39 | RemoteFolder rootRemoteFolder = new RemoteFolder(); 40 | session.persist(rootRemoteFolder); 41 | RemoteFolder remoteFolder1 = new RemoteFolder(); 42 | rootRemoteFolder.addChild(remoteFolder1); 43 | session.persist(remoteFolder1); 44 | RemoteFolder remoteFolder11 = new RemoteFolder(); 45 | remoteFolder1.addChild(remoteFolder11); 46 | session.persist(remoteFolder11); 47 | return null; 48 | 49 | }); 50 | } 51 | 52 | @MappedSuperclass 53 | public abstract class GenericHierarchicalDictionary { 54 | 55 | public abstract GenericHierarchicalDictionary getParent(); 56 | 57 | public abstract Set getChildren(); 58 | 59 | } 60 | 61 | @Entity 62 | @Table(name = "LocalFolder") 63 | public class LocalFolder extends GenericHierarchicalDictionary { 64 | 65 | @Id 66 | @GeneratedValue(strategy=GenerationType.IDENTITY) 67 | private Long id; 68 | 69 | @ManyToOne 70 | private LocalFolder parent; 71 | 72 | @OneToMany(mappedBy = "parent") 73 | private Set children = new HashSet(); 74 | 75 | @Override 76 | public LocalFolder getParent() { 77 | return parent; 78 | } 79 | 80 | @Override 81 | public Set getChildren() { 82 | return children; 83 | } 84 | 85 | public void addChild(LocalFolder localFolder) { 86 | localFolder.parent = this; 87 | children.add(localFolder); 88 | } 89 | } 90 | 91 | @Entity 92 | @Table(name = "RemoteFolder") 93 | public class RemoteFolder extends GenericHierarchicalDictionary { 94 | 95 | @Id 96 | @GeneratedValue(strategy=GenerationType.IDENTITY) 97 | private Long id; 98 | 99 | @ManyToOne 100 | private RemoteFolder parent; 101 | 102 | @OneToMany(mappedBy = "parent") 103 | private Set children = new HashSet(); 104 | 105 | @Override 106 | public RemoteFolder getParent() { 107 | return parent; 108 | } 109 | 110 | @Override 111 | public Set getChildren() { 112 | return children; 113 | } 114 | 115 | public void addChild(RemoteFolder localFolder) { 116 | localFolder.parent = this; 117 | children.add(localFolder); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/jpa/RuntimeProxyDirtyCheckingTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.jpa; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.flushing.OrderLine; 4 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractJPATest; 5 | import org.junit.Ignore; 6 | import org.junit.Test; 7 | 8 | import javax.persistence.EntityManager; 9 | import java.util.Date; 10 | import java.util.Properties; 11 | 12 | /** 13 | * RuntimeProxyDirtyCheckingTest - Test to check runtime proxy dirty checking capabilities 14 | * 15 | * @author Vlad Mihalcea 16 | */ 17 | @Ignore 18 | public class RuntimeProxyDirtyCheckingTest extends AbstractJPATest { 19 | 20 | @Override 21 | protected Class[] entities() { 22 | return new Class[] { 23 | OrderLine.class 24 | }; 25 | } 26 | 27 | @Override 28 | protected Properties getProperties() { 29 | Properties properties = super.getProperties(); 30 | properties.setProperty("hibernate.ejb.use_class_enhancer", Boolean.TRUE.toString()); 31 | return properties; 32 | } 33 | 34 | @Test 35 | public void testAutoFlushHQL() { 36 | 37 | doInTransaction(new TransactionCallable() { 38 | @Override 39 | public Void execute(EntityManager entityManager) { 40 | OrderLine orderLine = new OrderLine(); 41 | entityManager.persist(orderLine); 42 | entityManager.flush(); 43 | orderLine.setNumber(123L); 44 | orderLine.setOrderedBy("Vlad"); 45 | orderLine.setOrderedOn(new Date()); 46 | entityManager.flush(); 47 | return null; 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/mapping/BidirectionalOneToOneMapsIdTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.mapping; 2 | 3 | import java.util.Date; 4 | import javax.persistence.CascadeType; 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.FetchType; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.Id; 10 | import javax.persistence.JoinColumn; 11 | import javax.persistence.MapsId; 12 | import javax.persistence.OneToOne; 13 | import javax.persistence.Table; 14 | 15 | import org.junit.Test; 16 | 17 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 18 | 19 | /** 20 | * BidirectionalOneToOneMapsIdTest - Bidirectional @OneToOne Test 21 | * 22 | * @author Vlad Mihalcea 23 | */ 24 | public class BidirectionalOneToOneMapsIdTest extends AbstractTest { 25 | 26 | @Override 27 | protected Class[] entities() { 28 | return new Class[] { 29 | Post.class, 30 | PostDetails.class, 31 | }; 32 | } 33 | 34 | @Test 35 | public void testLifecycle() { 36 | doInJPA(entityManager -> { 37 | Post post = new Post("First post"); 38 | PostDetails details = new PostDetails("John Doe"); 39 | post.setDetails(details); 40 | entityManager.persist(post); 41 | }); 42 | 43 | doInJPA(entityManager -> { 44 | LOGGER.info("Fetching Post"); 45 | Post post = entityManager.find(Post.class, 1L); 46 | /*Post post = entityManager.createQuery( 47 | "select p " + 48 | "from Post p " + 49 | "where p.id = :id", Post.class) 50 | .setParameter("id", 1L) 51 | .getSingleResult();*/ 52 | }); 53 | } 54 | 55 | @Entity(name = "Post") 56 | @Table(name = "post") 57 | public static class Post { 58 | 59 | @Id 60 | @GeneratedValue 61 | private Long id; 62 | 63 | private String title; 64 | 65 | @OneToOne(mappedBy = "post", cascade = CascadeType.ALL, fetch = FetchType.LAZY) 66 | private PostDetails details; 67 | 68 | public Post() {} 69 | 70 | public Post(String title) { 71 | this.title = title; 72 | } 73 | 74 | public Long getId() { 75 | return id; 76 | } 77 | 78 | public void setId(Long id) { 79 | this.id = id; 80 | } 81 | 82 | public String getTitle() { 83 | return title; 84 | } 85 | 86 | public void setTitle(String title) { 87 | this.title = title; 88 | } 89 | 90 | public PostDetails getDetails() { 91 | return details; 92 | } 93 | 94 | public void setDetails(PostDetails details) { 95 | this.details = details; 96 | details.setPost(this); 97 | } 98 | } 99 | 100 | @Entity(name = "PostDetails") 101 | @Table(name = "post_details") 102 | public static class PostDetails { 103 | 104 | @Id 105 | private Long id; 106 | 107 | @Column(name = "created_on") 108 | private Date createdOn; 109 | 110 | @Column(name = "created_by") 111 | private String createdBy; 112 | 113 | @OneToOne(fetch = FetchType.LAZY) 114 | @JoinColumn(name = "id") 115 | @MapsId 116 | private Post post; 117 | 118 | public PostDetails() {} 119 | 120 | public PostDetails(String createdBy) { 121 | createdOn = new Date(); 122 | this.createdBy = createdBy; 123 | } 124 | 125 | public Long getId() { 126 | return id; 127 | } 128 | 129 | public void setId(Long id) { 130 | this.id = id; 131 | } 132 | 133 | public Date getCreatedOn() { 134 | return createdOn; 135 | } 136 | 137 | public String getCreatedBy() { 138 | return createdBy; 139 | } 140 | 141 | public Post getPost() { 142 | return post; 143 | } 144 | 145 | public void setPost(Post post) { 146 | this.post = post; 147 | } 148 | } 149 | 150 | @Override 151 | protected boolean nativeHibernateSessionFactoryBootstrap() { 152 | return false; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/mapping/CompositeIdWithManyToOneTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.mapping; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.io.Serializable; 9 | import java.util.List; 10 | import java.util.Set; 11 | 12 | import static org.junit.Assert.assertEquals; 13 | 14 | /** 15 | * CompositeIdWithManyToOneTest - CompositeIdWithManyToOneTest 16 | * 17 | * @author Vlad Mihalcea 18 | */ 19 | public class CompositeIdWithManyToOneTest extends AbstractTest { 20 | 21 | @Override 22 | protected Class[] entities() { 23 | return new Class[] { 24 | Car.class, 25 | Factory.class, 26 | CarFactory.class 27 | }; 28 | } 29 | 30 | @Before 31 | public void init() { 32 | super.init(); 33 | doInTransaction(session -> { 34 | Car car = new Car(); 35 | car.transmission = "Auto"; 36 | 37 | Car car1 = new Car(); 38 | car1.transmission = "Manual"; 39 | 40 | Factory factory = new Factory(); 41 | session.persist(factory); 42 | session.persist(car); 43 | session.persist(car1); 44 | 45 | CarFactory carFactory = new CarFactory(); 46 | carFactory.setCar(car); 47 | carFactory.setFactory(factory); 48 | 49 | CarFactory carFactory1 = new CarFactory(); 50 | carFactory1.setCar(car1); 51 | carFactory1.setFactory(factory); 52 | 53 | session.persist(carFactory); 54 | session.persist(carFactory1); 55 | }); 56 | } 57 | 58 | @Test 59 | public void test() { 60 | doInTransaction(session -> { 61 | List carFactoryList = session.createQuery("from CarFactory").list(); 62 | assertEquals(2, carFactoryList.size()); 63 | }); 64 | } 65 | 66 | @Entity(name = "Car") 67 | public static class Car implements Serializable { 68 | 69 | @Id 70 | @GeneratedValue 71 | long id; 72 | 73 | @Column(name="transmission", nullable = false) 74 | String transmission; 75 | @OneToMany(fetch = FetchType.LAZY, mappedBy = "car") 76 | Set factories; 77 | } 78 | 79 | @Entity(name = "Factory") 80 | public static class Factory implements Serializable { 81 | 82 | @Id 83 | @GeneratedValue 84 | long id; 85 | } 86 | 87 | @Entity(name = "CarFactory") 88 | public static class CarFactory implements Serializable { 89 | 90 | @Id 91 | @ManyToOne 92 | @JoinColumn(name = "transmission", referencedColumnName = "transmission") 93 | Car car; 94 | 95 | @ManyToOne 96 | @Id 97 | Factory factory; 98 | 99 | public void setCar(Car car) { 100 | this.car = car; 101 | } 102 | 103 | public void setFactory(Factory factory) { 104 | this.factory = factory; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/mapping/ElementCollectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.mapping; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.ObjectNotFoundException; 5 | import org.hibernate.annotations.CacheConcurrencyStrategy; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import javax.persistence.*; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.Properties; 13 | 14 | import static org.junit.Assert.assertEquals; 15 | import static org.junit.Assert.assertFalse; 16 | 17 | 18 | /** 19 | * ElementCollectionTest - Test to check how to speed-up @ElementCollection operations 20 | * 21 | * @author Vlad Mihalcea 22 | */ 23 | public class ElementCollectionTest extends AbstractTest { 24 | 25 | @Override 26 | protected Class[] entities() { 27 | return new Class[] { 28 | Patch.class 29 | }; 30 | } 31 | 32 | @Before 33 | public void init() { 34 | super.init(); 35 | doInTransaction(session -> { 36 | Patch patch = new Patch(); 37 | patch.getChanges().add(new Change("README.txt", "0a1,5...")); 38 | patch.getChanges().add(new Change("web.xml", "17c17...")); 39 | session.persist(patch); 40 | }); 41 | } 42 | 43 | @Test 44 | public void testAddingEmbeddable() { 45 | LOGGER.info("Adding embeddable"); 46 | doInTransaction(session -> { 47 | Patch patch = (Patch) session.get(Patch.class, 1L); 48 | patch.getChanges().add(new Change("web.xml", "1d17...")); 49 | }); 50 | } 51 | 52 | @Test 53 | public void testAddingFirstEmbeddable() { 54 | LOGGER.info("Adding first embeddable"); 55 | doInTransaction(session -> { 56 | Patch patch = (Patch) session.get(Patch.class, 1L); 57 | patch.getChanges().add(0, new Change("web.xml", "1d17...")); 58 | }); 59 | } 60 | 61 | @Test 62 | public void testRemovingEmbeddable() { 63 | LOGGER.info("Removing embeddable"); 64 | doInTransaction(session -> { 65 | Patch patch = (Patch) session.get(Patch.class, 1L); 66 | patch.getChanges().remove(0); 67 | }); 68 | } 69 | 70 | @Test 71 | public void testRemovingLastEmbeddable() { 72 | LOGGER.info("Removing last embeddable"); 73 | doInTransaction(session -> { 74 | Patch patch = (Patch) session.get(Patch.class, 1L); 75 | patch.getChanges().remove(patch.getChanges().size() - 1); 76 | }); 77 | } 78 | 79 | @Test 80 | public void testRemovingMiddleEmbeddable() { 81 | LOGGER.info("Removing middle embeddable"); 82 | doInTransaction(session -> { 83 | Patch patch = (Patch) session.get(Patch.class, 1L); 84 | patch.getChanges().add(new Change("web.xml", "1d17...")); 85 | patch.getChanges().add(new Change("server.xml", "3a5...")); 86 | }); 87 | doInTransaction(session -> { 88 | Patch patch = (Patch) session.get(Patch.class, 1L); 89 | patch.getChanges().remove(1); 90 | }); 91 | } 92 | 93 | /** 94 | * Patch - Patch 95 | * 96 | * @author Vlad Mihalcea 97 | */ 98 | @Entity(name = "Patch") 99 | public static class Patch { 100 | 101 | @Id 102 | @GeneratedValue(strategy = GenerationType.AUTO) 103 | private Long id; 104 | 105 | @ElementCollection 106 | @CollectionTable( 107 | name="patch_change", 108 | joinColumns=@JoinColumn(name="patch_id") 109 | ) 110 | @OrderColumn(name = "index_id") 111 | private List changes = new ArrayList<>(); 112 | 113 | public List getChanges() { 114 | return changes; 115 | } 116 | } 117 | 118 | /** 119 | * Change - Change 120 | * 121 | * @author Vlad Mihalcea 122 | */ 123 | @Embeddable 124 | public static class Change { 125 | 126 | @Column(name = "path", nullable = false) 127 | private String path; 128 | 129 | @Column(name = "diff", nullable = false) 130 | private String diff; 131 | 132 | public Change() { 133 | } 134 | 135 | public Change(String path, String diff) { 136 | this.path = path; 137 | this.diff = diff; 138 | } 139 | 140 | public String getPath() { 141 | return path; 142 | } 143 | 144 | public String getDiff() { 145 | return diff; 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/mapping/IndexOverrideTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.mapping; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.*; 8 | import java.util.List; 9 | import java.util.UUID; 10 | 11 | /** 12 | * IndexOverrideTest - 13 | * 14 | * @author Vlad Mihalcea 15 | */ 16 | public class IndexOverrideTest extends AbstractTest { 17 | 18 | @Override 19 | protected Class[] entities() { 20 | return new Class[] { 21 | Base.class, 22 | ChildY.class, 23 | ChildZ.class 24 | }; 25 | } 26 | 27 | @Before 28 | public void init() { 29 | super.init(); 30 | doInTransaction(session -> { 31 | ChildY childy = new ChildY(); 32 | ChildZ childz = new ChildZ(); 33 | session.persist(childy); 34 | session.persist(childz); 35 | }); 36 | } 37 | 38 | @Test 39 | public void testIndex() { 40 | doInTransaction(session -> { 41 | List bases = session.createQuery("from Base").list(); 42 | bases.stream().forEach(base -> base.setX(UUID.randomUUID().toString())); 43 | }); 44 | } 45 | 46 | @Entity(name = "Base") 47 | @Table(name="Base") 48 | @Inheritance(strategy = InheritanceType.JOINED) 49 | public static abstract class Base { 50 | 51 | @Id 52 | @GeneratedValue(strategy = GenerationType.AUTO) 53 | private Long id; 54 | 55 | @Transient 56 | protected String x; 57 | 58 | public Long getId() { 59 | return id; 60 | } 61 | 62 | public String getX() { 63 | return x; 64 | } 65 | 66 | public void setX(String x) { 67 | this.x = x; 68 | } 69 | } 70 | 71 | @Entity(name = "ChildY") 72 | @Table(name="ChildY") 73 | @DiscriminatorValue("Y") 74 | public static class ChildY extends Base { 75 | 76 | private String y; 77 | 78 | @Override 79 | @org.hibernate.annotations.Index(name = "xy") 80 | @Access(AccessType.PROPERTY) 81 | public String getX() { 82 | return x; 83 | } 84 | } 85 | 86 | @Entity(name = "ChildZ") 87 | @Table(name="ChildZ") 88 | @Inheritance(strategy = InheritanceType.JOINED) 89 | @DiscriminatorValue("Z") 90 | public static class ChildZ extends Base { 91 | 92 | private String z; 93 | 94 | @Override 95 | @org.hibernate.annotations.Index(name = "xz") 96 | @Access(AccessType.PROPERTY) 97 | public String getX() { 98 | return x; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/mapping/ManyToManyWithElementCollectionTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.mapping; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.Date; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import javax.persistence.CascadeType; 10 | import javax.persistence.CollectionTable; 11 | import javax.persistence.Column; 12 | import javax.persistence.ElementCollection; 13 | import javax.persistence.Entity; 14 | import javax.persistence.GeneratedValue; 15 | import javax.persistence.Id; 16 | import javax.persistence.JoinColumn; 17 | import javax.persistence.ManyToMany; 18 | import javax.persistence.MapKeyJoinColumn; 19 | import javax.persistence.Temporal; 20 | import javax.persistence.TemporalType; 21 | 22 | import org.junit.Ignore; 23 | import org.junit.Test; 24 | 25 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 26 | 27 | import static org.junit.Assert.assertEquals; 28 | 29 | /** 30 | * ManyToManyWithElementCollectionTest - ManyToMany with ElementCollection Test 31 | * 32 | * @author Vlad Mihalcea 33 | */ 34 | public class ManyToManyWithElementCollectionTest extends AbstractTest { 35 | 36 | @Override 37 | protected Class[] entities() { 38 | return new Class[] { 39 | Clubber.class, 40 | Club.class 41 | }; 42 | } 43 | 44 | @Test @Ignore 45 | public void testAddingEmbeddable() { 46 | final Clubber clubberReference = doInTransaction(session -> { 47 | Clubber clubber = new Clubber(); 48 | Club club = new Club(); 49 | clubber.addClub(club); 50 | session.persist(club); 51 | session.flush(); 52 | return clubber; 53 | }); 54 | 55 | doInTransaction(session -> { 56 | Clubber clubber = (Clubber) session.get(Clubber.class, clubberReference.getId()); 57 | assertEquals(1, clubber.getClubs().size()); 58 | assertEquals(1, clubber.getJoinDate().size()); 59 | }); 60 | } 61 | 62 | @Entity(name = "Clubber") 63 | public static class Clubber{ 64 | 65 | @Id 66 | @GeneratedValue 67 | @Column(name = "Clubber_Id") 68 | private Integer id; 69 | 70 | @Temporal(TemporalType.TIMESTAMP) 71 | @ElementCollection 72 | @CollectionTable(name="CLUB_ASSIGNMENTS", joinColumns=@JoinColumn(name="Clubber_Id", referencedColumnName="Clubber_Id")) 73 | @Column(name="CLUB_DATE") 74 | @MapKeyJoinColumn(name = "Club_ID", referencedColumnName="Club_ID") 75 | private Map joinDate = new HashMap<>(); 76 | 77 | public Integer getId() { 78 | return id; 79 | } 80 | 81 | public Map getJoinDate() { 82 | return joinDate; 83 | } 84 | 85 | public Collection getClubs() { 86 | return joinDate.keySet(); 87 | } 88 | 89 | public void addClub(Club club) { 90 | joinDate.put(club, new Date()); 91 | //clubs.add(club); 92 | club.getClubbers().add(this); 93 | } 94 | } 95 | 96 | @Entity(name = "Club") 97 | public static class Club { 98 | 99 | @Id 100 | @GeneratedValue 101 | @Column(name = "Club_ID") 102 | private Integer id; 103 | 104 | @ManyToMany(mappedBy = "joinDate", cascade = {CascadeType.PERSIST, CascadeType.MERGE}) 105 | private List clubbers = new ArrayList<>(); 106 | 107 | public Integer getId() { 108 | return id; 109 | } 110 | 111 | public List getClubbers() { 112 | return clubbers; 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/mapping/OneTableMultipleEntitiesTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.mapping; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractTest; 4 | import org.hibernate.annotations.DynamicUpdate; 5 | import org.hibernate.annotations.Immutable; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | 9 | import javax.persistence.*; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | 14 | /** 15 | * OneTableMultipleEntitiesTest - Test to check the one table multiple entities 16 | * 17 | * @author Vlad Mihalcea 18 | */ 19 | public class OneTableMultipleEntitiesTest extends AbstractTest { 20 | 21 | @Override 22 | protected Class[] entities() { 23 | return new Class[]{ 24 | Post.class, 25 | PostSummary.class, 26 | UpdatablePostSummary.class 27 | }; 28 | } 29 | 30 | @Before 31 | public void init() { 32 | super.init(); 33 | doInTransaction(session -> { 34 | Post post = new Post(); 35 | post.setName("Hibernate Master Class"); 36 | post.setDescription("Hibernate Master Class Description"); 37 | session.persist(post); 38 | }); 39 | } 40 | 41 | @Test 42 | public void testOneTableMultipleEntities() { 43 | doInTransaction(session -> { 44 | Post post = (Post) session.get(Post.class, 1L); 45 | PostSummary postSummary = (PostSummary) session.get(PostSummary.class, 1L); 46 | UpdatablePostSummary updatablePostSummary = (UpdatablePostSummary) session.get(UpdatablePostSummary.class, 1L); 47 | assertEquals(post.getName(), postSummary.getName()); 48 | assertEquals(post.getName(), updatablePostSummary.getName()); 49 | updatablePostSummary.setName("Hibernate Master Class Tutorial."); 50 | }); 51 | } 52 | 53 | @Entity(name = "Post") 54 | public static class Post { 55 | 56 | @Id 57 | @GeneratedValue(strategy=GenerationType.AUTO) 58 | private Long id; 59 | 60 | private String name; 61 | 62 | private String description; 63 | 64 | public String getName() { 65 | return name; 66 | } 67 | 68 | public void setName(String name) { 69 | this.name = name; 70 | } 71 | 72 | public String getDescription() { 73 | return description; 74 | } 75 | 76 | public void setDescription(String description) { 77 | this.description = description; 78 | } 79 | } 80 | 81 | @Entity(name = "PostSummary") 82 | @Table(name = "Post") 83 | @Immutable 84 | public static class PostSummary { 85 | 86 | @Id 87 | @GeneratedValue(strategy = GenerationType.AUTO) 88 | private Long id; 89 | 90 | private String name; 91 | 92 | public String getName() { 93 | return name; 94 | } 95 | 96 | public void setName(String name) { 97 | this.name = name; 98 | } 99 | } 100 | 101 | @Entity(name = "UpdatablePostSummary") 102 | @Table(name = "Post") 103 | @DynamicUpdate 104 | public static class UpdatablePostSummary { 105 | 106 | @Id 107 | @GeneratedValue(strategy = GenerationType.AUTO) 108 | private Long id; 109 | 110 | private String name; 111 | 112 | public String getName() { 113 | return name; 114 | } 115 | 116 | public void setName(String name) { 117 | this.name = name; 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/AbstractConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.SessionFactory; 5 | import org.hibernate.Transaction; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | public abstract class AbstractConnectionProviderTest { 13 | 14 | protected final Logger LOGGER = LoggerFactory.getLogger(getClass()); 15 | 16 | private SessionFactory sf; 17 | 18 | @Before 19 | public void init() { 20 | sf = newSessionFactory(); 21 | } 22 | 23 | @After 24 | public void destroy() { 25 | sf.close(); 26 | } 27 | 28 | protected abstract SessionFactory newSessionFactory(); 29 | 30 | public SessionFactory getSessionFactory() { 31 | return sf; 32 | } 33 | 34 | @Test 35 | public void test() { 36 | Session session = null; 37 | Transaction txn = null; 38 | try { 39 | session = sf.openSession(); 40 | txn = session.beginTransaction(); 41 | 42 | SecurityId securityId = new SecurityId(); 43 | securityId.setRole("Role"); 44 | session.persist(securityId); 45 | 46 | txn.commit(); 47 | } catch (RuntimeException e) { 48 | if ( txn != null && txn.isActive() ) txn.rollback(); 49 | throw e; 50 | } finally { 51 | if (session != null) { 52 | session.close(); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/DriverConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import org.hibernate.SessionFactory; 4 | import org.hibernate.boot.registry.StandardServiceRegistryBuilder; 5 | import org.hibernate.cfg.Configuration; 6 | 7 | import java.util.Properties; 8 | 9 | public class DriverConnectionProviderTest extends AbstractConnectionProviderTest { 10 | 11 | protected Properties getProperties() { 12 | Properties properties = new Properties(); 13 | properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); 14 | //log settings 15 | properties.put("hibernate.hbm2ddl.auto", "update"); 16 | properties.put("hibernate.show_sql", "true"); 17 | //driver settings 18 | properties.put("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver"); 19 | properties.put("hibernate.connection.url", "jdbc:hsqldb:mem:test"); 20 | properties.put("hibernate.connection.username", "sa"); 21 | properties.put("hibernate.connection.password", ""); 22 | return properties; 23 | } 24 | 25 | @Override 26 | protected SessionFactory newSessionFactory() { 27 | Properties properties = getProperties(); 28 | 29 | return new Configuration() 30 | .addProperties(properties) 31 | .addAnnotatedClass(SecurityId.class) 32 | .buildSessionFactory( 33 | new StandardServiceRegistryBuilder() 34 | .applySettings(properties) 35 | .build() 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/ExternalDataSourceConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import net.ttddyy.dsproxy.listener.SLF4JQueryLoggingListener; 4 | import net.ttddyy.dsproxy.support.ProxyDataSource; 5 | import org.hibernate.SessionFactory; 6 | import org.hibernate.boot.registry.StandardServiceRegistryBuilder; 7 | import org.hibernate.cfg.Configuration; 8 | import org.hsqldb.jdbc.JDBCDataSource; 9 | 10 | import java.util.Properties; 11 | 12 | public class ExternalDataSourceConnectionProviderTest extends AbstractConnectionProviderTest { 13 | 14 | protected Properties getProperties() { 15 | Properties properties = new Properties(); 16 | properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); 17 | //log settings 18 | properties.put("hibernate.hbm2ddl.auto", "update"); 19 | //data source settings 20 | properties.put("hibernate.connection.datasource", newDataSource()); 21 | return properties; 22 | } 23 | 24 | @Override 25 | protected SessionFactory newSessionFactory() { 26 | Properties properties = getProperties(); 27 | 28 | return new Configuration() 29 | .addProperties(properties) 30 | .addAnnotatedClass(SecurityId.class) 31 | .buildSessionFactory( 32 | new StandardServiceRegistryBuilder() 33 | .applySettings(properties) 34 | .build() 35 | ); 36 | } 37 | 38 | protected ProxyDataSource newDataSource() { 39 | JDBCDataSource actualDataSource = new JDBCDataSource(); 40 | actualDataSource.setUrl("jdbc:hsqldb:mem:test"); 41 | actualDataSource.setUser("sa"); 42 | actualDataSource.setPassword(""); 43 | ProxyDataSource proxyDataSource = new ProxyDataSource(); 44 | proxyDataSource.setDataSource(actualDataSource); 45 | proxyDataSource.setListener(new SLF4JQueryLoggingListener()); 46 | return proxyDataSource; 47 | } 48 | 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/InternalDataSourceConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import org.hibernate.SessionFactory; 4 | import org.hibernate.boot.registry.StandardServiceRegistryBuilder; 5 | import org.hibernate.cfg.Configuration; 6 | 7 | import java.util.Properties; 8 | 9 | public class InternalDataSourceConnectionProviderTest extends AbstractConnectionProviderTest { 10 | 11 | protected Properties getProperties() { 12 | Properties properties = new Properties(); 13 | properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); 14 | //log settings 15 | properties.put("hibernate.hbm2ddl.auto", "update"); 16 | properties.put("hibernate.show_sql", "true"); 17 | //driver settings 18 | properties.put("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver"); 19 | properties.put("hibernate.connection.url", "jdbc:hsqldb:mem:test"); 20 | properties.put("hibernate.connection.username", "sa"); 21 | properties.put("hibernate.connection.password", ""); 22 | //c3p0 settings 23 | properties.put("hibernate.c3p0.min_size", 1); 24 | properties.put("hibernate.c3p0.max_size", 5); 25 | return properties; 26 | } 27 | 28 | protected SessionFactory newSessionFactory() { 29 | Properties properties = getProperties(); 30 | 31 | return new Configuration() 32 | .addProperties(properties) 33 | .addAnnotatedClass(SecurityId.class) 34 | .buildSessionFactory( 35 | new StandardServiceRegistryBuilder() 36 | .applySettings(properties) 37 | .build() 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/SecurityId.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.GeneratedValue; 5 | import javax.persistence.Id; 6 | 7 | /** 8 | * SecurityId - SecurityId 9 | * 10 | * @author Vlad Mihalcea 11 | */ 12 | @Entity 13 | class SecurityId { 14 | @Id 15 | @GeneratedValue 16 | private Long id; 17 | 18 | private String role; 19 | 20 | public Long getId() { 21 | return id; 22 | } 23 | 24 | public String getRole() { 25 | return role; 26 | } 27 | 28 | public void setRole(String role) { 29 | this.role = role; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/TransactionIsolationDriverConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.Transaction; 5 | import org.hibernate.cfg.Environment; 6 | import org.hibernate.jdbc.Work; 7 | import org.junit.Test; 8 | 9 | import java.sql.Connection; 10 | import java.sql.SQLException; 11 | import java.util.Properties; 12 | 13 | /** 14 | * TransactionIsolationDriverConnectionProviderTest - TransactionIsolation DriverConnectionProviderTest 15 | * 16 | * @author Vlad Mihalcea 17 | */ 18 | public class TransactionIsolationDriverConnectionProviderTest extends DriverConnectionProviderTest { 19 | 20 | @Override 21 | protected Properties getProperties() { 22 | Properties properties = super.getProperties(); 23 | properties.setProperty("hibernate.connection.isolation", String.valueOf(Connection.TRANSACTION_SERIALIZABLE)); 24 | return properties; 25 | } 26 | 27 | @Test 28 | public void test() { 29 | Session session = null; 30 | Transaction txn = null; 31 | try { 32 | session = getSessionFactory().openSession(); 33 | txn = session.beginTransaction(); 34 | session.doWork(new Work() { 35 | @Override 36 | public void execute(Connection connection) throws SQLException { 37 | LOGGER.debug("Transaction isolation level is {}", Environment.isolationLevelToString(connection.getTransactionIsolation())); 38 | } 39 | }); 40 | txn.commit(); 41 | } catch (RuntimeException e) { 42 | if ( txn != null && txn.isActive() ) txn.rollback(); 43 | throw e; 44 | } finally { 45 | if (session != null) { 46 | session.close(); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/TransactionIsolationExternalDataSourceConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.Transaction; 5 | import org.hibernate.cfg.Environment; 6 | import org.hibernate.jdbc.Work; 7 | import org.junit.Test; 8 | 9 | import java.sql.Connection; 10 | import java.sql.SQLException; 11 | import java.util.Properties; 12 | 13 | public class TransactionIsolationExternalDataSourceConnectionProviderTest extends ExternalDataSourceConnectionProviderTest { 14 | 15 | @Override 16 | protected Properties getProperties() { 17 | Properties properties = super.getProperties(); 18 | properties.setProperty("hibernate.connection.isolation", String.valueOf(Connection.TRANSACTION_SERIALIZABLE)); 19 | return properties; 20 | } 21 | 22 | @Test 23 | public void test() { 24 | Session session = null; 25 | Transaction txn = null; 26 | try { 27 | session = getSessionFactory().openSession(); 28 | txn = session.beginTransaction(); 29 | session.doWork(new Work() { 30 | @Override 31 | public void execute(Connection connection) throws SQLException { 32 | LOGGER.debug("Transaction isolation level is {}", Environment.isolationLevelToString(connection.getTransactionIsolation())); 33 | } 34 | }); 35 | txn.commit(); 36 | } catch (RuntimeException e) { 37 | if ( txn != null && txn.isActive() ) txn.rollback(); 38 | throw e; 39 | } finally { 40 | if (session != null) { 41 | session.close(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/TransactionIsolationExternalDataSourceExternalconfgiurationConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import net.ttddyy.dsproxy.listener.SLF4JQueryLoggingListener; 4 | import net.ttddyy.dsproxy.support.ProxyDataSource; 5 | import org.hibernate.Session; 6 | import org.hibernate.Transaction; 7 | import org.hibernate.cfg.Environment; 8 | import org.hibernate.jdbc.Work; 9 | import org.hsqldb.jdbc.JDBCDataSource; 10 | import org.junit.Test; 11 | 12 | import java.sql.Connection; 13 | import java.sql.SQLException; 14 | import java.util.Properties; 15 | 16 | public class TransactionIsolationExternalDataSourceExternalconfgiurationConnectionProviderTest extends ExternalDataSourceConnectionProviderTest { 17 | 18 | @Test 19 | public void test() { 20 | Session session = null; 21 | Transaction txn = null; 22 | try { 23 | session = getSessionFactory().openSession(); 24 | txn = session.beginTransaction(); 25 | session.doWork(new Work() { 26 | @Override 27 | public void execute(Connection connection) throws SQLException { 28 | LOGGER.debug("Transaction isolation level is {}", Environment.isolationLevelToString(connection.getTransactionIsolation())); 29 | } 30 | }); 31 | txn.commit(); 32 | } catch (RuntimeException e) { 33 | if ( txn != null && txn.isActive() ) txn.rollback(); 34 | throw e; 35 | } finally { 36 | if (session != null) { 37 | session.close(); 38 | } 39 | } 40 | } 41 | 42 | protected ProxyDataSource newDataSource() { 43 | JDBCDataSource actualDataSource = new JDBCDataSource(); 44 | actualDataSource.setUrl("jdbc:hsqldb:mem:test"); 45 | actualDataSource.setUser("sa"); 46 | actualDataSource.setPassword(""); 47 | Properties properties = new Properties(); 48 | properties.setProperty("hsqldb.tx_level", "SERIALIZABLE"); 49 | actualDataSource.setProperties(properties); 50 | ProxyDataSource proxyDataSource = new ProxyDataSource(); 51 | proxyDataSource.setDataSource(actualDataSource); 52 | proxyDataSource.setListener(new SLF4JQueryLoggingListener()); 53 | return proxyDataSource; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/testenv/TransactionIsolationInternalC3P0ConnectionProviderTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.testenv; 2 | 3 | import org.hibernate.Session; 4 | import org.hibernate.Transaction; 5 | import org.hibernate.cfg.Environment; 6 | import org.hibernate.jdbc.Work; 7 | import org.junit.Test; 8 | 9 | import java.sql.Connection; 10 | import java.sql.SQLException; 11 | import java.util.Properties; 12 | 13 | public class TransactionIsolationInternalC3P0ConnectionProviderTest extends InternalDataSourceConnectionProviderTest { 14 | 15 | @Override 16 | protected Properties getProperties() { 17 | Properties properties = super.getProperties(); 18 | properties.setProperty("hibernate.connection.isolation", String.valueOf(Connection.TRANSACTION_SERIALIZABLE)); 19 | return properties; 20 | } 21 | 22 | @Test 23 | public void test() { 24 | Session session = null; 25 | Transaction txn = null; 26 | try { 27 | session = getSessionFactory().openSession(); 28 | txn = session.beginTransaction(); 29 | session.doWork(new Work() { 30 | @Override 31 | public void execute(Connection connection) throws SQLException { 32 | LOGGER.debug("Transaction isolation level is {}", Environment.isolationLevelToString(connection.getTransactionIsolation())); 33 | } 34 | }); 35 | txn.commit(); 36 | } catch (RuntimeException e) { 37 | if ( txn != null && txn.isActive() ) txn.rollback(); 38 | throw e; 39 | } finally { 40 | if (session != null) { 41 | session.close(); 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/type/PostgreQuoteStringTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.type; 2 | 3 | import com.vladmihalcea.hibernate.masterclass.laboratory.util.AbstractPostgreSQLIntegrationTest; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | 7 | import javax.persistence.Entity; 8 | import javax.persistence.Id; 9 | import java.util.List; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | /** 14 | * PostgreQuoteStringTest - PostgreQuoteStringTest 15 | * 16 | * @author Vlad Mihalcea 17 | */ 18 | public class PostgreQuoteStringTest extends AbstractPostgreSQLIntegrationTest { 19 | @Override 20 | protected Class[] entities() { 21 | return new Class[] { 22 | WidgetContentTo.class 23 | }; 24 | } 25 | 26 | @Before 27 | public void init() { 28 | super.init(); 29 | doInTransaction(session -> { 30 | WidgetContentTo widgetContentTo = new WidgetContentTo(); 31 | widgetContentTo.setWidgetContentId(1); 32 | widgetContentTo.setSiteId(1); 33 | widgetContentTo.setWidgetContentName("aaa`bbb"); 34 | session.persist(widgetContentTo); 35 | }); 36 | } 37 | 38 | @Test 39 | public void test() { 40 | doInTransaction(session -> { 41 | List widgetContentTos = session.createQuery("from WidgetContentTo").list(); 42 | assertEquals(1, widgetContentTos.size()); 43 | }); 44 | } 45 | 46 | @Entity(name = "WidgetContentTo") 47 | public static class WidgetContentTo 48 | { 49 | @Id 50 | private int widgetContentId; 51 | private int siteId; 52 | private String widgetContentName; 53 | 54 | public int getWidgetContentId() { 55 | return widgetContentId; 56 | } 57 | 58 | public void setWidgetContentId(int widgetContentId) { 59 | this.widgetContentId = widgetContentId; 60 | } 61 | 62 | public int getSiteId() { 63 | return siteId; 64 | } 65 | 66 | public void setSiteId(int siteId) { 67 | this.siteId = siteId; 68 | } 69 | 70 | public String getWidgetContentName() { 71 | return widgetContentName; 72 | } 73 | 74 | public void setWidgetContentName(String widgetContentName) { 75 | this.widgetContentName = widgetContentName; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/util/AbstractJPATest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.util; 2 | 3 | import net.ttddyy.dsproxy.listener.SLF4JQueryLoggingListener; 4 | import net.ttddyy.dsproxy.support.ProxyDataSource; 5 | import org.hsqldb.jdbc.JDBCDataSource; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | import javax.persistence.EntityManager; 12 | import javax.persistence.EntityManagerFactory; 13 | import javax.persistence.EntityTransaction; 14 | import javax.persistence.Persistence; 15 | import java.util.Arrays; 16 | import java.util.Properties; 17 | 18 | public abstract class AbstractJPATest { 19 | 20 | protected final Logger LOGGER = LoggerFactory.getLogger(getClass()); 21 | 22 | protected static abstract class TransactionCallable { 23 | public abstract T execute(EntityManager entityManager); 24 | } 25 | 26 | private EntityManagerFactory entityManagerFactory; 27 | 28 | @Before 29 | public void init() { 30 | entityManagerFactory = newEntityManagerFactory(); 31 | } 32 | 33 | @After 34 | public void destroy() { 35 | entityManagerFactory.close(); 36 | } 37 | 38 | protected abstract Class[] entities(); 39 | 40 | private EntityManagerFactory newEntityManagerFactory() { 41 | Properties properties = getProperties(); 42 | properties.put(org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, Arrays.asList(entities())); 43 | return Persistence.createEntityManagerFactory("testPersistenceUnit", properties); 44 | 45 | } 46 | 47 | protected Properties getProperties() { 48 | Properties properties = new Properties(); 49 | properties.setProperty("hibernate.ejb.use_class_enhancer", Boolean.TRUE.toString()); 50 | properties.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); 51 | //log settings 52 | properties.put("hibernate.hbm2ddl.auto", "create-drop"); 53 | //data source settings 54 | properties.put("hibernate.connection.datasource", newDataSource()); 55 | return properties; 56 | } 57 | 58 | private ProxyDataSource newDataSource() { 59 | JDBCDataSource actualDataSource = new JDBCDataSource(); 60 | actualDataSource.setUrl("jdbc:hsqldb:mem:test"); 61 | actualDataSource.setUser("sa"); 62 | actualDataSource.setPassword(""); 63 | ProxyDataSource proxyDataSource = new ProxyDataSource(); 64 | proxyDataSource.setDataSource(actualDataSource); 65 | proxyDataSource.setListener(new SLF4JQueryLoggingListener()); 66 | return proxyDataSource; 67 | } 68 | 69 | protected T doInTransaction(TransactionCallable callable) { 70 | T result = null; 71 | EntityManager entityManager = null; 72 | EntityTransaction txn = null; 73 | try { 74 | entityManager = entityManagerFactory.createEntityManager(); 75 | txn = entityManager.getTransaction(); 76 | txn.begin(); 77 | result = callable.execute(entityManager); 78 | txn.commit(); 79 | } catch (RuntimeException e) { 80 | if ( txn != null && txn.isActive() ) txn.rollback(); 81 | throw e; 82 | } finally { 83 | if (entityManager != null) { 84 | entityManager.close(); 85 | } 86 | } 87 | return result; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/util/AbstractMySQLIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.util; 2 | 3 | /** 4 | * AbstractMySQLIntegrationTest - Abstract MySQL IntegrationTest 5 | * 6 | * @author Vlad Mihalcea 7 | */ 8 | public abstract class AbstractMySQLIntegrationTest extends AbstractTest { 9 | 10 | @Override 11 | protected DataSourceProvider getDataSourceProvider() { 12 | return new MySQLDataSourceProvider(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/util/AbstractOracleXEIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.util; 2 | 3 | /** 4 | * AbstractOracleXEIntegrationTest - Abstract Orcale XE IntegrationTest 5 | * 6 | * @author Vlad Mihalcea 7 | */ 8 | public abstract class AbstractOracleXEIntegrationTest extends AbstractTest { 9 | 10 | @Override 11 | protected DataSourceProvider getDataSourceProvider() { 12 | return new OracleDataSourceProvider(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/util/AbstractPostgreSQLIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.util; 2 | 3 | /** 4 | * AbstractPostgreSQLIntegrationTest - Abstract PostgreSQL IntegrationTest 5 | * 6 | * @author Vlad Mihalcea 7 | */ 8 | public abstract class AbstractPostgreSQLIntegrationTest extends AbstractTest { 9 | 10 | @Override 11 | protected DataSourceProvider getDataSourceProvider() { 12 | return new PostgreSQLDataSourceProvider(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/util/AbstractSQLServerIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.util; 2 | 3 | /** 4 | * AbstractSQLServerIntegrationTest - Abstract SQL Server IntegrationTest 5 | * 6 | * @author Vlad Mihalcea 7 | */ 8 | public abstract class AbstractSQLServerIntegrationTest extends AbstractTest { 9 | 10 | @Override 11 | protected DataSourceProvider getDataSourceProvider() { 12 | return new SQLServerDataSourceProvider(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/util/DataSourceProviderIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.util; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.junit.runners.Parameterized; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.List; 9 | 10 | /** 11 | * DataSourceProviderIntegrationTest - Test against some common RDBMS providers 12 | * 13 | * @author Vlad Mihalcea 14 | */ 15 | @RunWith(Parameterized.class) 16 | public abstract class DataSourceProviderIntegrationTest extends AbstractTest { 17 | 18 | private final DataSourceProvider dataSourceProvider; 19 | 20 | public DataSourceProviderIntegrationTest(DataSourceProvider dataSourceProvider) { 21 | this.dataSourceProvider = dataSourceProvider; 22 | } 23 | 24 | @Parameterized.Parameters 25 | public static Collection rdbmsDataSourceProvider() { 26 | List providers = new ArrayList<>(); 27 | providers.add(new DataSourceProvider[]{new OracleDataSourceProvider()}); 28 | providers.add(new DataSourceProvider[]{new SQLServerDataSourceProvider()}); 29 | providers.add(new DataSourceProvider[]{new PostgreSQLDataSourceProvider()}); 30 | providers.add(new DataSourceProvider[]{new MySQLDataSourceProvider()}); 31 | return providers; 32 | } 33 | 34 | @Override 35 | protected DataSourceProvider getDataSourceProvider() { 36 | return dataSourceProvider; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/util/EntityProvider.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.util; 2 | 3 | /** 4 | * EntityProvider - Entity Provider 5 | * 6 | * @author Vlad Mihalcea 7 | */ 8 | public interface EntityProvider { 9 | 10 | /** 11 | * Entity types shared among multiple test configurations 12 | * 13 | * @return entity types 14 | */ 15 | Class[] entities(); 16 | } 17 | -------------------------------------------------------------------------------- /core/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/util/PersistenceUnitInfoImpl.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.util; 2 | 3 | import org.hibernate.jpa.HibernatePersistenceProvider; 4 | 5 | import javax.persistence.SharedCacheMode; 6 | import javax.persistence.ValidationMode; 7 | import javax.persistence.spi.ClassTransformer; 8 | import javax.persistence.spi.PersistenceUnitInfo; 9 | import javax.persistence.spi.PersistenceUnitTransactionType; 10 | import javax.sql.DataSource; 11 | import java.net.URL; 12 | import java.util.Collections; 13 | import java.util.List; 14 | import java.util.Properties; 15 | 16 | /** 17 | * AbstractPersistenceUnitInfo - Base PersistenceUnitInfo 18 | * 19 | * @author Vlad Mihalcea 20 | */ 21 | public class PersistenceUnitInfoImpl implements PersistenceUnitInfo { 22 | 23 | public static PersistenceUnitInfoImpl newJTAPersistenceUnitInfo( 24 | String persistenceUnitName, List mappingFileNames, Properties properties, DataSource jtaDataSource) { 25 | PersistenceUnitInfoImpl persistenceUnitInfo = new PersistenceUnitInfoImpl( 26 | persistenceUnitName, mappingFileNames, properties 27 | ); 28 | persistenceUnitInfo.jtaDataSource = jtaDataSource; 29 | persistenceUnitInfo.nonJtaDataSource = null; 30 | persistenceUnitInfo.transactionType = PersistenceUnitTransactionType.JTA; 31 | return persistenceUnitInfo; 32 | } 33 | 34 | private final String persistenceUnitName; 35 | 36 | private PersistenceUnitTransactionType transactionType = PersistenceUnitTransactionType.RESOURCE_LOCAL; 37 | 38 | private final List managedClassNames; 39 | 40 | private final Properties properties; 41 | 42 | private DataSource jtaDataSource; 43 | 44 | private DataSource nonJtaDataSource; 45 | 46 | public PersistenceUnitInfoImpl(String persistenceUnitName, List managedClassNames, Properties properties) { 47 | this.persistenceUnitName = persistenceUnitName; 48 | this.managedClassNames = managedClassNames; 49 | this.properties = properties; 50 | } 51 | 52 | @Override 53 | public String getPersistenceUnitName() { 54 | return persistenceUnitName; 55 | } 56 | 57 | @Override 58 | public String getPersistenceProviderClassName() { 59 | return HibernatePersistenceProvider.class.getName(); 60 | } 61 | 62 | @Override 63 | public PersistenceUnitTransactionType getTransactionType() { 64 | return transactionType; 65 | } 66 | 67 | @Override 68 | public DataSource getJtaDataSource() { 69 | return jtaDataSource; 70 | } 71 | 72 | @Override 73 | public DataSource getNonJtaDataSource() { 74 | return nonJtaDataSource; 75 | } 76 | 77 | @Override 78 | public List getMappingFileNames() { 79 | return null; 80 | } 81 | 82 | @Override 83 | public List getJarFileUrls() { 84 | return Collections.emptyList(); 85 | } 86 | 87 | @Override 88 | public URL getPersistenceUnitRootUrl() { 89 | return null; 90 | } 91 | 92 | @Override 93 | public List getManagedClassNames() { 94 | return managedClassNames; 95 | } 96 | 97 | @Override 98 | public boolean excludeUnlistedClasses() { 99 | return false; 100 | } 101 | 102 | @Override 103 | public SharedCacheMode getSharedCacheMode() { 104 | return SharedCacheMode.UNSPECIFIED; 105 | } 106 | 107 | @Override 108 | public ValidationMode getValidationMode() { 109 | return ValidationMode.AUTO; 110 | } 111 | 112 | public Properties getProperties() { 113 | return properties; 114 | } 115 | 116 | @Override 117 | public String getPersistenceXMLSchemaVersion() { 118 | return "2.1"; 119 | } 120 | 121 | @Override 122 | public ClassLoader getClassLoader() { 123 | return Thread.currentThread().getContextClassLoader(); 124 | } 125 | 126 | @Override 127 | public void addTransformer(ClassTransformer transformer) { 128 | 129 | } 130 | 131 | @Override 132 | public ClassLoader getNewTempClassLoader() { 133 | return null; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /core/src/test/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | TEST Persistence Unit 7 | org.hibernate.jpa.HibernatePersistenceProvider 8 | 9 | com.vladmihalcea.hibernate.masterclass.laboratory.flushing.OrderLine 10 | true 11 | 12 | 13 | -------------------------------------------------------------------------------- /core/src/test/resources/OracleLog.properties: -------------------------------------------------------------------------------- 1 | # OracleLog.properties Copyright Oracle 2007 2 | 3 | # Controls output of java.util.logging output for Oracle JDBC drivers 4 | 5 | # See the Javadoc for OracleLog for more information. 6 | 7 | # The OracleLog system uses the services of 8 | # java.util.logging.* This file is a starting 9 | # point for controlling that output via a properties 10 | # file. Note that there is also a programatic interface 11 | # for java.util.logging which may be used as well. That 12 | # would allow finer grained control and the ability to 13 | # change the logging as the program runs. 14 | 15 | # Copy this file to your runtime directory to use as a 16 | # starting point. You should expect to change it to 17 | # suit your needs. 18 | 19 | # To enable logging controlled by this file start your 20 | # main java class with the swtiches 21 | 22 | # -Doracle.jdbc.Trace=true 23 | # -Djava.util.logging.config.file=OracleLog.properties 24 | 25 | # See also the file logging.properties in the jre/lib directory 26 | # in your JDK installation and the JDK documentation. 27 | 28 | # default file output is in user's home directory. 29 | java.util.logging.FileHandler.pattern = jdbc.log 30 | java.util.logging.FileHandler.limit = 50000 31 | java.util.logging.FileHandler.count = 1 32 | java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter 33 | 34 | # log to the console by default 35 | handlers = java.util.logging.ConsoleHandler 36 | 37 | # for sqlnet tracing uncomment the lines below 38 | # oracle.jdbc.diagnostics.DemultiplexingLogHandler.pattern= jdbc_%s.trc 39 | # oracle.jdbc.diagnostics.DemultiplexingLogHandler.formatter = java.util.logging.SimpleFormatter 40 | # handlers = oracle.jdbc.diagnostics.DemultiplexingLogHandler 41 | 42 | # default is to log everything generated. control what is generated below 43 | java.util.logging.ConsoleHandler.level = ALL 44 | java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter 45 | 46 | # JDBC uses the following Levels. Levels lower than FINE produce output that 47 | # may not be meaningful to users. Levels lower than FINER will produce very 48 | # large volumes of output. 49 | # 50 | # INTERNAL_ERROR Internal Errors 51 | # SEVERE SQLExceptions 52 | # WARNING SQLWarnings and other invisible problems 53 | # INFO Public events such as connection attempts or RAC events 54 | # CONFIG SQL statements 55 | # FINE Public APIs 56 | # TRACE_10 Internal events 57 | # FINER Internal APIs 58 | # TRACE_20 Internal debug, sqlnet tracing (oracle.net.ns.level) 59 | # TRACE_30 High volume internal APIs 60 | # FINEST High volume internal debug 61 | 62 | # Uncomment and/or change the levels for more detail 63 | oracle.jdbc.level = FINEST 64 | #oracle.jdbc.connector.level = FINE 65 | oracle.jdbc.driver.level = FINEST 66 | #oracle.jdbc.internal.level = FINE 67 | #oracle.jdbc.oci.level = FINE 68 | #oracle.jdbc.oracore.level = FINE 69 | #oracle.jdbc.pool.level = FINE 70 | #oracle.jdbc.rowset.level = FINE 71 | #oracle.jdbc.util.level = FINE 72 | #oracle.jdbc.xa.level = FINE 73 | #oracle.jdbc.xa.client.level = FINE 74 | #oracle.jpub.level = FINE 75 | #oracle.net.ns.level = TRACE_20 76 | #oracle.sql.level = FINE 77 | -------------------------------------------------------------------------------- /core/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DEBUG 5 | 6 | target/test.log 7 | false 8 | 9 | %-5p [%t]: %c{1} - %m%n 10 | UTF-8 11 | 12 | 13 | 14 | 15 | DEBUG 16 | 17 | 18 | %-5p [%t]: %c{1} - %m%n 19 | UTF-8 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /docs/draw/CacheAside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/CacheAside.png -------------------------------------------------------------------------------- /docs/draw/CacheReadThrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/CacheReadThrough.png -------------------------------------------------------------------------------- /docs/draw/CacheWriteBehind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/CacheWriteBehind.png -------------------------------------------------------------------------------- /docs/draw/CacheWriteThrough.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/CacheWriteThrough.png -------------------------------------------------------------------------------- /docs/draw/CollectionCacheRepositoryCommitChange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/CollectionCacheRepositoryCommitChange.png -------------------------------------------------------------------------------- /docs/draw/DefaultFlushEventFlow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/DefaultFlushEventFlow.png -------------------------------------------------------------------------------- /docs/draw/DistributedCacheNodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/DistributedCacheNodes.png -------------------------------------------------------------------------------- /docs/draw/EllementCollectionPatchChange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/EllementCollectionPatchChange.png -------------------------------------------------------------------------------- /docs/draw/FlexyPoolConnectionProxyDecorator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/FlexyPoolConnectionProxyDecorator.png -------------------------------------------------------------------------------- /docs/draw/FlushAUTOEntities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/FlushAUTOEntities.png -------------------------------------------------------------------------------- /docs/draw/HibernateEntityStates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/HibernateEntityStates.png -------------------------------------------------------------------------------- /docs/draw/HibernateJDBCBatchBenchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/HibernateJDBCBatchBenchmark.png -------------------------------------------------------------------------------- /docs/draw/MultipleCacheNodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/MultipleCacheNodes.png -------------------------------------------------------------------------------- /docs/draw/NonStrictReadWriteCacheConcurrencyStrategy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/NonStrictReadWriteCacheConcurrencyStrategy.png -------------------------------------------------------------------------------- /docs/draw/PooledLoOptimizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/PooledLoOptimizer.png -------------------------------------------------------------------------------- /docs/draw/PooledOptimizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/PooledOptimizer.png -------------------------------------------------------------------------------- /docs/draw/PostAuthorQueryCache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/PostAuthorQueryCache.png -------------------------------------------------------------------------------- /docs/draw/PostCommentDetailsBatchDelete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/PostCommentDetailsBatchDelete.png -------------------------------------------------------------------------------- /docs/draw/PostCommentDetailsLockCascade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/PostCommentDetailsLockCascade.png -------------------------------------------------------------------------------- /docs/draw/PostCommentDetailsSecondLevelCache.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/PostCommentDetailsSecondLevelCache.png -------------------------------------------------------------------------------- /docs/draw/PostCommentFetchSize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/PostCommentFetchSize.png -------------------------------------------------------------------------------- /docs/draw/PostCommentJdbcBatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/PostCommentJdbcBatch.png -------------------------------------------------------------------------------- /docs/draw/ProductOrderLineOptimisticLockMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/ProductOrderLineOptimisticLockMode.png -------------------------------------------------------------------------------- /docs/draw/ReadWriteCacheConcurrencyStrategy_Delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/ReadWriteCacheConcurrencyStrategy_Delete.png -------------------------------------------------------------------------------- /docs/draw/ReadWriteCacheConcurrencyStrategy_Update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/ReadWriteCacheConcurrencyStrategy_Update.png -------------------------------------------------------------------------------- /docs/draw/RepositoryCommitChangeOptimisticForceIncrement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/RepositoryCommitChangeOptimisticForceIncrement.png -------------------------------------------------------------------------------- /docs/draw/RepositoryCommitChangeReadOnlyCacheConcurrencyStrategy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/RepositoryCommitChangeReadOnlyCacheConcurrencyStrategy.png -------------------------------------------------------------------------------- /docs/draw/SingleCacheNode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/SingleCacheNode.png -------------------------------------------------------------------------------- /docs/draw/TransactionalXACacheConcurrencyStrategy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/TransactionalXACacheConcurrencyStrategy.png -------------------------------------------------------------------------------- /docs/draw/TransactionalXAStrictCacheConcurrencyStrategy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/TransactionalXAStrictCacheConcurrencyStrategy.png -------------------------------------------------------------------------------- /docs/draw/entityStates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/entityStates.png -------------------------------------------------------------------------------- /docs/draw/hi_lo_algorithm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/hi_lo_algorithm.png -------------------------------------------------------------------------------- /docs/draw/hibernate-entity-states.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/hibernate-entity-states.png -------------------------------------------------------------------------------- /docs/draw/jpa-entity-states.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/jpa-entity-states.jpg -------------------------------------------------------------------------------- /docs/draw/jpa-entity-states.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladmihalcea/hibernate-master-class/11d1cc18ba8afc1374b971d9fa52b4365856ba45/docs/draw/jpa-entity-states.png -------------------------------------------------------------------------------- /maven-bytecode-enhance/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | com.vladmihalcea 8 | hibernate-master-class-parent 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 4.0.0 13 | 14 | hibernate-master-class-maven-bytecode-enhance 15 | 16 | 17 | 18 | 19 | org.hibernate.javax.persistence 20 | hibernate-jpa-2.1-api 21 | 1.0.0.Final 22 | 23 | 24 | 25 | com.vladmihalcea 26 | hibernate-master-class-core 27 | 1.0-SNAPSHOT 28 | 29 | 30 | 31 | 32 | com.vladmihalcea 33 | hibernate-master-class-core 34 | 1.0-SNAPSHOT 35 | test-jar 36 | test 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | org.hibernate.orm.tooling 45 | hibernate-enhance-maven-plugin 46 | ${hibernate.version} 47 | 48 | 49 | 50 | true 51 | true 52 | true 53 | true 54 | 55 | 56 | enhance 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /maven-bytecode-enhance/src/main/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/EnhancedOrderLine.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import javax.persistence.*; 4 | import java.util.Date; 5 | 6 | /** 7 | * Order - Order 8 | * 9 | * @author Vlad Mihalcea 10 | */ 11 | @Entity 12 | public class EnhancedOrderLine { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.AUTO) 16 | private Long id; 17 | 18 | private Long number; 19 | 20 | private String orderedBy; 21 | 22 | private Date orderedOn; 23 | 24 | public Long getId() { 25 | return id; 26 | } 27 | 28 | public Long getNumber() { 29 | return number; 30 | } 31 | 32 | public void setNumber(Long number) { 33 | this.number = number; 34 | } 35 | 36 | public String getOrderedBy() { 37 | return orderedBy; 38 | } 39 | 40 | public void setOrderedBy(String orderedBy) { 41 | this.orderedBy = orderedBy; 42 | } 43 | 44 | public Date getOrderedOn() { 45 | return orderedOn; 46 | } 47 | 48 | public void setOrderedOn(Date orderedOn) { 49 | this.orderedOn = orderedOn; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /maven-bytecode-enhance/src/test/java/com/vladmihalcea/hibernate/masterclass/laboratory/flushing/BytecodeEnhancedTest.java: -------------------------------------------------------------------------------- 1 | package com.vladmihalcea.hibernate.masterclass.laboratory.flushing; 2 | 3 | import org.hibernate.Session; 4 | import org.junit.Test; 5 | 6 | import java.util.Date; 7 | 8 | /** 9 | * BytecodeEnhancedTest - Test to check auto dirty checking capabilities 10 | * 11 | * @author Vlad Mihalcea 12 | */ 13 | public class BytecodeEnhancedTest extends AutoDirtyCheckingTest { 14 | 15 | @Override 16 | protected Class[] entities() { 17 | return new Class[] { 18 | EnhancedOrderLine.class 19 | }; 20 | } 21 | 22 | @Test 23 | public void testDirtyChecking() { 24 | doInTransaction(session -> { 25 | EnhancedOrderLine orderLine = new EnhancedOrderLine(); 26 | orderLine.setNumber(987L); 27 | orderLine.setOrderedBy("System"); 28 | orderLine.setOrderedOn(new Date()); 29 | session.persist(orderLine); 30 | session.flush(); 31 | orderLine.setNumber(123L); 32 | orderLine.setOrderedBy("Vlad"); 33 | orderLine.setOrderedOn(new Date()); 34 | session.flush(); 35 | orderLine.setOrderedBy("Alex"); 36 | return null; 37 | 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /maven-bytecode-enhance/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DEBUG 5 | 6 | target/test.log 7 | false 8 | 9 | %-5p [%t]: %c{1} - %m%n 10 | UTF-8 11 | 12 | 13 | 14 | 15 | DEBUG 16 | 17 | 18 | %-5p [%t]: %c{1} - %m%n 19 | UTF-8 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | --------------------------------------------------------------------------------