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