下面列出了怎么用org.hibernate.NonUniqueObjectException的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Performs the load of an entity.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
*
* @return The loaded entity.
*/
private CompletionStage<Object> load( LoadEvent event, EntityPersister persister, EntityKey keyToLoad, LoadType options) {
final EventSource session = event.getSession();
if ( event.getInstanceToLoad() != null ) {
if ( session.getPersistenceContextInternal().getEntry( event.getInstanceToLoad() ) != null ) {
throw new PersistentObjectException(
"attempted to load into an instance that was already associated with the session: " +
MessageHelper.infoString( persister, event.getEntityId(), session.getFactory() ) );
}
persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), session );
}
return doLoad( event, persister, keyToLoad, options )
.thenApply( optional -> {
boolean isOptionalInstance = event.getInstanceToLoad() != null;
if ( optional==null && ( !options.isAllowNulls() || isOptionalInstance ) ) {
throwEntityNotFound( session, event.getEntityClassName(), event.getEntityId() );
}
else if ( isOptionalInstance && optional != event.getInstanceToLoad() ) {
throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
}
return optional;
} );
}
public static void saveWithoutUpdate(List<Subject> subjects){
HibernateUtil.withSession(session -> {
session.beginTransaction();
int saved = 0;
for (Subject subject : subjects) {
try{
session.save(subject);
saved++;
}catch(NonUniqueObjectException e){
log.warn("Could not save subject {}, name {},", subject.getLabel(), subject.getName());
}
if ( saved % 50 == 0 ) {
session.flush();
session.clear();
}
}
session.getTransaction().commit();
});
}
public static int save(List<TimedValue> timedValues){
return HibernateUtil.withSession((session) -> {
int saved = 0;
session.beginTransaction();
for (TimedValue timedValue : timedValues){
try{
session.saveOrUpdate(timedValue);
saved++;
}catch(NonUniqueObjectException e){
// This is happening because the TFL stations contain a duplicate ID
log.warn("Could not save timed value for subject {}, attribute {}, time {}: {}",
timedValue.getId().getSubject().getLabel(),
timedValue.getId().getAttribute().getDescription(),
timedValue.getId().getTimestamp().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
e.getMessage());
}
if ( saved % 50 == 0 ) { // because batch size in the hibernate config is 50
session.flush();
session.clear();
}
}
session.getTransaction().commit();
return saved;
});
}
public static int saveWithoutUpdate(List<TimedValue> timedValues){
return HibernateUtil.withSession((session) -> {
int saved = 0;
session.beginTransaction();
for (TimedValue timedValue : timedValues){
try{
session.save(timedValue);
saved++;
}catch(NonUniqueObjectException e){
log.warn("Could not save timed value for subject {}, attribute {}, time {}: {}",
timedValue.getId().getSubject().getLabel(),
timedValue.getId().getAttribute().getDescription(),
timedValue.getId().getTimestamp().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
e.getMessage());
}
if ( saved % 50 == 0 ) {
session.flush();
session.clear();
}
}
session.getTransaction().commit();
return saved;
});
}
public static int save(List<FixedValue> fixedValues){
return HibernateUtil.withSession((session) -> {
int saved = 0;
session.beginTransaction();
for (FixedValue fixedValue : fixedValues){
try{
session.saveOrUpdate(fixedValue);
saved++;
}catch(NonUniqueObjectException e){
// This is happening because the TFL stations contain a duplicate ID
log.warn("Could not save fixed value for subject {}, attribute {}: {}",
fixedValue.getId().getSubject().getLabel(),
fixedValue.getId().getAttribute().getLabel(),
e.getMessage());
}
if ( saved % 50 == 0 ) { // because batch size in the hibernate config is 50
session.flush();
session.clear();
}
}
session.getTransaction().commit();
return saved;
});
}
public static int saveWithoutUpdate(List<FixedValue> fixedValues){
return HibernateUtil.withSession((session) -> {
int saved = 0;
session.beginTransaction();
for (FixedValue fixedValue : fixedValues){
try{
session.save(fixedValue);
saved++;
}catch(NonUniqueObjectException e){
log.warn("Could not save fixed value for subject {}, attribute {}: {}",
fixedValue.getId().getSubject().getLabel(),
fixedValue.getId().getAttribute().getLabel(),
e.getMessage());
}
if ( saved % 50 == 0 ) {
session.flush();
session.clear();
}
}
session.getTransaction().commit();
return saved;
});
}
public void testPersistThenMergeInSameTxnWithVersion() {
Session s = openSession();
Transaction tx = s.beginTransaction();
VersionedEntity entity = new VersionedEntity( "test", "test" );
s.persist( entity );
s.merge( new VersionedEntity( "test", "test-2" ) );
try {
// control operation...
s.saveOrUpdate( new VersionedEntity( "test", "test-3" ) );
fail( "saveOrUpdate() should fail here" );
}
catch( NonUniqueObjectException expected ) {
// expected behavior
}
tx.commit();
s.close();
cleanup();
}
public void testPersistThenMergeInSameTxnWithTimestamp() {
Session s = openSession();
Transaction tx = s.beginTransaction();
TimestampedEntity entity = new TimestampedEntity( "test", "test" );
s.persist( entity );
s.merge( new TimestampedEntity( "test", "test-2" ) );
try {
// control operation...
s.saveOrUpdate( new TimestampedEntity( "test", "test-3" ) );
fail( "saveOrUpdate() should fail here" );
}
catch( NonUniqueObjectException expected ) {
// expected behavior
}
tx.commit();
s.close();
cleanup();
}
@Override
public void checkUniqueness(EntityKey key, Object object) throws HibernateException {
final Object entity = getEntity( key );
if ( entity == object ) {
throw new AssertionFailure( "object already associated, but no entry was found" );
}
if ( entity != null ) {
throw new NonUniqueObjectException( key.getIdentifier(), key.getEntityName() );
}
}
/**
* Performs the load of an entity.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
*
* @return The loaded entity.
*
* @throws HibernateException
*/
private Object load(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options) {
if ( event.getInstanceToLoad() != null ) {
if ( event.getSession().getPersistenceContext().getEntry( event.getInstanceToLoad() ) != null ) {
throw new PersistentObjectException(
"attempted to load into an instance that was already associated with the session: " +
MessageHelper.infoString(
persister,
event.getEntityId(),
event.getSession().getFactory()
)
);
}
persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), event.getSession() );
}
final Object entity = doLoad( event, persister, keyToLoad, options );
boolean isOptionalInstance = event.getInstanceToLoad() != null;
if ( entity == null && ( !options.isAllowNulls() || isOptionalInstance ) ) {
event.getSession()
.getFactory()
.getEntityNotFoundDelegate()
.handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
}
else if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
}
return entity;
}
/**
* Attempts to check whether the given key represents an entity already loaded within the
* current session.
* @param object The entity reference against which to perform the uniqueness check.
* @throws HibernateException
*/
public void checkUniqueness(EntityKey key, Object object) throws HibernateException {
Object entity = getEntity(key);
if ( entity == object ) {
throw new AssertionFailure( "object already associated, but no entry was found" );
}
if ( entity != null ) {
throw new NonUniqueObjectException( key.getIdentifier(), key.getEntityName() );
}
}
/**
* Perfoms the load of an entity.
*
* @return The loaded entity.
* @throws HibernateException
*/
protected Object load(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options)
throws HibernateException {
if ( event.getInstanceToLoad() != null ) {
if ( event.getSession().getPersistenceContext().getEntry( event.getInstanceToLoad() ) != null ) {
throw new PersistentObjectException(
"attempted to load into an instance that was already associated with the session: " +
MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
);
}
persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), event.getSession().getEntityMode() );
}
Object entity = doLoad(event, persister, keyToLoad, options);
boolean isOptionalInstance = event.getInstanceToLoad() != null;
if ( !options.isAllowNulls() || isOptionalInstance ) {
if ( entity == null ) {
event.getSession().getFactory().getEntityNotFoundDelegate().handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
}
}
if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
}
return entity;
}
public static boolean lock(SessionFactory sessionFactory, Object target) {
Session session = sessionFactory.getCurrentSession();
try {
session.buildLockRequest(LockOptions.NONE).lock(target);
return true;
} catch (NonUniqueObjectException e) {
// different object with the same identifier value was already associated with the session
return false;
}
}
@Test
public void givenSessionContainingAnId_whenIdAssociatedAgain_thenNonUniqueObjectException() {
thrown.expect(isA(NonUniqueObjectException.class));
thrown.expectMessage(
"A different object with the same identifier value was already associated with the session");
Session session = null;
Transaction transaction = null;
try {
session = sessionFactory.openSession();
transaction = session.beginTransaction();
Product product1 = new Product();
product1.setId(1);
product1.setName("Product 1");
session.save(product1);
Product product2 = new Product();
product2.setId(1);
product2.setName("Product 2");
session.save(product2);
transaction.commit();
} catch (Exception e) {
rollbackTransactionQuietly(transaction);
throw (e);
} finally {
closeSessionQuietly(session);
}
}
/**
* Prepares the save call by checking the session caches for a pre-existing
* entity and performing any lifecycle callbacks.
*
* @param entity The entity to be saved.
* @param id The id by which to save the entity.
* @param persister The entity's persister instance.
* @param useIdentityColumn Is an identity column being used?
* @param context Generally cascade-specific information.
* @param source The session from which the event originated.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
* not, post-insert style id generators may be postponed if we are outside
* a transaction).
*
* @return The id used to save the entity; may be null depending on the
* type of id generator used and the requiresImmediateIdAccess value
*/
protected CompletionStage<Void> reactivePerformSave(
Object entity,
Serializable id,
EntityPersister persister,
boolean useIdentityColumn,
C context,
EventSource source,
boolean requiresImmediateIdAccess) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Saving {0}", MessageHelper.infoString( persister, id, source.getFactory() ) );
}
final EntityKey key;
if ( !useIdentityColumn ) {
key = source.generateEntityKey( id, persister );
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
Object old = persistenceContext.getEntity( key );
if ( old != null ) {
if ( persistenceContext.getEntry( old ).getStatus() == Status.DELETED ) {
source.forceFlush( persistenceContext.getEntry( old ) );
}
else {
return CompletionStages.failedFuture( new NonUniqueObjectException( id, persister.getEntityName() ) );
}
}
persister.setIdentifier( entity, id, source );
}
else {
key = null;
}
return reactivePerformSaveOrReplicate(
entity,
key,
persister,
useIdentityColumn,
context,
source,
requiresImmediateIdAccess
);
}
/**
* Construct a ActivationKeyCloneCommand
* @param userIn user doing the cloning
* @param key Activation key to be cloned
* @param cloneDescription The description of the cloned key.
*/
public ActivationKeyCloneCommand(User userIn, String key,
String cloneDescription) {
ActivationKeyManager akm = ActivationKeyManager.getInstance();
ActivationKey ak = lookupKey(key, userIn);
try {
cak = akm.createNewActivationKey(userIn, "", cloneDescription,
ak.getUsageLimit(), ak.getBaseChannel(), false);
// only one akey can be Universal default
}
catch (ValidatorException ve) { // the user is not allowed to create AK
throw FaultException.create(1091, "activationkey", ve.getResult());
}
catch (NonUniqueObjectException e) {
throw new ActivationKeyAlreadyExistsException();
}
// enable/disable
cak.setDisabled(ak.isDisabled());
// Entitlements
Set<ServerGroupType> cloneEnt = new HashSet<ServerGroupType>();
cloneEnt.addAll(ak.getEntitlements());
cak.setEntitlements(cloneEnt);
// child channels
Set<Channel> channels = new HashSet<Channel>();
channels.addAll(ak.getChannels());
cak.setChannels(channels);
// Configuration File Deployment
cak.setDeployConfigs(ak.getDeployConfigs());
// packages
for (Iterator<TokenPackage> it = ak.getPackages().iterator(); it
.hasNext();) {
TokenPackage temp = it.next();
cak.addPackage(temp.getPackageName(), temp.getPackageArch());
}
// Configuration channels
List<String> lcloneConfigChannels = new ArrayList<String>();
for (Iterator<ConfigChannel> it = ak.getConfigChannelsFor(userIn)
.iterator(); it.hasNext();) {
lcloneConfigChannels.add(it.next().getLabel());
}
List<String> lcak = new ArrayList<String>();
lcak.add(cak.getKey());
setConfigChannels(userIn, lcak, lcloneConfigChannels);
// Groups
Set<ServerGroup> cloneServerGroups = new HashSet<ServerGroup>();
cloneServerGroups.addAll(ak.getServerGroups());
cak.setServerGroups(cloneServerGroups);
// Contact method
cak.setContactMethod(ak.getContactMethod());
}
/**
* Prepares the save call by checking the session caches for a pre-existing
* entity and performing any lifecycle callbacks.
*
* @param entity The entity to be saved.
* @param id The id by which to save the entity.
* @param persister The entity's persister instance.
* @param useIdentityColumn Is an identity column being used?
* @param anything Generally cascade-specific information.
* @param source The session from which the event originated.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
* not, post-insert style id generators may be postponed if we are outside
* a transaction).
*
* @return The id used to save the entity; may be null depending on the
* type of id generator used and the requiresImmediateIdAccess value
*/
protected Serializable performSave(
Object entity,
Serializable id,
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
EventSource source,
boolean requiresImmediateIdAccess) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Saving {0}", MessageHelper.infoString( persister, id, source.getFactory() ) );
}
final EntityKey key;
if ( !useIdentityColumn ) {
key = source.generateEntityKey( id, persister );
Object old = source.getPersistenceContext().getEntity( key );
if ( old != null ) {
if ( source.getPersistenceContext().getEntry( old ).getStatus() == Status.DELETED ) {
source.forceFlush( source.getPersistenceContext().getEntry( old ) );
}
else {
throw new NonUniqueObjectException( id, persister.getEntityName() );
}
}
persister.setIdentifier( entity, id, source );
}
else {
key = null;
}
if ( invokeSaveLifecycle( entity, persister, source ) ) {
return id; //EARLY EXIT
}
return performSaveOrReplicate(
entity,
key,
persister,
useIdentityColumn,
anything,
source,
requiresImmediateIdAccess
);
}
/**
* Ppepares the save call by checking the session caches for a pre-existing
* entity and performing any lifecycle callbacks.
*
* @param entity The entity to be saved.
* @param id The id by which to save the entity.
* @param persister The entity's persister instance.
* @param useIdentityColumn Is an identity column being used?
* @param anything Generally cascade-specific information.
* @param source The session from which the event originated.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
* not, post-insert style id generators may be postponed if we are outside
* a transaction).
*
* @return The id used to save the entity; may be null depending on the
* type of id generator used and the requiresImmediateIdAccess value
*/
protected Serializable performSave(
Object entity,
Serializable id,
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
EventSource source,
boolean requiresImmediateIdAccess) {
if ( log.isTraceEnabled() ) {
log.trace(
"saving " +
MessageHelper.infoString( persister, id, source.getFactory() )
);
}
EntityKey key;
if ( !useIdentityColumn ) {
key = new EntityKey( id, persister, source.getEntityMode() );
Object old = source.getPersistenceContext().getEntity( key );
if ( old != null ) {
if ( source.getPersistenceContext().getEntry( old ).getStatus() == Status.DELETED ) {
source.forceFlush( source.getPersistenceContext().getEntry( old ) );
}
else {
throw new NonUniqueObjectException( id, persister.getEntityName() );
}
}
persister.setIdentifier( entity, id, source.getEntityMode() );
}
else {
key = null;
}
if ( invokeSaveLifecycle( entity, persister, source ) ) {
return id; //EARLY EXIT
}
return performSaveOrReplicate(
entity,
key,
persister,
useIdentityColumn,
anything,
source,
requiresImmediateIdAccess
);
}
@Test(expected = NonUniqueObjectException.class)
public void testAddAdd() {
dao.add("uuid", "componentId", "contextId1");
dao.add("uuid", "componentId", "contextId2");
}
@Test(expected = NonUniqueObjectException.class)
public void testAddAdd() {
dao.add("uuid", "componentId", "contextId1");
dao.add("uuid", "componentId", "contextId2");
}
/**
* Construct a ActivationKeyCloneCommand
* @param userIn user doing the cloning
* @param key Activation key to be cloned
* @param cloneDescription The description of the cloned key.
*/
public ActivationKeyCloneCommand(User userIn, String key,
String cloneDescription) {
ActivationKeyManager akm = ActivationKeyManager.getInstance();
ActivationKey ak = lookupKey(key, userIn);
try {
cak = akm.createNewActivationKey(userIn, "", cloneDescription,
ak.getUsageLimit(), ak.getBaseChannel(), false);
// only one akey can be Universal default
}
catch (ValidatorException ve) { // the user is not allowed to create AK
throw FaultException.create(1091, "activationkey", ve.getResult());
}
catch (NonUniqueObjectException e) {
throw new ActivationKeyAlreadyExistsException();
}
// enable/disable
cak.setDisabled(ak.isDisabled());
// Entitlements
Set<ServerGroupType> cloneEnt = new HashSet<ServerGroupType>();
cloneEnt.addAll(ak.getEntitlements());
cak.setEntitlements(cloneEnt);
// child channels
Set<Channel> channels = new HashSet<Channel>();
channels.addAll(ak.getChannels());
cak.setChannels(channels);
// Configuration File Deployment
cak.setDeployConfigs(ak.getDeployConfigs());
// packages
for (Iterator<TokenPackage> it = ak.getPackages().iterator(); it
.hasNext();) {
TokenPackage temp = it.next();
cak.addPackage(temp.getPackageName(), temp.getPackageArch());
}
// Configuration channels
List<String> lcloneConfigChannels = new ArrayList<String>();
for (Iterator<ConfigChannel> it = ak.getConfigChannelsFor(userIn)
.iterator(); it.hasNext();) {
lcloneConfigChannels.add(it.next().getLabel());
}
List<String> lcak = new ArrayList<String>();
lcak.add(cak.getKey());
setConfigChannels(userIn, lcak, lcloneConfigChannels);
// Groups
Set<ServerGroup> cloneServerGroups = new HashSet<ServerGroup>();
cloneServerGroups.addAll(ak.getServerGroups());
cak.setServerGroups(cloneServerGroups);
}
/**
* Persists all the given entities into the DB configured in the {@code SessionFactory}. Specify
* the following system properties backoff.delay
*/
@Override
@Transactional
@Retryable(
value = {LockAcquisitionException.class},
maxAttemptsExpression = "#{ @systemProperties['retryBackoff'] ?: 20}",
backoff =
@Backoff(
delayExpression = "#{ @systemProperties['retryDelay'] ?: 100}",
maxDelayExpression = "#{ @systemProperties['retryMaxDelay'] ?: 50000 }",
multiplierExpression = "#{ @systemProperties['retryMultiplier'] ?: 1.5}"))
public void persistReportEntities(List<? extends Report> reportEntities) {
int batchFlush = 0;
Session session = sessionFactory.getCurrentSession();
FlushMode previousFlushMode = session.getHibernateFlushMode();
session.setHibernateFlushMode(FlushMode.MANUAL);
try {
for (Report report : reportEntities) {
report.setRowId();
session.saveOrUpdate(report);
batchFlush++;
if (batchFlush == config.getBatchSize()) {
session.flush();
session.clear();
batchFlush = 0;
}
}
if (batchFlush > 0) {
session.flush();
session.clear();
}
} catch (NonUniqueObjectException ex) {
// Github issue 268 & 280
// https://github.com/googleads/aw-reporting/issues/268
// https://github.com/googleads/aw-reporting/issues/280
//
// Currently we allow specifying report definitions which do not include all primary key
// fields. This leads to cryptic hibernate errors without providing a reasonable
// resolution strategy.
//
// This fix explains where to find the list of primary key fields, but does not address
// the underlying issue of allowing non-unique rows to be downloaded in the first place.
//
// Ideally we would guarantee uniqueness of rows without the user having to specify the
// PK fields.
// However, this would be a substantial migration for the AWReporting user base.
// Instead, we just log a (hopefully) useful error message.
// Also note that the error message assumes that reportEntities was not empty, because
// otherwise the exception would not have been thrown.
logger.error(
"Duplicate row detected. This is most likely because your report definition does not "
+ "include the primary key fields defined in {}.setRowId(). "
+ "Please add the missing fields and try again.",
reportEntities.get(0).getClass().getName());
throw ex;
} finally {
session.setHibernateFlushMode(previousFlushMode);
}
}