JPA: Difference between revisions
Jump to navigation
Jump to search
(41 intermediate revisions by the same user not shown) | |||
Line 6: | Line 6: | ||
The Instant class represents a moment on the timeline in '''UTC''' with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).All three java.time.Local… classes are all lacking any concept of time zone or offset-from-UTC. | The Instant class represents a moment on the timeline in '''UTC''' with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).All three java.time.Local… classes are all lacking any concept of time zone or offset-from-UTC. | ||
==Sequence Style== | |||
<source lang="java"> | |||
@Id | |||
@Column(name = "code", length = 6) | |||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "page_sqn") | |||
//@SequenceGenerator(name = "page_sqn", sequenceName = "page_sqn", initialValue = 60466176, allocationSize = 1) | |||
@GenericGenerator(name = "page_sqn", strategy = "org.chorke.academia.core.entity.Base36Style", parameters = { | |||
@Parameter(name = Base36Style.INITIAL_VALUE, value = Base36Style.DIGIT_6_MIN), | |||
@Parameter(name = Base36Style.SEQUENCE_NAME, value = "page_sqn"), | |||
@Parameter(name = Base36Style.ALLOCATION_SIZE, value = "1"), | |||
}) | |||
private String code; | |||
</source> | |||
<source lang="java" highlight="15-17,34,41"> | |||
package org.chorke.academia.core.entity; | |||
import java.io.Serializable; | |||
import java.util.Properties; | |||
import org.hibernate.HibernateException; | |||
import org.hibernate.MappingException; | |||
import org.hibernate.engine.spi.SharedSessionContractImplementor; | |||
import org.hibernate.id.enhanced.SequenceStyleGenerator; | |||
import org.hibernate.service.ServiceRegistry; | |||
import org.hibernate.type.Type; | |||
public class Base36Style extends SequenceStyleGenerator { | |||
private static final Logger LOG = LoggerFactory.getLogger(Base36Style.class); | |||
public static final String ALLOCATION_SIZE = INCREMENT_PARAM; | |||
public static final String SEQUENCE_NAME = SEQUENCE_PARAM; | |||
public static final String INITIAL_VALUE = INITIAL_PARAM; | |||
public static final int RADIX = 36; | |||
public static final String DIGIT_1_MIN = "0"; // 0 => Z | |||
public static final String DIGIT_2_MIN = "36"; // 10 => ZZ | |||
public static final String DIGIT_3_MIN = "1296"; // 100 => ZZZ | |||
public static final String DIGIT_4_MIN = "46656"; // 1,000 => Z,ZZZ | |||
public static final String DIGIT_5_MIN = "1679616"; // 10,000 => ZZ,ZZZ | |||
public static final String DIGIT_6_MIN = "60466176"; // 100,000 => ZZZ,ZZZ | |||
public static final String DIGIT_7_MIN = "2176782336"; // 1,000,000 => Z,ZZZ,ZZZ | |||
public static final String DIGIT_8_MIN = "78364164096"; // 10,000,000 => ZZ,ZZZ,ZZZ | |||
public static final String DIGIT_9_MIN = "2821109907456"; // 100,000,000 => ZZZ,ZZZ,ZZZ | |||
public static final String DIGIT_X_MIN = "101559956668416"; //1,000,000,000 => Z,ZZZ,ZZZ,ZZZ | |||
@Override | |||
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException { | |||
Serializable nextval = super.generate(session, object); | |||
String base36 = Long.toString((Long) nextval, RADIX); | |||
LOG.debug("Base36: {}", base36.toUpperCase()); | |||
return base36.toUpperCase(); | |||
} | |||
@Override | |||
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { | |||
super.configure(LongType.INSTANCE, params, serviceRegistry); | |||
} | |||
} | |||
</source> | |||
==Challenges== | |||
{| class="wikitable sortable" | |||
|- | |||
! Database !! Auto Increment !! Sequence !! Usable | |||
|- | |||
! DB2/LUW | |||
| <code>✓</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! DB2/z | |||
| <code>✓</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! PostgreSQL | |||
| <code>✓</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! Derby | |||
| <code>✕</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! Firebird | |||
| <code>✕</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! H2 | |||
| <code>✓</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! HyperSQL | |||
| <code>✓</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! INGRES | |||
| <code>✓</code> || <code>✕</code> || <code>✕</code> | |||
|- | |||
! Informix | |||
| <code>✓</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! MariaDB | |||
| <code>✓</code> || <code>✕</code> || <code>✕</code> | |||
|- | |||
! MySQL | |||
| <code>✓</code> || <code>✕</code> || <code>✕</code> | |||
|- | |||
! Oracle | |||
| <code>✕</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! Sql Server | |||
| <code>✕</code> || <code>✓</code> || <code>✓</code> | |||
|- | |||
! SQLite | |||
| <code>✓</code> || <code>✕</code> || <code>✕</code> | |||
|- | |||
! Sybase | |||
| <code>✓</code> || <code>✕</code> || <code>✕</code> | |||
|- | |||
! Sybase Anywhere | |||
| <code>✓</code> || <code>✓</code> || <code>✓</code> | |||
|} | |||
==Date Time== | |||
<source lang="java"> | |||
import java.time.LocalDateTime; | |||
import java.time.temporal.ChronoUnit; | |||
class Playground { | |||
public static void main(String[ ] args) { | |||
System.out.println("Yesterday Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L)); | |||
System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusNanos(1L)); | |||
System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L).plusDays(1L).minusNanos(1L)); | |||
System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L).plusHours(24).minusNanos(1L)); | |||
System.out.println(); | |||
System.out.println("Today Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS)); | |||
System.out.println("Today Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(1L).minusNanos(1L)); | |||
System.out.println("Today Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusHours(24).minusNanos(1L)); | |||
System.out.println(); | |||
System.out.println("Tomorrow Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(1L)); | |||
System.out.println("Tomorrow Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(2L).minusNanos(1L)); | |||
System.out.println("Tomorrow Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusHours(48).minusNanos(1L)); | |||
} | |||
} | |||
</source> | |||
==Knowledge== | |||
{| | |||
| valign="top" colspan="2" | | |||
<source lang='java'> | |||
import org.hibernate.Session; | |||
Session session = (Session) entityManager.getDelegate(); | |||
Page<Country> countries = countryRepo.findAll(page); | |||
countries = countries.map(country -> { | |||
session.evict(country); | |||
if (ObjectUtils.isEmpty(country.getContinent())) { | |||
Continent continent = continentRepo.findById(country.getContinentCode()); | |||
country.setContinent(continent); | |||
return country; | |||
} else return country; | |||
}); | |||
</source> | |||
|- | |||
| colspan="2" | | |||
---- | |||
|- | |||
| valign="top" colspan="2" | | |||
<source lang='java'> | |||
@PersistenceContext | |||
EntityManager entityManager; | |||
if (entityManager.contains(country)) entityManager.detach(country); | |||
// entityManager.detach(country); | |||
</source> | |||
|- | |||
| colspan="2" | | |||
---- | |||
|- | |||
| valign="top" | | |||
| valign="top" | | |||
|} | |||
==References== | ==References== | ||
Line 22: | Line 202: | ||
| valign="top" | | | valign="top" | | ||
* [https://stackoverflow.com/questions/24650186 Choosing between <code>java.util.Date</code> or <code>java.sql.Date</code>] | * [https://stackoverflow.com/questions/24650186/ Choosing between <code>java.util.Date</code> or <code>java.sql.Date</code>] | ||
* [https://stackoverflow.com/questions/47259048 How to generate Custom Id] | * [https://programmer.group/integration-of-mybatis-and-jpa-persistence-in-springboot-learning-6.html Integration of MyBatis & JPA in Spring boot] | ||
* [https://thorben-janssen.com/custom-sequence-based-idgenerator/ Custom Sequence Based ID Generator] | |||
* [https://docs.liquibase.com/change-types/community/add-auto-increment.html#:~:text=Database%20support Auto Increment Supported Database] | |||
* [https://stackoverflow.com/questions/30397988/ SQLite3 Doesn't Provide a Date Type] | |||
* [https://stackoverflow.com/questions/52887289/ JPA use hbm.xml & annotations] | |||
* [https://stackoverflow.com/questions/9319850/ JPA & SQLite3 - Wrong Date] | |||
* [https://stackoverflow.com/questions/47259048/ How to generate Custom Id] | |||
* [https://stackoverflow.com/questions/27690709/ JPA Primary Key Prefix] | |||
* [https://stackoverflow.com/questions/1404210/ Java Date vs Calendar] | |||
| valign="top" | | |||
* [https://stackoverflow.com/questions/21708339/ Prevent Jackson to Serialize <code>Non-Fetched Lazy</code> Objects] | |||
* [https://stackoverflow.com/questions/57168773/ Does JPA delete also remove large objects of Blob fields] | |||
* [https://programmer.group/oracle-to-mysql-database-migration-primary-key-generation-policy-replacement.html Using MySQL table to simulate Oracle Sequence] | |||
* [https://www.baeldung.com/spring-data-jpa-stored-procedures Calling Stored Procedures from Spring Data JPA] | |||
* [https://stackoverflow.com/questions/28539915/ Multiple SequenceGenerator in Hibernate Entity] | |||
* [https://coderanch.com/t/573996/databases/SequenceGenerator-MySql-Database <code>@SequenceGenerator</code> for MySql Database] | |||
* [https://docs.liquibase.com/change-types/community/create-sequence.html#:~:text=Database%20support Create Sequence Supported Database] | |||
* [https://vladmihalcea.com/ Vlad Mihalcea the Java Champion] | |||
* [https://github.com/eugenp/tutorials/blob/master/persistence-modules/spring-data-jpa-repo/src/main/java/com/baeldung/storedprocedure/repository/CarRepository.java Example of Stored Procedure] | |||
* [[Liquibase]] | |||
|- | |||
| colspan="3" | | |||
---- | |||
|- | |||
| valign="top" | | |||
* [https://stackoverflow.com/questions/45973070/ Spring JPA ExampleMatcher compare date condition] | |||
* [https://stackoverflow.com/questions/60112439 Difference btn. <code>evict</code> and <code>detach</code> in hibernate] | |||
* [https://stackoverflow.com/questions/65478350/ Column type is JSON but expression is Varchar] | |||
* [https://stackoverflow.com/questions/39620317/ Map a JSON column with H2 & Spring JPA] | |||
* [https://stackoverflow.com/questions/2311125/ Ignore Hibernate <code>@Where</code> annotation] | |||
* [https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html Java » ISO <code>DateTimeFormatter</code>] | |||
* [https://stackoverflow.com/questions/7700071/ Use <code>@Where</code> in Hibernate] | |||
* [[PostgreSQL]] | |||
* [[MapStruct]] | |||
* [[Lombok]] | |||
|} | |} |
Latest revision as of 18:06, 1 February 2024
Replacements
java.util.Date => java.time.Instant java.sql.Timestamp => java.time.Instant java.sql.Date => java.time.LocalDate java.sql.Time => java.time.LocalTime
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).All three java.time.Local… classes are all lacking any concept of time zone or offset-from-UTC.
Sequence Style
@Id
@Column(name = "code", length = 6)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "page_sqn")
//@SequenceGenerator(name = "page_sqn", sequenceName = "page_sqn", initialValue = 60466176, allocationSize = 1)
@GenericGenerator(name = "page_sqn", strategy = "org.chorke.academia.core.entity.Base36Style", parameters = {
@Parameter(name = Base36Style.INITIAL_VALUE, value = Base36Style.DIGIT_6_MIN),
@Parameter(name = Base36Style.SEQUENCE_NAME, value = "page_sqn"),
@Parameter(name = Base36Style.ALLOCATION_SIZE, value = "1"),
})
private String code;
package org.chorke.academia.core.entity;
import java.io.Serializable;
import java.util.Properties;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
public class Base36Style extends SequenceStyleGenerator {
private static final Logger LOG = LoggerFactory.getLogger(Base36Style.class);
public static final String ALLOCATION_SIZE = INCREMENT_PARAM;
public static final String SEQUENCE_NAME = SEQUENCE_PARAM;
public static final String INITIAL_VALUE = INITIAL_PARAM;
public static final int RADIX = 36;
public static final String DIGIT_1_MIN = "0"; // 0 => Z
public static final String DIGIT_2_MIN = "36"; // 10 => ZZ
public static final String DIGIT_3_MIN = "1296"; // 100 => ZZZ
public static final String DIGIT_4_MIN = "46656"; // 1,000 => Z,ZZZ
public static final String DIGIT_5_MIN = "1679616"; // 10,000 => ZZ,ZZZ
public static final String DIGIT_6_MIN = "60466176"; // 100,000 => ZZZ,ZZZ
public static final String DIGIT_7_MIN = "2176782336"; // 1,000,000 => Z,ZZZ,ZZZ
public static final String DIGIT_8_MIN = "78364164096"; // 10,000,000 => ZZ,ZZZ,ZZZ
public static final String DIGIT_9_MIN = "2821109907456"; // 100,000,000 => ZZZ,ZZZ,ZZZ
public static final String DIGIT_X_MIN = "101559956668416"; //1,000,000,000 => Z,ZZZ,ZZZ,ZZZ
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
Serializable nextval = super.generate(session, object);
String base36 = Long.toString((Long) nextval, RADIX);
LOG.debug("Base36: {}", base36.toUpperCase());
return base36.toUpperCase();
}
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
super.configure(LongType.INSTANCE, params, serviceRegistry);
}
}
Challenges
Database | Auto Increment | Sequence | Usable |
---|---|---|---|
DB2/LUW | ✓ |
✓ |
✓
|
DB2/z | ✓ |
✓ |
✓
|
PostgreSQL | ✓ |
✓ |
✓
|
Derby | ✕ |
✓ |
✓
|
Firebird | ✕ |
✓ |
✓
|
H2 | ✓ |
✓ |
✓
|
HyperSQL | ✓ |
✓ |
✓
|
INGRES | ✓ |
✕ |
✕
|
Informix | ✓ |
✓ |
✓
|
MariaDB | ✓ |
✕ |
✕
|
MySQL | ✓ |
✕ |
✕
|
Oracle | ✕ |
✓ |
✓
|
Sql Server | ✕ |
✓ |
✓
|
SQLite | ✓ |
✕ |
✕
|
Sybase | ✓ |
✕ |
✕
|
Sybase Anywhere | ✓ |
✓ |
✓
|
Date Time
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
class Playground {
public static void main(String[ ] args) {
System.out.println("Yesterday Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L));
System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusNanos(1L));
System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L).plusDays(1L).minusNanos(1L));
System.out.println("Yesterday Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).minusDays(1L).plusHours(24).minusNanos(1L));
System.out.println();
System.out.println("Today Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS));
System.out.println("Today Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(1L).minusNanos(1L));
System.out.println("Today Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusHours(24).minusNanos(1L));
System.out.println();
System.out.println("Tomorrow Min: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(1L));
System.out.println("Tomorrow Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusDays(2L).minusNanos(1L));
System.out.println("Tomorrow Max: " + LocalDateTime.now().truncatedTo(ChronoUnit.DAYS).plusHours(48).minusNanos(1L));
}
}
Knowledge
import org.hibernate.Session;
Session session = (Session) entityManager.getDelegate();
Page<Country> countries = countryRepo.findAll(page);
countries = countries.map(country -> {
session.evict(country);
if (ObjectUtils.isEmpty(country.getContinent())) {
Continent continent = continentRepo.findById(country.getContinentCode());
country.setContinent(continent);
return country;
} else return country;
});
| |
| |
@PersistenceContext
EntityManager entityManager;
if (entityManager.contains(country)) entityManager.detach(country);
// entityManager.detach(country);
| |
| |