Main | Project Page | Download |
Grateful to for hosting this project |
1. What's Daozero? How it help me?
3. Changed from a typical iBatis DAO bean to daozero bean
5. Some limitation from current daozero release
6. How to deal with those iBatis features that current daozero doesn't support
8. For other features & futher usage
9. Why it's recommended? Compare daozero with code generation tools
If you have any suggestion or problem, contact me (suntoech@sh163.net)Dao-zero bean invokes iBatis mapped statement whose name is same as method name of DAO interface( or abstract class). Both count and occurrence index of mapped statement should be keeped same as method arguments for current implementation(If the parameter is one Java bean, we could ignore this convention). It's a factory bean which implements org.springframework.beans.factory.FactoryBean and creates proxy object that implements DAO interface( or abstract class) for those beans need it, which typically are service beans. The proxy object takes repsonsibilities of constructing parameter map from invocation arguments and pass the parameter map to iBatis API, such as queryForObject(), queryForList(), etc. It is smart enough to know what you want is a java.lang.List or a ordinary java bean(POJO). But by current release, it doen't support queryForMap() yet.
Proxy object is created from different way depends on whether or not DAO type required is interface. If it is interface, proxy is created using standard JDK proxy(java.lang.reflect.Proxy), else, created using CGLIB enhancer(net.sf.cglib.proxy.Enhancer). For a CGLIB proxy, it will try to implement all public abstract methods for the abstract DAO class proxied. And, dao-zero provides some additional features, for example, to convert java.util.List returned by iBatis to POJO array or java.util.Iterator.
In fact, I hacked iBatis, have to cast some iBatis interface to its internal implementation class, because I cannot found how to get parameter map's meta data by iBatis's API. (So sorry for the bad smell )
*I assume you have experience on taking Spring's iBatis support as persistence tier solution.
Supposed we have a table named "account":
--HSQLDB SQL
create table account (
userid varchar(80) not null,
email varchar(80) not null,
constraint pk_account primary key (userid)
);.
Accordingly, an entity class with properties "userId" and "email":
public class Account implements Serializable {
private String userid;
private String email;
public String getUserId() { return this.userid; }
public void setUserId(String s) { this.userid=s; }
public String getEmail() { return this.email; }
public void setEmail(String s) { this.email=s; }
}.
And the DAO interface is:
public interface AccountDao {
Account getAccountByUserId(String userId);
void updateAccount(Account account);
List getUsernameList();
}.
import org.springframework.org.ibatis.support.SqlMapClientDaoSupport;
public class AccountDaoImpl
extends SqlMapClientDaoSupport
implements AccountDao {
public Account getAccountByUserIdAndEmail(String userId, String email) {
Map params = new HashMap();
params.put( "userId", userId );
params.put( "email", email );
return getTemplate().queryForObject( "getAccountByUserIdAndEmail",
params );
}
/* Or, another way of getAccount...
public Account getAccountByUserIdAndEmail(Account conditions) {
return getTemplate().queryForObject( "getAccountByUserIdAndEmail", conditions );
}*/
public int updateAccount(Account account) {
return getTemplate().update( "updateAccount", account
);
}
public List getUsernameList();
return getTemplate().queryForList( "getUsernameList",
null );
}
<select id="getAccountByUserIdAndEmail" resultClass="Account">
select * from account where userid=#userId# AND email=#email#
</select>
<select id="getUsernameList" resultClass="java.lang.String">
select userid from account
</select>
<update id="updateAccount">
update account set email = #email# where userid=#userId#
</update>
<bean id="accountDao" class="AccountDaoImpl">
<property name="sqlMapClient" ref="sqlMapClient"/>
</bean>
Now let us see what will happen with daozero: the first thing is to delete that AccountDaoImpl.java, and change Spring bean definition to:
<bean id="accountDao" class="daozero.ibatis.Dao">
<property name="sqlMapClient" ref="sqlMapClient"/>
<property name="targetType" value="AccountDao"
/> <!-- interface -->
</bean>
In some cases that you hope daozero not to override all your methods implementation, that means daozero should work with abstract implementation. The solution is to set bean's "targetType" property with an abstract class implemented DAO interface. For above sample, we reserve AccountDaoImpl.java, but maybe insert some additional operation into method "updateAccount(Account)":
public abstract
class AccountDaoImpl
extends SqlMapClientDaoSupport
implements AccountDao {
public abstract int __updateAccount(Account account);
public int updateAccount(Account account) {
// Insert additional operation code here
return __updateAccount(account);
}
}
The last place we should modifiy is SQL mapped statement's name to let daozero build relation between AccountDaoImpl.__updateAccount() and statement "__updateAccount":
<select id="getAccountByUserIdAndEmail"
resultClass="Account">
select * from account where userid=#userId# AND email=#email#
</select>
<select id="getUsernameList" resultClass="java.lang.String">
select userid from account
</select>
<update id="__updateAccount">
update account set email = #email# where userid=#userId#
</update>