这是一个矛盾的设计:
为什么说是失败的设计: 因为不支持友好扩展,死代码就是死代码,不能 删除后手动恢复。
但是矛盾点在于,我如果修改了唯一值的时候,会找不到对应的值,但是可以手动添加。
使用场景:
这些自动生成策略不支持的情况下:
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;
}
}
}