package org.example.demo.hibernate;
import java.time.Period;
import javax.persistence.AttributeConverter;
import javax.persistence.Convert;
import javax.persistence.Converter;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
public class Test {
public static void main(String[] args) throws Exception {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Event event = new Event();
event.span = Period.ofDays(2);
em.getTransaction().begin();
em.persist(event);
em.getTransaction().commit();
em.clear();
Event e = em.find(Event.class, event.id);
// P2D
System.out.println(e.span);
em.close();
factory.close();
}
@Entity(name = "Event")
public static class Event {
@Id
@GeneratedValue
Integer id;
@Convert(converter = PeriodStringConverter.class)
Period span;
}
@Converter
public static class PeriodStringConverter implements AttributeConverter<Period, String> {
@Override
public String convertToDatabaseColumn(Period attribute) {
return attribute.toString();
}
@Override
public Period convertToEntityAttribute(String dbData) {
return Period.parse(dbData);
}
}
}
生成 SQL
drop table if exists Event cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Event (id int4 not null, span varchar(255), primary key (id))
select nextval ('hibernate_sequence')
insert into Event (span, id) values ('P2D', 1)
select test_event0_.id as id1_0_0_, test_event0_.span as span2_0_0_ from Event test_event0_ where test_event0_.id=1
AttributeConverter 转换的类,需要至少定义 equals and/or hashCode ,否则 Hibernate 会报 WARN 参见 org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry.checkEqualsAndHashCode(Class)
如果使用 AttributeConverter 的 attribute type(Java type) 是不可变的(immutable)则 basic type(Hibernate type) 也是不可变的,如果 attribute type(Java type) 是 mutable 则 basic type(Hibernate type) 也是可变的。
尽管 AttributeConverter types 可以是 mutable 并且 dirty checking, deep copying and second-level caching 都可以正常使用。但将它们当做 immutable 更高效。因此应该尽可能使用 immutable types
package org.example.demo.hibernate;
import javax.persistence.AttributeConverter;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Persistence;
public class Test {
public static void main(String[] args) throws Exception {
EntityManagerFactory factory = Persistence.createEntityManagerFactory("test");
EntityManager em = factory.createEntityManager();
Account account = new Account();
account.balance = new Money(100);
em.getTransaction().begin();
em.persist(account);
em.getTransaction().commit();
em.clear();
Account a = em.find(Account.class, account.id);
// 100
System.out.println(a.balance.getCents());
em.getTransaction().begin();
a.balance.setCents(200);
em.getTransaction().commit();
em.close();
factory.close();
}
public static class Money {
private long cents;
public Money(long cents) {
this.cents = cents;
}
public long getCents() {
return cents;
}
public void setCents(long cents) {
this.cents = cents;
}
}
public static class MoneyConverter implements AttributeConverter<Money, Long> {
@Override
public Long convertToDatabaseColumn(Money attribute) {
return attribute == null ? null : attribute.getCents();
}
@Override
public Money convertToEntityAttribute(Long dbData) {
return dbData == null ? null : new Money(dbData);
}
}
@Entity(name = "Account")
public static class Account {
@Id
@GeneratedValue
Long id;
String owner;
@Convert(converter = MoneyConverter.class)
Money balance;
}
}
生成的 SQL
drop table if exists Account cascade
drop sequence if exists hibernate_sequence
create sequence hibernate_sequence start 1 increment 1
create table Account (id int8 not null, balance int8, owner varchar(255), primary key (id))
select nextval ('hibernate_sequence')
insert into Account (balance, owner, id) values (100, NULL, 1)
update Account set balance=100, owner=NULL where id=1
select test_accou0_.id as id1_0_0_, test_accou0_.balance as balance2_0_0_, test_accou0_.owner as owner3_0_0_ from Account test_accou0_ where test_accou0_.id=1
update Account set balance=200, owner=NULL where id=1