注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

断尘居

温柔的男人像海洋。

 
 
 
 
 

日志

 
 

ibatis 开发指南(四)  

2010-09-17 03:35:51|  分类: SSH |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 一元判定
一元判定是针对属性值本身的判定,如属性是否为NULL,是否为空值等。
上面示例中isNotEmpty 就是典型的一元判定。
一元判定节点有:
节点名描述
<isPropertyAvailable> 参数类中是否提供了此属性
<isNotPropertyAvailable> 与<isPropertyAvailable> 相反
<isNull> 属性值是否为NULL 
<isNotNull> 与<isNull> 相反
<isEmpty> 如果属性为Collection 或者String,其size 是否<1, 
如果非以上两种类型,则通过
String.valueOf( 属性值) 
获得其String 类型的值后,判断其size 是否<1 
<isNotEmpty> 与<isEmpty> 相反。
. 二元判定
二元判定有两个判定参数, 一是属性名,而是判定值,如
<isGreaterThan prepend="AND" property="age"
compareValue="18">
(age=#age#) 
</isGreaterThan>
其中,property="age" 指定了属性名”age”,compareValue=”18”指明
了判定值为”18”。
上面判定节点isGreaterThan 对应的语义是:如果age 属性大于
18(compareValue),则在SQL 中加入(age=#age#) 条件。
二元判定节点有:
节点名属性值与的关系
相等。
不等。
大于
大于等于
小于
小于等于
compareValues 
<isEqual> 
<isNotEqual> 
<isGreaterThan> 
<isGreaterEqual> 
<isLessThan> 
<isLessEqual> 

事务管理
基于JDBC 的事务管理机制
ibatis 提供了自动化的JDBC 事务管理机制。
对于传统JDBC Connection 而言,我们获取Connection 实例之后,需要调用
Connection.setAutoCommit 设定事务提交模式。
在AutoCommit 为true 的情况下,JDBC 会对我们的操作进行自动提交,此时,每
个JDBC 操作都是一个独立的任务。
为了实现整体事务的原子性,我们需要将AutoCommit 设为false ,并结合
Connection.commit/rollback 方法进行事务的提交/回滚操作。
ibatis 的所谓“自动化的事务提交机制”,即ibatis 会根据当前的调用环境,自动
判断操作是否需要自动提交。
如果代码没有显式的调用SqlMapClient.startTransaction() 方法,则ibatis 
会将当前的数据库操作视为自动提交模式(AutoCommit=true),如:
sqlMap = xmlBuilder.buildSqlMap(reader); 
User user = new User(); 
user.setId(new Integer(1)); 
user.setName("Erica"); 
user.setSex(new Integer(0)); 
sqlMap.update("User.updateUser", user); 
User user2 = new User(); 
user2.setId(new Integer(2)); 
user2.setName("Kevin"); 
user2.setSex(new Integer(1)); 
sqlMap.update("User.updateUser", user2); 
在执行的时候,会自动判定运行环境,这里操作sqlMap.update ibatis 当前的update 
并没有相对应的事务范围(startTransaction 和endTransaction 代码块),于是
ibatis 将其作为一个单独的事务,并自动提交。对于上面的代码,update 执行了两次, 
与其相对应,事务也提交了两次(即每个update 操作为一个单独的事务)。
不过,值得注意的是,这里的所谓“自动判定”,可能有些误导,ibatis 并没有去
检查当前是否已经有事务开启,从而判断当前数据库连接是否设定为自动提交。
实际上,在执行update 语句时,sqlMap 会检查当前的Session 是否已经关联了某个
数据库连接,如果没有,则取一个数据库连接,将其AutoCommit 属性设为true ,然后
执行update 操作,执行完之后又将这个连接释放。这样,上面两次update 操作实际上
先后获取了两个数据库连接,而不是我们通常所认为的两次update 操作都基于同一个
JDBC Connection 。这点在开发时需特别注意。
对于多条SQL 组合而成的一个JDBC 事务操作而言,必须使用
startTransaction、commit 和endTransaction 操作以实现整体事务的原子性。

如:
try{ 
sqlMap = xmlBuilder.buildSqlMap(reader); 
sqlMap.startTransaction(); 
User user = new User(); 
user.setId(new Integer(1)); 
user.setName("Erica"); 
user.setSex(new Integer(0)); 
sqlMap.update("User.updateUser", user); 
User user2 = new User(); 
user2.setId(new Integer(2)); 
user2.setName("Kevin"); 
user2.setSex(new Integer(1)); 
sqlMap.update("User.updateUser", user2); 
sqlMap.commitTransaction(); 
}finally{ 
sqlMap.endTransaction(); 

如果user1 或者user2 的update 操作失败,整个事务就会在endTransaction 时回
滚,从而保证了两次update 操作的原子性。
基于JTA 的事务管理机制
JTA 提供了跨数据库连接(或其他JTA 资源)的事务管理能力。这一点是与JDBC 
Transaction 最大的差异。
JDBC 事务由Connnection 管理,也就是说,事务管理实际上是在JDBC Connection 
中实现。事务周期限于Connection 的生命周期。同样,对于基于JDBC 的ibatis 事务管
理机制而言,事务管理在SqlMapClient 所依托的JDBC Connection 中实现,事务周期限
于SqlMapClient 的生命周期。
JTA 事务管理则由JTA 容器实现,JTA 容器对当前加入事务的众多Connection 进
行调度,实现其事务性要求。JTA 的事务周期可横跨多个JDBC Connection 生命周期。
同样,对于基于JTA 事务的ibatis 而言,JTA 事务横跨可横跨多个SqlMapClient 。
下面这幅图形象的说明了这个问题:

为了在ibatis 中使用JTA 事务管理,我们需要在配置文件中加以设定: 
<transactionManager type="JTA"> 
……
</transactionManager>
在实际开发中,我们可能需要面对分布式事务的处理,如系统范围内包含了多个数据库, 
也许还引入了JMS 上的事务管理(这在EAI 系统实现中非常常见)。我们就需要引入JTA 
以实现系统范围内的全局事务,如下面示例中,我们同时将user 对象更新到两个不同的数
据库: 
User user = new User(); 
user.setId(new Integer(1)); 
user.setName("Erica"); 
user.setSex(new Integer(0)); 
sqlMap1 = xmlBuilder.buildSqlMap(db1Config); 
sqlMap2 = xmlBuilder.buildSqlMap(db2Config); 
try{ 
sqlMap1.startTransaction(); 
sqlMap1.update("User.updateUser", user); 
sqlMap2.update("User.updateUser", user); 
sqlMap1. commitTransaction();
}finally{ 
sqlMap1.endTransaction(); 

上面的代码中,两个针对不同数据库的实例,在同一个事务中SqlMapClient JTA 
对user 对象所对应的数据库记录进行更新。外层的sqlMap1 启动了一个全局事务,此
事务将涵盖本线程内commitTransaction 之前的所有数据库操作。只要其间发生了

异常,则整个事务都将被回滚。
外部事务管理
基于JTA 的事务管理还有另外一个特殊情况,就是利用外部事务管理机制。
对于外部事务管理,我们需要在配置文件中进行如下设定: 
<transactionManager type="EXTERNAL"> 
……
</transactionManager>
下面是一个外部事务管理的典型示例: 
UserTransaction tx = new InitialContext().lookup(“……”); 
……
sqlMap1 = xmlBuilder.buildSqlMap(db1Config); 
sqlMap2 = xmlBuilder.buildSqlMap(db2Config); 
sqlMap1.update("User.updateUser", user); 
sqlMap2.update("User.updateUser", user); 
……
tx.commit(); 
此时,我们借助实例启动了一个全局事务。之后的操作JTA UserTransaction ibatis 
( sqlMap1.update 和sqlMap2.update)全部被包含在此全局事务之中,当
UserTransaction 提交的时候,
ibatis 操作被包含在事务中提交,反之,如果UserTransaction 
回滚,那么其间的ibatis 操作也将作为事务的一部分被回滚。这样,我们就实现了ibatis 
外部的事务控制。
另一种外部事务管理方式是借助EJB 容器,通过EJB 的部署配置,我们可以指定
EJB 方法的事务性
下面是一个Session Bean 的doUpdate 方法,它的事务属性被申明为“Required”, 
EJB 容器将自动维护此方法执行过程中的事务: 
/**

@ejb.interface-method

view-type="remote"
*

@ejb.transaction type = "Required"
**/
public void doUpdate(){
//EJB环境中,通过部署配置即可实现事务申明,而无需显式调用事务
……
sqlMap1 = xmlBuilder.buildSqlMap(db1Config); 
sqlMap2 = xmlBuilder.buildSqlMap(db2Config); 
sqlMap1.update("User.updateUser", user); 
sqlMap2.update("User.updateUser", user); 
……
}//方法结束时,如果没有异常发生,则事务由EJB容器自动提交。
上面的示例中,ibatis 数据操作的事务管理将全部委托给EJB 容器管理,由EJB 
容器控制其事务调度。

在上面JTA 事务管理的例子中,为了保持清晰,我们省略了startTransaction 、
commitTransaction 和endTransaction 的编写,在这种情况下,调用ibatis 
的事务管理方法并非必须,不过在实际开发时,请酌情添加startTransaction 、
commitTransaction 和endTransaction 语句,这样可以获得更好的性能(如果
省略了startTransaction 、commitTransaction 和endTransaction 语句, 
ibatis 将为每个数据操作获取一个数据连接,就算引入了数据库连接池机制,这样的
无谓开销也应尽量避免,具体请参见JDBC 事务管理中的描述),并保持代码风格的统
一。
Cache 
在特定硬件基础上(同时假设系统不存在设计上的缺漏和糟糕低效的SQL 语句) 
Cache 往往是提升系统性能的最关键因素)。
相对Hibernate 等封装较为严密的ORM 实现而言(因为对数据对象的操作实现
了较为严密的封装,可以保证其作用范围内的缓存同步,而ibatis 提供的是半封闭
的封装实现,因此对缓存的操作难以做到完全的自动化同步)。
ibatis 的缓存机制使用必须特别谨慎。特别是flushOnExecute 的设定(见
“ibatis 配置”一节中的相关内容),需要考虑到所有可能引起实际数据与缓存数据
不符的操作。如本模块中其他Statement 对数据的更新,其他模块对数据的更新,甚
至第三方系统对数据的更新。否则,脏数据的出现将为系统的正常运行造成极大隐患。
如果不能完全确定数据更新操作的波及范围,建议避免Cache 的盲目使用。
结合cacheModel 来看: 
<cacheModel
id="product-cache"
type ="LRU"
readOnly="true"
serialize="false">
</cacheModel>
可以看到,Cache 有如下几个比较重要的属性: 
. readOnly 
. serialize 
. type 
readOnly 
readOnly 值的是缓存中的数据对象是否只读。这里的只读并不是意味着数据对象一
旦放入缓存中就无法再对数据进行修改。而是当数据对象发生变化的时候,如数据对
象的某个属性发生了变化,则此数据对象就将被从缓存中废除,下次需要重新从数据
库读取数据,构造新的数据对象。
而readOnly="false" 则意味着缓存中的数据对象可更新,如user 对象的name 
属性发生改变。
只读Cache 能提供更高的读取性能,但一旦数据发生改变,则效率降低。系统设计
时需根据系统的实际情况(数据发生更新的概率有多大)来决定Cache 的读写策略。

serialize 
如果需要全局的数据缓存,CacheModel 的serialize 属性必须被设为true 。否则数据
缓存只对当前Session(可简单理解为当前线程)有效,局部缓存对系统的整体性能提
升有限。
在serialize="true" 的情况下,如果有多个Session 同时从Cache 中读取某个
数据对象,Cache 将为每个Session 返回一个对象的复本,也就是说,每个Session 将
得到包含相同信息的不同对象实例。因而Session 可以对其从Cache 获得的数据进行
存取而无需担心多线程并发情况下的同步冲突。
Cache Type: 
与hibernate 类似,ibatis 通过缓冲接口的插件式实现,提供了多种Cache 的实现机
制可供选择: 
1. MEMORY 
2. LRU 
3. FIFO 
4. OSCACHE 
MEMORY 类型Cache 与WeakReference 
MEMORY 类型的Cache 实现,实际上是通过Java 对象引用进行。ibatis 中,其实现类
为com.ibatis.db.sqlmap.cache.memory.MemoryCacheController,MemoryCacheController 内部,
使用一个HashMap 来保存当前需要缓存的数据对象的引用。
这里需要注意的是Java2 中的三种对象引用关系: 
a SoftReference 
b WeakReference 
c PhantomReference 
传统的Java 对象引用, 如:
public void doSomeThing(){ 
User user = new User() 
……

当doSomeThing 方法结束时,user 对象的引用丢失,其所占的内存空间将由JVM 在下
次垃圾回收时收回。如果我们将user 对象的引用保存在一个全局的HashMap 中,如:
Map map = new HashMap(); 
public void doSomeThing(){ 
User user = new User(); 
map.put("user",user); 

此时,user 对象由于在map 中保存了引用,只要这个引用存在,那么JVM 永远也不会
收回user 对象所占用的内存。
这样的内存管理机制相信诸位都已经耳熟能详,在绝大多数情况下,这几乎是一种完美

的解决方案。但在某些情况下,却有些不便。如对于这里的Cache 而言,当user 对象使用
之后,我们希望保留其引用以供下次需要的时候可以重复使用,但又不希望这个引用长期保
存, 如果每个对象的引用都长期保存下去的话,那随着时间推移,有限的内存空间将立即被
这些数据所消耗殆尽。最好的方式,莫过于有一种引用方式,可以在对象没有被垃圾回收器
回收之前,依然能够访问此对象,当垃圾回收器启动时,如果此对象没有被其他对象所使用,
则按照常规对其进行回收。
SoftReference 、WeakReference 、PhantomReference 为上面的思路提供了有力支持。
这三种类型的引用都属于“非持续性引用”,也就是说,这种引用关系并非持续存在,
它们所代表的引用的生命周期与JVM 的运行密切相关,而非与传统意义上的引用一样依赖
于编码阶段的预先规划。
先看一个SoftReference 的例子: 
SoftReference ref; 
public void doSomeThing(){ 
User user = new User(); 
ref = new SoftReference(user); 

public void doAnotherThing(){ 
User user = (User)ref.get();//通过SoftReference 获得对象引用
System.out.println(user.getName()); 

假设我们先执行了doSomeThing 方法,产生了一个User 对象,并为其创建了一个
SoftReference 引用。
之后的某个时刻,我们调用了doAnotherThing 方法,并通过SoftReference 获取User 对
象的引用。
此时我们是否还能取得user 对象的引用?这要看JVM 的运行情况。对于SoftReference 
而言,只有当目前内存不足的情况下,JVM 在垃圾回收时才会收回其包含的引用(JVM 并
不是只有当内存不足时才启动垃圾回收机制, 何时进行垃圾回收取决于各版本JVM 的垃圾
回收策略。如某这垃圾回收策略为:当系统目前较为空闲, 且无效对象达到一定比率时启动
垃圾回收机制,此时的空余内存倒可能还比较充裕)。这里可能出现两种情况,即: 
. JVM 目前还未出现过因内存不足所引起的垃圾回收,user 对象的引用可以通过
SoftReference 从JVM Heap 中收回。
. JVM 已经因为内存不足启动了垃圾回收机制,SoftReference 所包含的user 对象的
引用被JVM 所废弃。此时ref.get 方法将返回一个空引用(null),对于上面
的代码而言,也就意味着这里可能抛出一个NullPointerException 。
WeakReference 比SoftReference 在引用的维持性上来看更加微弱。无需等到内存不足的
情况,只要JVM 启动了垃圾回收机制,那么WeakReference 所对应的对象就将被JVM 回收。

也就是说,相对SoftReference 而言,WeakReference 被JVM 回收的概率更大。
PhantomReference 比WeakReference 的引用维持性更弱。与WeakReference 和
SoftReference 不同,PhantomReference 所引用的对象几乎无法被回收重用。它指向的对象实
际上已经被JVM 销毁(finalize 方法已经被执行),只是暂时还没被垃圾回收器收回而已。
PhantomReference 主要用于辅助对象的销毁过程,在实际应用层研发中,几乎不会涉及。
MEMORY 类型的Cache 正是借助SoftReference 、WeakReference 以及通常意义上的Java 
Reference 实现了对象的缓存管理。
下面是一个典型的MEMORY 类型Cache 配置: 
<cacheModel id="user_cache" type="MEMORY"> 
<flushInterval hours="24"/> 
<flushOnExecute statement="updateUser"/> 
<property name="reference-type" value="WEAK" /> 
</cacheModel> 
其中flushInterval 指定了多长时间清除缓存,上例中指定每24 小时强行清空缓存
区的所有内容。
reference-type 属性可以有以下几种配置: 
1. STRONG 
即基于传统的Java 对象引用机制,除非对Cache 显式清空(如到了flushInterval 
设定的时间;执行了flushOnExecute 所指定的方法;或代码中对Cache 执行了清除
操作等),否则引用将被持续保留。
此类型的设定适用于缓存常用的数据对象, 或者当前系统内存非常充裕的情况。
2. SOFT 
基于SoftReference 的缓存实现,只有JVM 内存不足的时候,才会对缓冲池中的数
据对象进行回收。
此类型的设定适用于系统内存较为充裕,且系统并发量比较稳定的情况。
3. WEAK 
基于WeakReference 的缓存实现,当JVM 垃圾回收时,缓存中的数据对象将被JVM 
收回。
一般情况下,可以采用WEAK 的MEMORY 型Cache 配置。
LRU 型Cache 
当Cache 达到预先设定的最大容量时,ibatis 会按照“最少使用”原则将使用频率最少
的对象从缓冲中清除。
<cacheModel id="userCache" type="LRU"> 
<flushInterval hours="24"/> 
<flushOnExecute statement="updateUser"/> 
<property name="size" value="1000" /> 
</cacheModel> 
可配置的参数有:
. flushInterval 
指定了多长时间清除缓存,上例中指定每24小时强行清空缓存区的所有内容。
. size 

Cache 的最大容量。
FIFO 型Cache 
先进先出型缓存,最先放入Cache 中的数据将被最先废除。可配置参数与LRU 型相同: 
<cacheModel id="userCache" type="FIFO"> 
<flushInterval hours="24"/> 
<flushOnExecute statement="updateUser"/> 
<property name="size" value="1000" /> 
</cacheModel> 
OSCache 
与上面几种类型的Cache 不同,OSCache 来自第三方组织Opensymphony 。可以通过以
下网址获得OSCache 的最新版本(http://www.opensymphony.com/oscache/)。
在生产部署时,建议采用OSCache,OSCache 是得到了广泛使用的开源Cache 实现
(Hibernate 中也提供了对OSCache 的支持),它基于更加可靠高效的设计,更重要的是,
最新版本的OSCache 已经支持Cache 集群。如果系统需要部署在集群中,或者需要部署在
多机负载均衡模式的环境中以获得性能上的优势,那么OSCache 在这里则是不二之选。
Ibatis 中对于OSCache 的配置相当简单: 
<cacheModel id="userCache" type="OSCACHE"> 
<flushInterval hours="24"/> 
<flushOnExecute statement="updateUser"/> 
<property name="size" value="1000" /> 
</cacheModel> 
之所以配置简单,原因在于,OSCache 拥有自己的配置文件(oscache.properties)J。
下面是一个典型的OSCache 配置文件:
#是否使用内存作为缓存空间
cache.memory=true 
#缓存管理事件监听器,通过这个监听器可以获知当前Cache 的运行情况
cache.event.listeners=com.opensymphony.oscache.plugins.clustersupport.JMSBroa 
dcastingListener 
#如果使用磁盘缓存(cache.memory=false),则需要指定磁盘存储接口实现
#cache.persistence.class=com.opensymphony.oscache.plugins.diskpersistence.Disk 
PersistenceListener 
# 磁盘缓存所使用的文件存储路径
# cache.path=c:\\myapp\\cache 
# 缓存调度算法,可选的有LRU,FIFO 和无限缓存(UnlimitedCache) 

# cache.algorithm=com.opensymphony.oscache.base.algorithm.FIFOCache 
# cache.algorithm=com.opensymphony.oscache.base.algorithm.UnlimitedCache 
cache.algorithm=com.opensymphony.oscache.base.algorithm.LRUCache 
#内存缓存的最大容量
cache.capacity=1000 
# 是否限制磁盘缓存的容量
# cache.unlimited.disk=false 
# 基于JMS 的集群缓存同步配置
#cache.cluster.jms.topic.factory=java:comp/env/jms/TopicConnectionFactory 
#cache.cluster.jms.topic.name=java:comp/env/jms/OSCacheTopic 
#cache.cluster.jms.node.name=node1 
# 基于JAVAGROUP 的集群缓存同步配置
#cache.cluster.properties=UDP(mcast_addr=231.12.21.132;mcast_port=45566;ip_ 
ttl=32;mcast_send_buf_size=150000;mcast_recv_buf_size=80000):PING(timeout 
=2000;num_initial_members=3):MERGE2(min_interval=5000;max_interval=10000 
):FD_SOCK:VERIFY_SUSPECT(timeout=1500):pbcast.NAKACK(gc_lag=50;retransm 
it_timeout=300,600,1200,2400,4800):pbcast.STABLE(desired_avg_gossip=20000): 
UNICAST(timeout=5000):FRAG(frag_size=8096;down_thread=false;up_thread=fal 
se):pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;shun=false;print_loc 
al_addr=true) 
#cache.cluster.multicast.ip=231.12.21.132 
配置好之后,将此文件放在CLASSPATH 中,OSCache 在初始化时会自动找到此
文件并根据其中的配置创建缓存实例。

ibatis in Spring 
这里我们重点探讨Spring 框架下的ibatis 应用,特别是在容器事务管理模式下的ibatis 
应用开发。
关于Spring Framework ,请参见笔者另一篇文档:
《Spring 开发指南》http://www.xiaxin.net/Spring_Dev_Guide.rar 
针对ibatis,Spring 配置文件如下:
Ibatis-Context.xml: 
<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" 
"> 
<beans> 
<bean id="dataSource" 
class="org.apache.commons.dbcp.BasicDataSource" 
destroy-method="close"> 
<property name="driverClassName"> 
<value>net.sourceforge.jtds.jdbc.Driver</value> 
</property> 
<property name="url"> 
<value>jdbc:jtds:sqlserver://127.0.0.1:1433/Sample</value> 
</property> 
<property name="username"> 
<value>test</value> 
</property> 
<property name="password"> 
<value>changeit</value> 
</property> 
</bean> 
<bean id="sqlMapClient" 
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> 
<property name="configLocation"> 
<value>SqlMapConfig.xml</value> 
</property> 
</bean> 
<bean id="transactionManager" 
class="org.springframework.jdbc.datasource.DataSourceTransactio 
nManager"> 
"http://www.springframework.org/dtd/spring-beans.dtd

<property name="dataSource"> 
<ref local="dataSource"/> 
</property>
</bean>
<bean id="userDAO" class="net.xiaxin.dao.UserDAO">
<property name="dataSource">
<ref local="dataSource" />
</property>
<property name="sqlMapClient">
<ref local="sqlMapClient" />
</property>
</bean>
<bean id="userDAOProxy"
class="org.springframework.transaction.interceptor.TransactionPro
xyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="target">
<ref local="userDAO" />
</property>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
</beans>
可以看到: 
1. sqlMapClient 节点
sqlMapClient 节点实际上配置了一个sqlMapClient 的创建工厂类。
configLocation 属性配置了ibatis 映射文件的名称。
2. transactionManager 节点
transactionManager 采用了Spring 中的DataSourceTransactionManager 。
3. userDAO 节点

对应的,UserDAO 需要配置两个属性,sqlMapClient 和DataSource, 
sqlMapClient 将从指定的DataSource 中获取数据库连接。
本例中Ibatis 映射文件非常简单: 
sqlMapConfig.xml: 
<sqlMapConfig> 
<sqlMap resource="net/xiaxin/dao/entity/user.xml"/> 
</sqlMapConfig> 
net/xiaxin/dao/entity/user.xml 
<sqlMap namespace="User">
<typeAlias alias="user" type="net.xiaxin.dao.entity.User" />
<insert id="insertUser" parameterClass="user">
INSERT INTO users ( username, password) VALUES ( #username#, 
#password# ) 
</insert>
</sqlMap>
UserDAO.java: 
public class UserDAO extends SqlMapClientDaoSupport implements
IUserDAO { 
public void insertUser(User user) { 
getSqlMapClientTemplate().update("insertUser", user); 


SqlMapClientDaoSupport(如果使用ibatis 1.x 版本,对应支持类是
SqlMapDaoSupport)是Spring 中面向ibatis 的辅助类,它负责调度DataSource 、
SqlMapClientTemplate(对应ibatis 1.x 版本是SqlMapTemplate)完成ibatis 操作,
而DAO 则通过对此类进行扩展获得上述功能。上面配置文件中针对UserDAO 的属性设
置部分,其中的属性也是继承自于这个基类。
SqlMapClientTemplate 对传统SqlMapClient 调用模式进行了封装,简化了上层访问
代码。
User.java: 
public class User { 
public Integer id; 
public String username; 

public String password; 
public Integer getId() { 
return id; 

public void setId(Integer id) {
this.id = id; 
}
public String getPassword() { 
return password; 

public void setPassword(String password) {
this.password = password; 

public String getUsername() { 
return username; 

public void setUsername(String username) {
this.username = username; 

}
测试代码:
InputStream is = new FileInputStream("Ibatis-Context.xml"); 
XmlBeanFactory factory = new XmlBeanFactory(is); 
IUserDAO userdao = (IUserDAO)factory.getBean("userDAOProxy"); 
User user = new User(); 
user.setUsername("Sofia"); 
user.setPassword("mypass"); 
userdao.insertUser(user);
对比前面ibatis 程序代码,我们可以发现UserDAO.java 变得异常简洁,这也正是
Spring Framework 为我们带来的巨大帮助。
Spring 以及其他IOC 框架对传统的应用框架进行了颠覆性的革新,也许这样的评价有
点过于煽情,但是这确是笔者第一次跑通Spring HelloWorld 时的切身感受。有兴趣的
读者可以研究一下Spring framework,enjoy it! 

  评论这张
 
阅读(2249)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017