and couldn't find it anywhere in a Ctrl+C / Ctrl+V form.
How to implement optimistic locking under iBatis when there is no standard support for it.
It's quite simple. Implement it by your self.
- implement custom OptimisticLockException or reuse the one from JPA package: javax.persistence
- add new db field named 'version' into entity's table. it should be numerical non-null field with default value defined as 1
- add new field into Entity's class: int version
- Update DAO interface to throw OptimisticLockException (so anybody using this DAO can change his code accordingly)
public interface EntityDao { void createEntity(Entity entity); Entity selectEntryById(Long id); void updateEntity(Entity entity) throws OptimisticLockException; void deleteEntity(Entity entity); }
- Update DAO class to process version fields
public class EntityDaoImpl extends SqlMapClientDaoSupport implements EntityDao { @Override public void createEntity(final Entity entity) { getSqlMapClientTemplate().insert("insertEntity", entity); entity.setVersion(1); } @Override public Entity selectEntryById(final Long id) { return (Entity) getSqlMapClientTemplate().queryForObject("findEntityById", id); } @Override public void updateEntity(final Entity entity) throws OptimisticLockException { final int oldVersion = entity.getVersion(); final int newVersion = oldVersion + 1; final Map<String, Object> params = new HashMap<String, Object>(); params.put("entity", entity); params.put("oldVersion", oldVersion); params.put("newVersion", newVersion); int updateCount = getSqlMapClientTemplate().update("updateEntity", params); if (updateCount == 0) { throw new OptimisticLockException("trying to update database with obsolete Entity"); } entity.setVersion(newVersion); } @Override public void deleteEntity(Entity entity) { getSqlMapClientTemplate().delete("deleteEntity", entity); } }
- Update statements file
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd"> <sqlMap> <typeAlias alias="Entity" type="yourPackage.domain.Entity"/> <resultMap id="EntityMap" class="Entity"> <result column="id" property="id"/> <result column="value" property="value"/> <result column="version" property="version"/> </resultMap> <insert id="insertEntity" parameterClass="Entity"> INSERT INTO entity (id, value, version) VALUES (#id#, #value#, 1) </insert> <select id="findEntityById" parameterClass="java.lang.Long" resultClass="Entity" resultMap="EntityMap"> SELECT id, value, version FROM entity WHERE id=#value# </select> <update id="updateEntity" parameterClass="java.util.Map"> UPDATE entity SET value=#entity.value# version=#newVersion# WHERE id=#entity.id# AND version=#oldVersion# </update> <delete id="deleteEntity" parameterClass="Entity"> DELETE FROM entity WHERE id=#id# </delete> </sqlMap>