Я вынужден задать свой вопрос на этом форуме, потратив около 8 часов, поиск по всему Интернету (включая SO), безрезультатно. Мой вопрос связан с JPA @Version field doesn't get incremented, но есть некоторые отличия.JPA 2.0 колонка @Version не получает приращение
Моя настройка: Java, JPA 2.0, DataNucleus 3.1.3, SDK приложения Google App Engine 1.9.17.
У меня есть модели данных, пользователь, который имеет поле с аннотацией @version следующим образом:
import javax.persistence.Table;
import javax.persistence.Version;
import org.datanucleus.api.jpa.annotations.Extension;
@Entity(name="User")
@Table(name="User")
public class User
implements Serializable {
private static final long serialVersionUID = -6706180854431454626L;
public User() {
}
@Id
@Column (name="USER_IDEN_PK",nullable=false)
....
....
@Basic (fetch = FetchType.EAGER)
@Column (name="USER_LAST_LOGOUT_TIMESTAMP",nullable=false)
private Long userLastLogoutTimestamp = null;
@Version
private Integer version;
public void setUserLastLogoutTimestamp(Long userLastLogoutTimestamp) {
this.userLastLogoutTimestamp = userLastLogoutTimestamp;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
Ниже приведен код, в котором объект пользователя обновляется. Параметр paramUser - это обновленный пользовательский объект, который должен сохраняться в хранилище данных с высокой репликацией Google App Engine.
public synchronized User updateUser (User paramUser)
throws Exception {
User existingUser = null;
existingUser = getUserByUserIden(paramUser.getUserIden());
logger.info("exst ver = " + existingUser.getVersion().intValue());
logger.info("param ver = " + paramUser.getVersion().intValue());
if(null != existingUser) {
modifiedUser = tu.getEM().merge(paramUser);
tu.getEM().flush();
}
logger.info("new ver = " + modifiedUser.getVersion().intValue());
return modifiedUser;
}
Вот что происходит:
- Первоначально поле «версия» имеет значение = 1. объект пользователя считывается из базы данных и отображаются на экране.
- Некоторые атрибуты настоящего Пользовательского объекта изменены.
- Попытка сохранить этот объект .
- «paramUser» имеет все немодифицированные, а также измененные поля .
- Код сначала «нахожу» сущность, и, согласно моему ожиданию , я получаю «1», напечатанный против «exst ver».
- Затем код печатает «1» против «param ver», что тоже соответствует моим ожиданиям, потому что я НЕ должен изменять это значение.
- Код, затем «слияние» с объектом «paramUser». Этот метод возвращает обновленный объект пользователя, который я сохраняю в «modifiedUser».
- Наконец, я очищаю диспетчер сущностей.
Вот вопрос: против «новой веры» я все еще получаю «1», тогда как я ожидал, что получу «2». Даже в базовом хранилище данных GAE значение «версии» остается «1».
Что мне нужно сделать, чтобы сделать хранилище данных JPA/DataNucleus/GAE/High-Replication увеличивающим поле «версия» на 1, когда я называю API «слияния»?
Любая помощь/идеи/предложения будут высоко оценены.
Вот лог:
2015-07-08 21:57:33.147
com.applix.imedipro.serverapp.controller.UserController update: paramJSONUser = {"userIden":"someUserIden","userPassword":"someUserPassword","userName":"someUserName","userMobile":2222222222,"userStreet":"someUserStreet","userArea":"someUserArea","userTown":"someUserTown","userDistrict":"someUserDistrict","userState":"someUserState","userCountry":"someUserCountry","userListOfRoleNames":["SuperUser"],"userLastLoginTimestamp":1436372833064,"userLastLogoutTimestamp":0,"version":1}
I 2015-07-08 21:57:33.147
com.applix.imedipro.serverapp.dao.DaoUser <init>: This object is [email protected]
D 2015-07-08 21:57:33.148
org.datanucleus.ObjectManagerImpl initialiseLevel1Cache: Level 1 Cache of type "soft" initialised
D 2015-07-08 21:57:33.148
org.datanucleus.ObjectManagerImpl <init>: Object Manager "[email protected]" opened for datastore "[email protected]" with txn="[email protected]"
D 2015-07-08 21:57:33.148
org.datanucleus.transaction.Transaction <init>: Transaction created [DataNucleus Transaction, ID=Xid=
D 2015-07-08 21:57:33.148
org.datanucleus.TransactionImpl internalBegin: Transaction begun for ObjectManager [email protected] (optimistic=true)
D 2015-07-08 21:57:33.148
com.google.appengine.datanucleus.DatastoreConnectionFactoryImpl$DatastoreManagedConnection <init>: Created ManagedConnection using DatastoreService = [email protected]
D 2015-07-08 21:57:33.148
org.datanucleus.transaction.Transaction enlistResource: Running enlist operation on resource: [email protected], error code TMNOFLAGS and transaction: [DataNucleus Transaction, ID=Xid=
D 2015-07-08 21:57:33.151
com.google.appengine.datanucleus.DatastoreXAResource start: Started datastore transaction: 4261602282148180867
D 2015-07-08 21:57:33.152
org.datanucleus.store.connection.ConnectionManagerImpl allocateConnection: Connection added to the pool : com.google.appengine.datanu[email protected]4445f6 for [email protected] in factory=ConnectionFactory:tx[[email protected]842f22]
D 2015-07-08 21:57:33.157
org.datanucleus.ObjectManagerImpl getObjectFromLevel1Cache: Object with id "com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM" not found in Level 1 cache [cache size = 0]
D 2015-07-08 21:57:33.157
org.datanucleus.ObjectManagerImpl putObjectIntoLevel1Cache: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") added to Level 1 cache (loadedFlags="[NNNNYNNNNNNNNNN]")
D 2015-07-08 21:57:33.158
org.datanucleus.state.JDOStateManager wrapSCOField: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") is having the value in field "userListOfRoleNames" replaced by a SCO wrapper
D 2015-07-08 21:57:33.158
org.datanucleus.store.types.sco.simple.ArrayList initialise: Created SCO wrapper for object "[email protected]" field "userListOfRoleNames" with 1 entries, using options="cached,allowNulls"
D 2015-07-08 21:57:33.158
org.datanucleus.ObjectManagerImpl enlistInTransaction: Object "[email protected]" (id="ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") enlisted in transactional cache
D 2015-07-08 21:57:33.158
org.datanucleus.ObjectManagerImpl getObjectFromLevel2Cache: Object with id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM" taken from Level 2 cache (fields="[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]", version="") - represented as "[email protected]"
D 2015-07-08 21:57:33.158
org.datanucleus.state.LifeCycleState changeState: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") has a lifecycle change : "P_CLEAN"->"P_NONTRANS"
D 2015-07-08 21:57:33.158
org.datanucleus.ObjectManagerImpl evictFromTransaction: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") being evicted from transactional cache
D 2015-07-08 21:57:33.159
org.datanucleus.ObjectManagerImpl removeObjectFromLevel2Cache: Object with id="ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM" removed from Level 2 cache
D 2015-07-08 21:57:33.159
org.datanucleus.ObjectManagerImpl persistObjectInternal: Making object persistent : "[email protected]"
D 2015-07-08 21:57:33.159
org.datanucleus.ObjectManagerImpl enlistInTransaction: Object "[email protected]" (id="[email protected]") enlisted in transactional cache
D 2015-07-08 21:57:33.159
org.datanucleus.state.JDOStateManager makePersistent: Object "[email protected]" has been marked for persistence but its actual persistence to the datastore will be delayed due to use of optimistic transactions or "delayDatastoreOperationsUntilCommit"
D 2015-07-08 21:57:33.159
org.datanucleus.ObjectManagerImpl putObjectIntoLevel1Cache: Object "[email protected]" (id="[email protected]") added to Level 1 cache (loadedFlags="[YYYYYYYYYYYYYYY]")
D 2015-07-08 21:57:33.159
org.datanucleus.ObjectManagerImpl flushInternalWithOrdering: ObjectManager.internalFlush() process started using ordered flush - 1 dirty objects
I 2015-07-08 21:57:33.159
com.applix.imedipro.serverapp.dao.DaoUser updateUser: existing version = 1
I 2015-07-08 21:57:33.159
com.applix.imedipro.serverapp.dao.DaoUser updateUser: param version = 1
D 2015-07-08 21:57:33.160
org.datanucleus.store.connection.ConnectionManagerImpl allocateConnection: Connection found in the pool : com.google.appengine.datanu[email protected]4445f6 for [email protected] in factory=ConnectionFactory:tx[[email protected]842f22]
D 2015-07-08 21:57:33.160
org.datanucleus.store.connection.ConnectionManagerImpl allocateConnection: Connection found in the pool : com.google.appengine.datanu[email protected]4445f6 for [email protected] in factory=ConnectionFactory:tx[[email protected]842f22]
D 2015-07-08 21:57:33.160
org.datanucleus.store.connection.ConnectionManagerImpl allocateConnection: Connection found in the pool : com.google.appengine.datanu[email protected]4445f6 for [email protected] in factory=ConnectionFactory:tx[[email protected]842f22]
D 2015-07-08 21:57:33.160
org.datanucleus.store.connection.ConnectionManagerImpl allocateConnection: Connection found in the pool : com.google.appengine.datanu[email protected]4445f6 for [email protected] in factory=ConnectionFactory:tx[[email protected]842f22]
D 2015-07-08 21:57:33.160
org.datanucleus.store.connection.ConnectionManagerImpl allocateConnection: Connection found in the pool : com.google.appengine.datanu[email protected]4445f6 for [email protected] in factory=ConnectionFactory:tx[[email protected]842f22]
D 2015-07-08 21:57:33.160
com.google.appengine.datanucleus.EntityUtils putEntitiesIntoDatastore: Putting entity of kind User with key User("someUserIden") as {USER_TOWN[someUserTown], USER_AREA[someUserArea], USER_DISTRICT[someUserDistrict], VERSION[1], USER_Street[someUserStreet], USER_NAME[someUserName], USER_MOBILE[2222222222], userListOfRoleNames[[SuperUser]], USER_LAST_LOGOUT_TIMESTAMP[0], USER_COUNTRY[someUserCountry], USER_STATE[someUserState], USER_PASSWORD[someUserPassword], USER_LAST_LOGIN_TIMESTAMP[1436372833064], }
D 2015-07-08 21:57:33.164
org.datanucleus.ObjectManagerImpl replaceObjectId: Object "[email protected]" (id="org.datanucleus.identity.Iden[email protected]") being changed to be referenced by id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM" in Level 1 cache
D 2015-07-08 21:57:33.164
org.datanucleus.ObjectManagerImpl replaceObjectId: Object "[email protected]" (id="[email protected]") enlisted in transactional cache is now enlisted using id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM"
D 2015-07-08 21:57:33.164
org.datanucleus.store.connection.ConnectionManagerImpl allocateConnection: Connection found in the pool : com.google.appengine.datanu[email protected]4445f6 for [email protected] in factory=ConnectionFactory:tx[[email protected]842f22]
D 2015-07-08 21:57:33.164
org.datanucleus.state.JDOStateManager wrapSCOField: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") is having the value in field "userListOfRoleNames" replaced by a SCO wrapper
D 2015-07-08 21:57:33.164
org.datanucleus.store.types.sco.simple.ArrayList initialise: Created SCO wrapper for object "[email protected]" field "userListOfRoleNames" with 1 entries, using options="cached,allowNulls"
D 2015-07-08 21:57:33.164
org.datanucleus.ObjectManagerImpl flushInternal: ObjectManager.internalFlush() process finished
I 2015-07-08 21:57:33.164
com.applix.imedipro.serverapp.dao.DaoUser updateUser: new version = 1
I 2015-07-08 21:57:33.164
com.applix.transactions.TranxUtility postTransaction: EM is open
D 2015-07-08 21:57:33.165
org.datanucleus.TransactionImpl internalPreCommit: Transaction committing for ObjectManager [email protected]
D 2015-07-08 21:57:33.165
org.datanucleus.ObjectManagerImpl flushInternalWithOrdering: ObjectManager.internalFlush() process started using ordered flush - 0 dirty objects
D 2015-07-08 21:57:33.165
org.datanucleus.ObjectManagerImpl flushInternal: ObjectManager.internalFlush() process finished
D 2015-07-08 21:57:33.165
org.datanucleus.ObjectManagerImpl putObjectsIntoLevel2Cache: Object "[email protected]" (id="ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") added to Level 2 cache (fields="[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]", version="1")
D 2015-07-08 21:57:33.165
org.datanucleus.transaction.Transaction commit: Committing [DataNucleus Transaction, ID=Xid=
I 2015-07-08 21:57:33.165
com.applix.transactions.TranxUtility postTransaction: transaction is active
I 2015-07-08 21:57:33.165
com.applix.transactions.TranxUtility postTransaction: About to start committing the transaction
D 2015-07-08 21:57:33.190
com.google.appengine.datanucleus.DatastoreXAResource commit: Committed datastore transaction: 4261602282148180867
D 2015-07-08 21:57:33.191
org.datanucleus.store.connection.ConnectionManagerImpl$1 managedConnectionPostClose: Connection removed from the pool : com.google.appengine.datanu[email protected]4445f6 for [email protected] in factory=ConnectionFactory:tx[[email protected]842f22]
D 2015-07-08 21:57:33.191
org.datanucleus.state.LifeCycleState changeState: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") has a lifecycle change : "P_NEW"->"P_NONTRANS"
D 2015-07-08 21:57:33.191
org.datanucleus.ObjectManagerImpl evictFromTransaction: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") being evicted from transactional cache
D 2015-07-08 21:57:33.191
org.datanucleus.TransactionImpl commit: Transaction committed in 26 ms
D 2015-07-08 21:57:33.191
org.datanucleus.state.JDOStateManager detach: Detaching object from persistence : "[email protected]" (depth=0)
I 2015-07-08 21:57:33.191
com.applix.transactions.TranxUtility postTransaction: Transaction committed
D 2015-07-08 21:57:33.192
org.datanucleus.state.JDOStateManager unwrapSCOField: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") is having the SCO wrapper in field "userListOfRoleNames" replaced by the unwrapped value
D 2015-07-08 21:57:33.192
org.datanucleus.state.LifeCycleState changeState: Object "[email protected]" (id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM") has a lifecycle change : "P_NONTRANS"->"DETACHED_CLEAN"
D 2015-07-08 21:57:33.192
org.datanucleus.state.JDOStateManager disconnect: Disconnecting [email protected] from StateManager[[email protected], lifecycle=DETACHED_CLEAN]
D 2015-07-08 21:57:33.192
org.datanucleus.ObjectManagerImpl removeObjectFromLevel1Cache: Object with id="com.applix.imedipro.entity.User:ahJzfmF0LWltZWRpcHJvLWJldGFyFwsSBFVzZXIiDW5pbWVzaF9wYXJtYXIM" being removed from Level 1 cache [current cache size = 1]
D 2015-07-08 21:57:33.192
org.datanucleus.ObjectManagerImpl disconnectObjectProvidersFromCache: Level 1 Cache cleared
D 2015-07-08 21:57:33.192
org.datanucleus.ObjectManagerImpl close: Object Manager "[email protected]" closed
I 2015-07-08 21:57:33.192
com.applix.transactions.TranxUtility postTransaction: Entity Manager cleared
и журнал говорит? –
новый журнал с .level = ALL добавлен. Извините за форматирование. –
Журнал обрезается по ширине столбца. Также укажите WHERE в этом журнале - это вызванное слияние, потому что вы можете легко выгрузить оператор в журнал непосредственно перед слиянием и, следовательно, посмотреть, какие утверждения относятся к вашему коду персистентности. И посмотрите состояние объекта, в котором вы проходите (который также будет регистрироваться). Возможно, он не отсоединен ... –