diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Address.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Address.java
new file mode 100644
index 0000000000..b20de6a471
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Address.java
@@ -0,0 +1,37 @@
+package com.baeldung.jpa.uniqueconstraints;
+
+import java.io.Serializable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table
+public class Address implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String streetAddress;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getStreetAddress() {
+ return streetAddress;
+ }
+
+ public void setStreetAddress(String streetAddress) {
+ this.streetAddress = streetAddress;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Person.java b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Person.java
new file mode 100644
index 0000000000..c5df90df73
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/main/java/com/baeldung/jpa/uniqueconstraints/Person.java
@@ -0,0 +1,116 @@
+package com.baeldung.jpa.uniqueconstraints;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+@Entity
+@Table(uniqueConstraints = { @UniqueConstraint(name = "UniqueNumberAndStatus", columnNames = { "personNumber", "isActive" }),
+ @UniqueConstraint(name = "UniqueSecurityAndDepartment", columnNames = { "securityNumber", "departmentCode" }),
+ @UniqueConstraint(name = "UniqueNumberAndAddress", columnNames = { "personNumber", "address" }) })
+public class Person implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue
+ private Long id;
+
+ private String name;
+
+ private String password;
+
+ @Column(unique = true)
+ private String email;
+
+ @Column(unique = true)
+ private Long personNumber;
+
+ private Boolean isActive;
+
+ private String securityNumber;
+
+ private String departmentCode;
+
+ @Column(unique = true)
+ @JoinColumn(name = "addressId", referencedColumnName = "id")
+ private Address address;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public Long getPersonNumber() {
+ return personNumber;
+ }
+
+ public void setPersonNumber(Long personNumber) {
+ this.personNumber = personNumber;
+ }
+
+ public Boolean getIsActive() {
+ return isActive;
+ }
+
+ public void setIsActive(Boolean isActive) {
+ this.isActive = isActive;
+ }
+
+ public String getScode() {
+ return securityNumber;
+ }
+
+ public void setScode(String scode) {
+ this.securityNumber = scode;
+ }
+
+ public String getDcode() {
+ return departmentCode;
+ }
+
+ public void setDcode(String dcode) {
+ this.departmentCode = dcode;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
index 666fc1500a..1166aaca71 100644
--- a/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
+++ b/persistence-modules/java-jpa-3/src/main/resources/META-INF/persistence.xml
@@ -113,6 +113,22 @@
+
+ org.hibernate.jpa.HibernatePersistenceProvider
+ com.baeldung.jpa.uniqueconstraints.Person
+ com.baeldung.jpa.uniqueconstraints.Address
+ true
+
+
+
+
+
+
+
+
+
+
+
org.hibernate.jpa.HibernatePersistenceProvider
com.baeldung.jpa.returnmultipleentities.Channel
diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueColumnIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueColumnIntegrationTest.java
new file mode 100644
index 0000000000..ca776ba00b
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueColumnIntegrationTest.java
@@ -0,0 +1,119 @@
+package com.baeldung.jpa.uniqueconstraints;
+
+import java.util.Optional;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.hibernate.exception.ConstraintViolationException;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class UniqueColumnIntegrationTest {
+
+ private static EntityManagerFactory factory;
+ private static EntityManager entityManager;
+
+ @BeforeAll
+ public static void setup() {
+ factory = Persistence.createEntityManagerFactory("jpa-unique-constraints");
+ entityManager = factory.createEntityManager();
+ }
+
+ @Test
+ public void whenPersistPersonWithSameNumber_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setPersonNumber(2000L);
+ person1.setEmail("john.beth@gmail.com");
+
+ Person person2 = new Person();
+ person2.setPersonNumber(2000L);
+ person2.setEmail("anthony.green@gmail.com");
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+
+ @Test
+ public void whenPersistPersonWithSameEmail_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setPersonNumber(4000L);
+ person1.setEmail("timm.beth@gmail.com");
+
+ Person person2 = new Person();
+ person2.setPersonNumber(3000L);
+ person2.setEmail("timm.beth@gmail.com");
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+
+ @Test
+ public void whenPersistPersonWithSameAddress_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setPersonNumber(5000L);
+ person1.setEmail("chris.beck@gmail.com");
+
+ Address address1 = new Address();
+ address1.setStreetAddress("20 Street");
+ person1.setAddress(address1);
+
+ Person person2 = new Person();
+ person2.setPersonNumber(6000L);
+ person2.setEmail("mark.jonson@gmail.com");
+ person2.setAddress(address1);
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+}
\ No newline at end of file
diff --git a/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueConstraintIntegrationTest.java b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueConstraintIntegrationTest.java
new file mode 100644
index 0000000000..f12313724e
--- /dev/null
+++ b/persistence-modules/java-jpa-3/src/test/java/com/baeldung/jpa/uniqueconstraints/UniqueConstraintIntegrationTest.java
@@ -0,0 +1,116 @@
+package com.baeldung.jpa.uniqueconstraints;
+
+import java.util.Optional;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Persistence;
+
+import org.hibernate.exception.ConstraintViolationException;
+import org.junit.Assert;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class UniqueConstraintIntegrationTest {
+ private static EntityManagerFactory factory;
+ private static EntityManager entityManager;
+
+ @BeforeAll
+ public static void setup() {
+ factory = Persistence.createEntityManagerFactory("jpa-unique-constraints");
+ entityManager = factory.createEntityManager();
+ }
+
+ @Test
+ public void whenPersistPersonWithSameNumberAndStatus_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setPersonNumber(12345L);
+ person1.setIsActive(Boolean.TRUE);
+
+ Person person2 = new Person();
+ person2.setPersonNumber(12345L);
+ person2.setIsActive(Boolean.TRUE);
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+
+ @Test
+ public void whenPersistPersonWithSameSCodeAndDecode_thenConstraintViolationException() {
+ Person person1 = new Person();
+ person1.setDcode("Sec1");
+ person1.setScode("Axybg356");
+
+ Person person2 = new Person();
+ person2.setDcode("Sec1");
+ person2.setScode("Axybg356");
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+
+ @Test
+ public void whenPersistPersonWithSameNumberAndAddress_thenConstraintViolationException() {
+ Address address1 = new Address();
+ address1.setStreetAddress("40 Street");
+
+ Person person1 = new Person();
+ person1.setPersonNumber(54321L);
+ person1.setAddress(address1);
+
+ Person person2 = new Person();
+ person2.setPersonNumber(99999L);
+ person2.setAddress(address1);
+
+ entityManager.getTransaction().begin();
+ entityManager.persist(person1);
+ entityManager.getTransaction().commit();
+
+ entityManager.getTransaction().begin();
+ try {
+ entityManager.persist(person2);
+ entityManager.getTransaction().commit();
+ Assert.fail("Should raise an exception - unique key violation");
+ } catch (Exception ex) {
+ Assert.assertTrue(Optional.of(ex)
+ .map(Throwable::getCause)
+ .map(Throwable::getCause)
+ .filter(x -> x instanceof ConstraintViolationException)
+ .isPresent());
+ } finally {
+ entityManager.getTransaction().rollback();
+ }
+ }
+}
\ No newline at end of file