這是一個矛盾的設計:
爲什麼說是失敗的設計: 因爲不支持友好擴展,死代碼就是死代碼,不能 刪除後手動恢復。
但是矛盾點在於,我如果修改了唯一值的時候,會找不到對應的值,但是可以手動添加。
使用場景:
這些自動生成策略不支持的情況下:
AbstractPostInsertGenerator
Assigned
CompositeNestedGeneratedValueGenerator
ForeignGenerator
GUIDGenerator
IncrementGenerator
MultipleHiLoPerTableGenerator
MyUUIDGenerator
SequenceGenerator
SequenceHiLoGenerator
SequenceIdentityGenerator
SequenceStyleGenerator
TableGenerator
UUIDGenerator
UUIDHexGenerator
比如,您想寫死幾個id,又想不想寫死的自動生成,這個矛盾的思路,就需要您自己手動創建策略
爲什麼寫死的id,會被替換(源碼解析)
首先列舉一下正常的保存思路:
調用org.springframework.data.jpa.repository.support SimpleJpaRepository 的 save 方法:
saveflush同理:
因爲:
然後:咱們開始分析 save 方法的源碼:
this.entityInformation.isNew(entity):
這個:this.versionAttribute 需要您看一下是什麼時候賦值的往上查,可以看到這個應該是
this.versionAttribute 爲空後:判斷id的class 是否是引用類型,如果不是引用類型就拋異常,如果是,就繼續判斷值是否爲空並把結果傳到最開始的流程
3.因爲id==null–》false 走到這個流程
走到了AbstractEntityManagerImpl checkOpen 就是判斷 EntityManager Session 等是否存活
return this.internalGetSession().merge(entity);
public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException {
MergeContext copyCache = (MergeContext)copiedAlready;
EventSource source = event.getSession();
Object original = event.getOriginal();
if (original != null) {
Object entity;
if (original instanceof HibernateProxy) {
LazyInitializer li = ((HibernateProxy)original).getHibernateLazyInitializer();
if (li.isUninitialized()) {
LOG.trace("Ignoring uninitialized proxy");
event.setResult(source.load(li.getEntityName(), li.getIdentifier()));
return;
}
entity = li.getImplementation();
} else {
entity = original;
}
if (copyCache.containsKey(entity) && copyCache.isOperatedOn(entity)) {
LOG.trace("Already in merge process");
event.setResult(entity);
} else {
if (copyCache.containsKey(entity)) {
LOG.trace("Already in copyCache; setting in merge process");
copyCache.setOperatedOn(entity, true);
}
event.setEntity(entity);
EntityState entityState = null;
EntityEntry entry = source.getPersistenceContext().getEntry(entity);
if (entry == null) {
EntityPersister persister = source.getEntityPersister(event.getEntityName(), entity);
Serializable id = persister.getIdentifier(entity, source);
if (id != null) {
EntityKey key = source.generateEntityKey(id, persister);
Object managedEntity = source.getPersistenceContext().getEntity(key);
entry = source.getPersistenceContext().getEntry(managedEntity);
if (entry != null) {
entityState = EntityState.DETACHED;
}
}
}
if (entityState == null) {
entityState = this.getEntityState(entity, event.getEntityName(), entry, source);
}
switch(entityState) {
case DETACHED:
this.entityIsDetached(event, copyCache);
break;
case TRANSIENT:
this.entityIsTransient(event, copyCache);
break;
case PERSISTENT:
this.entityIsPersistent(event, copyCache);
break;
default:
throw new ObjectDeletedException("deleted instance passed to merge", (Serializable)null, this.getLoggableName(event.getEntityName(), entity));
}
}
}
}
如果數據庫有,就走更新,把查出來的實體,和現在的實體進行對比,合併
之後的合併全是,copyCache裏的兩個實體的merge
this.copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FROM_PARENT);
給value 賦值 其他對象屬性
我本以爲源碼中會判讀兩個值,但是並沒有,自動生成主鍵規則調用生成主鍵,根本就不會在比較,直接就把id給改了:所以破局的原因就是主鍵的生成策略
this.idSetter : 可以研究一下 我會等有空在研究一下,目前看是綁定的規則的時候賦值的
策略代碼:
package com.adc.da.util.utils;
import org.hibernate.*;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDGenerationStrategy;
import org.hibernate.id.uuid.StandardRandomStrategy;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.UUIDTypeDescriptor;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;
import java.io.Serializable;
import java.util.Properties;
import java.util.UUID;
public class MyUUIDGenerator
extends HibernateDaoSupport implements IdentifierGenerator, Configurable {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger(MyUUIDGenerator.class);
/**
* 實體名稱
*/
private String entityName;
public static final String UUID_GEN_STRATEGY = "uuid_gen_strategy";
public static final String UUID_GEN_STRATEGY_CLASS = "uuid_gen_strategy_class";
private UUIDGenerationStrategy strategy;
private UUIDTypeDescriptor.ValueTransformer valueTransformer;
/**
* @param session
* @param obj 傳過來的實體
* @return
* @throws HibernateException
*/
@Override
public Serializable generate(SessionImplementor session, Object obj) throws HibernateException {
Serializable id = session.getEntityPersister(this.entityName, obj).getIdentifier(obj, session);
if (id == null) {
return this.valueTransformer.transform(this.strategy.generateUUID(session));
} else {
SessionFactory sessionFactory = session.getFactory();
Session session2 = sessionFactory.openSession();
Transaction transaction = session2.beginTransaction();
try {
transaction.begin();
Object o = session2.get(Class.forName(entityName), id.toString());
if (o != null) {
return UUID.randomUUID().toString();
} else {
return id;
}
} catch (ClassNotFoundException e) {
LOG.error(e.getMessage());
} finally {
transaction.commit();
session2.close();
}
}
return null;
}
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
this.entityName = params.getProperty("entity_name");
if (this.entityName == null) {
throw new MappingException("no entity name");
}
this.strategy = (UUIDGenerationStrategy) params.get("uuid_gen_strategy");
if (this.strategy == null) {
String strategyClassName = params.getProperty("uuid_gen_strategy_class");
if (strategyClassName != null) {
try {
ClassLoaderService cls = (ClassLoaderService) serviceRegistry.getService(ClassLoaderService.class);
Class strategyClass = cls.classForName(strategyClassName);
try {
this.strategy = (UUIDGenerationStrategy) strategyClass.newInstance();
} catch (Exception var8) {
LOG.unableToInstantiateUuidGenerationStrategy(var8);
}
} catch (ClassLoadingException var9) {
LOG.unableToLocateUuidGenerationStrategy(strategyClassName);
}
}
}
if (this.strategy == null) {
this.strategy = StandardRandomStrategy.INSTANCE;
}
if (UUID.class.isAssignableFrom(type.getReturnedClass())) {
this.valueTransformer = UUIDTypeDescriptor.PassThroughTransformer.INSTANCE;
} else if (String.class.isAssignableFrom(type.getReturnedClass())) {
this.valueTransformer = UUIDTypeDescriptor.ToStringTransformer.INSTANCE;
} else {
if (!byte[].class.isAssignableFrom(type.getReturnedClass())) {
throw new HibernateException("Unanticipated return type [" + type.getReturnedClass().getName() + "] for UUID conversion");
}
this.valueTransformer = UUIDTypeDescriptor.ToBytesTransformer.INSTANCE;
}
}
}