Hibernate 2.1.6 source code analysis

xiaoxiao2021-03-06  41

Article continuously updated each modification will be identified by color, and if there is any questions to identify the first annotation

1.sessionImpl.saveorupdate

Public void saveorupdate (Object obj) throws hibernateException {if (obj == null) throw new nullpointRexception ("Attempted to update null); // If the object is empty, throw an exception

IF (ReassociateifunInitializedProxy (obj)) Return;

Object Object = unproxyandreassociate (obj); // a proxy is always "update", Never "save"

EntityEntry E = GetEntry (Object); // Take Obj related ENTITYENTRY from the session, this object holds PO Current Status IF (E! = Null && E.STATUS! = Deleted) {// If in Obj in Session There is already corresponding ENTITYENTRY, that is, OBJ is already PO, and the status is not deleted, then do something not // do nothing for persistent instances log.trace ("SaveorUpdate () Persistent Instance");} else if (e! = NULL) {// ie. E.Status == deleted // If Obj has a corresponding ENTITYENTRY, that is, OBJ is already Po, and the status is deleted, then execute the delete operation log.trace ("saveorupdate () deleted Instance "); save (obj);} else {

// the object is transient Boolean isUnsaved = interceptor.isUnsaved (object); // interceptor is configurable, default Configratiron, return null ClassPersister persister = getPersister (object); // get the obj Persister Class mapping information if (isUnsaved == NULL) {// use unsaved-value

IF (Persister.isunsaved (Object)) / / Refer to AbstractTentityPersister.isunsaved, if the OBJ's IDentifier is empty, return True, otherwise, if the version of Version Property is empty, return true, otherwise return false {log.trace ("SaveorUpdate () unsaved instance "); save (obj);} else {// If the OBJ is still in the transient state, OBJ has a corresponding record in the database, then DoupDate Serializable ID = Persister.GetIdentifier (Object); if (log. iStraceNabled ()) log.trace ("SaveorUpdate () Previously Saved Instance With ID:" ID); Doupdate (Object, ID, Persister);

} Else {if (isUnsaved.booleanValue ()) {log.trace ( "saveOrUpdate () unsaved instance"); save (obj);} else {log.trace ( "saveOrUpdate () previously saved instance"); doUpdate (object , Persister.getiDentifier (Object), persister);}} 2.Session Impl.save

Public serializable save (object obj) throws hibernateException {

IF (obj == null) throw new nullpointersRext ("Attempted to Save Null);

Object object = unproxy (obj); // throws exception if uninitialize

ENTITYENTRY E = GetEntry (Object); if (e! = Null) // If there is a PO {if (E.STATUS == DELETED) {// if the PO status is deleted, Flush ForceFlush (e);} else {log.trace ("Object Already Associated with session); // Returns the ID of the PO, nothing to return Return E.ID;}}

Serializable id = saveWithGeneratedIdentifier (object, Cascades.ACTION_SAVE_UPDATE, null); // id might be generated by SQL insert reassociateProxy (obj, id); // TODO:? Move into saveWithGeneratedIdentifier () return id;

}

3.Session Impl.savewithGeneratedIdIndifier

private Serializable saveWithGeneratedIdentifier (Object object, Cascades.CascadingAction action, Object anything) throws HibernateException {ClassPersister persister = getPersister (object); try {Serializable id = persister.getIdentifierGenerator () .generate (this, object); // generated identity of obj If the id is assigned, then directly returns Obj's Identity, if it is Native, then generate ID according to the characteristics of the underlying database

if (id == null) {throw new IdentifierGenerationException ( "null id generated for:" object.getClass ());} {! return getIdentifier (object); // yick} else if (id == IdentifierGeneratorFactory.SHORT_CIRCUIT_INDICATOR) else if (id == IdentifierGeneratorFactory.IDENTITY_COLUMN_INDICATOR) {return doSave (object, null, persister, true, action, anything);} else {if (log.isDebugEnabled ()) log.debug ( "generated identifier:" id) Return DOSAVE (Object, ID, Persister, False, Action, Anything);}} catch (SQLException SQLE) {Throw new JDBCEXCEPTION ("Could Not Save Object", SQLE);}} 4.Session Impl.DOSAVE // Hibernate When INSERT is executed, INSERT SQL will generally not immediately execute the ID, unless you use the Identity mechanism to generate the ID, otherwise, INSERT SQL will only be executed when it is postponed to session.flush, will first generate the ID (using Sequence et al) Mechanism, as long as it is not an Identity mechanism), then put the Insert SQL plan in Insertions This queue, when Flush is executed, execute INSERT SQL, but it is necessary to note that when INSERT is used, when INDENTITY mechanism generates ID of Obj, Before inserting OBJ, Hibernate executes all INSERT SQL in the Insertions queue, why do you need this, unknown.

private Serializable doSave (final Object object, Key key, final ClassPersister persister, final boolean replicate, final boolean useIdentityColumn, final Cascades.CascadingAction cascadeAction, final Object anything) throws HibernateException {

IF (Persister.ImplementsValidatable ()) ((Validatable) Object) .validate (); // Verify OBJ's legitimacy

Serializable ID; if (useidentityColumn) {// If it is the ID generated by the Identity mechanism, then execute all the existing Insert SQL of the Session Insert queue, what is necessary? ID = null; executeinserts ();} else {ID = key.getidentifier ();

// put a placeholder in Entries, So We don't recurse back and try to save () The // Same Object Again. Questions: SHOULD THIS BE DONE BEFORE ONSAVE () IS CALLED? // LIKEWISE, SHOULD IT BE DONE BEFORE OnUpdate ()? Addentry (Object, Saving, Null, ID, Null, Lockmode.write, Useident Retention; // Okay if id is null here // cascade-save to man-to-one before the parent IS Saved // Take the father (primary table data) before processing the son (from watch data); try {cascades.cascade (this, persist, object, cascadeaction, cascades.cascade_before_insert_after_delete, annhening);} finally {cascading -;

Object [] value = personister.getPropertyValues ​​(object); type [] types = persister.getpropertytypes ();

Boolean substitude = false; if (! replicate) {

Substitution = interceptor.onsave (Object, ID, VALUES, PERSISTER.GETPROPERTYNAMES (), TYPES);

// keep the existing version number in the case of replicate if (persister.isVersioned ()) {substitute = Versioning.seedVersion (values, persister.getVersionProperty (), persister.getVersionType ()) || substitute;}!}

if (persister.hasCollections ()) {// TODO: make OnReplicateVisitor extend WrapVisitor if (replicate) {OnReplicateVisitor visitor = new OnReplicateVisitor (this, id); visitor.processValues ​​(values, types);} WrapVisitor visitor = new WrapVisitor (this ); // substitutes into values ​​by side-effect visitor.processValues ​​(Values, Types); Substitution = Substitution || Visitor.issubstitudeRequired ();}

IF (Substitution) Persister.SetPropertyValues ​​(Object, VALUES);

TypeFactory.deepCopy (values, types, persister.getPropertyUpdateability (), values); nullifyTransientReferences (values, types, useIdentityColumn, object); checkNullability (values, persister, false); if (useIdentityColumn) {// If identity is generating mechanism The ID, then you will not wait until Flush, you will insert the data because you want to return the ID, which is only available to INSERT if you want to return the ID. ScheduledIdentityInsertion insert = new ScheduledIdentityInsertion (values, object, persister, this); insert.execute (); executions.add (insert); id = insert.getGeneratedId (); persister.setIdentifier (object, id); key = new Key ( ID, persister; Checkuniqueness (key, object);

Object version = Versioning.getVersion (values, persister); addEntity (key, object); addEntry (object, LOADED, values, id, version, LockMode.WRITE, useIdentityColumn, persister, replicate); nonExists.remove (key);

IF (! users) {INSERTIONS.ADD (New ScheduledInsertion (ID, Values, Object, Persister, This);

// cascade-save to collections AFTER the collection owner was saved // father has been processed, the process where the son cascading ; try {Cascades.cascade (this, persister, object, cascadeAction, Cascades.CASCADE_AFTER_INSERT_BEFORE_DELETE, anything);} finally {cascading -;

Return ID;

}

5. SessionImpl.doupdatemutable Private Void Doupdatemutable (Object Object, Serializable ID, ClassPersister Persister) throws hibernateException {

IF (log.isticraceenabled ()) log.trace ("Updating" MessageHelper.infostring (Persister, ID));

Key Key = New key (id, person); checkuniqueason (key, object); // Check if the Object has the same one of the corresponding ID in Session, if there is, throw an exception

IF ("" ",") {log.debug ("Calling OnUpdate ()"); if ((Lifecycle) Object) .onupdate (this)) {// do callback log.debug ("Update Vetoed by Onupdate ) ")"); Reassociate (Object, ID, Persister); return;}} // this is a transient Object with existing Persistent State Not loaded by the session

New onupdatevisitor (this, id) .process (Object, Persister);

Addentity (Key, Object); // Incorporate Obj into session management, Transient Obj becomes PO Addentry (Object, Loaded, Null, ID, PERSISTER.GETVERSION (Object), LockMode.none, True, Persister, False ;

} Stage Summary: When executing Save or Update, there is a design principle that try to delay the time of the truly SQL to session.flush, but this also results in a problem, abnormal capture, When you invoke session.save or session.update, many times have not really executed SQL (will be in some time to perform Flush, the specific reference I have the official information of the notes in DOSAVE and the official information of Hibernate), of course, there will be no SQL exceptions thrown, if you try to capture exceptions at this time, it is invalid. This I used to make a simple discussion with AppFuse author Matt (Appfuse has a useerexistexception custom exception attempt to do Save or Update Out, pay attention to the appfuse1.6 to appfuse1.7 has a place to make changes, add geternalNateTemplate (). Flush (); this line code, so after each execution of save or update, immediately after each execution Save or Update Flush, immediately perform SQL, which can capture the SQL exception, thus throwing its own defined UseRexistexception, although AppFuse1.7 is modified in this way, still cannot catch this Usexistexception, because other reasons, solution It is this problem that will be changed from Extends RuntimeException from Extends RuntimeException, I will involve this issue in the future.

转载请注明原文地址:https://www.9cbs.com/read-68774.html

New Post(0)