`
sharkl
  • 浏览: 40856 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类

ibatis--部分更新表记录字段的方法

阅读更多

使用ibatis,如果要更新表记录,一般常用的做法就是,查找出记录,然后修改部分字段,进行update操作.
以member表为例:

MemberDO member  =  memberDAO.findById( 1 );
member.setName(
" stone " );
memberDAO.update(member);


这种是最常用的方法.不错,在很多应用场景下,这么干,完全没有问题.
但是(往往存在但是),如果member表中存在一个或者多个text(或者blob)字段.难道仅仅为了更新一个name字段,需要重新update那些本不需要更新的text/blob字段吗?

于是乎,人们又想出了一个办法,参数采用map,把需要更新的字段put到map中,
演示代码(省略ibatis的sqlmap文件):

Map < String,Object >  map  =   new  HashMap < String,Object > ();
map.put(
" name " , " stone " );
memberDAO.update(map);


没错,这种方法不错.需要更新哪些字段,只需要动态put到map中就可以.
但是,对于这种方法,需要调用更新的地方,需要手工维护数据库的字段名,如果在put的时候,一不小心拼错字段名,那么更新操作肯定和你预计的会有差别.
比如上面的代码:

Map < String,Object >  map  =   new  HashMap < String,Object > ();
map.put(
" nama " , " stone " );
memberDAO.update(map);

不小心把name拼成了nama,那么新的name字段就无法保存到数据库中.试想一下,任何需要更新字段的地方,都存在拼写错误的风险.

于是乎,人们又想到了参数类,比如就把MemberDO当成参数类:

MemberDO memberParam  =   new  MemberDO();
memberParam.setName(
" stone " );
memberDAO.update(memberParam);

sqlmap.xml如下:

update member
set gmt_modified = current_date
< dynamic >
< isNotNull  property ="loginId" ,prepend ="," >
login_id = #loginId#
</ isNotNull >
   
< isNotNull  property ="name" ,prepend ="," >
name = #name#
</ isNotNull >
   
</ dynamic >
where id = #id# 

这方法貌似不错,不会存在字段名拼写错误的风险.并且需要更新哪些字段,动态set一下就可以.
但是,如果要把某个字段设置为null,那怎么办?那没辙咯...(sqlmap中约定,只有不为null的时候,才更新).

那...那...那怎么办呢?
貌似只有Map才能满足需求嘛...因为sqlmap中有个
"isPropertyAvailable"和"isNull"属性支持.只要配合这两个属性,就能区分需要更新为null,还是不更新保持原字段内容.
sqlmap文件演示:

< isPropertyAvailable  property ="loginId"  prepend ="," >
        
< isNotNull  property ="loginId" >
          
<![CDATA[
            login_id = #loginId#
          
]]>
        
</ isNotNull >
        
< isNull  property ="loginId" >
          
<![CDATA[
            login_id = null
          
]]>
        
</ isNull >
</ isPropertyAvailable >

只要map不put loginId,那么更新的时候,就不会更新这个字段,如果map.put("loginId",null),那么就会把loginId更新为null.
看来只有map能胜任.

不是说,使用map,维护字段内容很麻烦嘛.但是好像又只能使用它?
于是乎,又想到了一种思路(也是本文要介绍的一个方法)
通过方法拦截,在设置参数类的时候,把设置的属性值put到map中.(cglib是很胜任这样的场合的)

首先,需要一个BaseDO.java DataObject的基类,仅仅用于维护一份Map对象.
BaseDO.java:

public   class  BaseDO  implements  Serializable {

    
private   static   final   long  serialVersionUID  =   - 315506079592557582L ;

    
private  Map < String, Object >  setterMap;

    
public   synchronized   void  initSetterMap() {
    
if  (setterMap  ==   null ) {
        setterMap 
=   new  HashMap < String, Object > ();
    }
    }

    
public  Map < String, Object >  getSetterMap() {
    
return  setterMap;
    }

}


采用Cglib,写一个对set方法的拦截器:
SetterInterceptor.java 用于对截获set操作,把set的对象put到map中

public   class  SetterInterceptor  implements  MethodInterceptor {

    
private   static   final  String SET_METHOD  =   " set " ;

    @Override
    
public  Object intercept(Object obj, Method method, Object[] args,
        MethodProxy proxy) 
throws  Throwable {
    
//  拦截DataObject中所有的set方法,把set的属性放入到map中
     if  (method.getName().startsWith(SET_METHOD)) {
        
if  (obj  instanceof  BaseDO) {
        BaseDO baseDO 
=  (BaseDO) obj;
        baseDO.initSetterMap();
        String attribute 
=  StringUtils.substring(method.getName(),
            SET_METHOD.length());
        attribute 
=  StringUtils.uncapitalize(attribute);
        
if  (args  !=   null   &&  args.length  ==   1 ) {
            baseDO.getSetterMap().put(attribute, args[
0 ]);
        }
        }
    }
    
return  proxy.invokeSuper(obj, args);
    }

}


写一个创建Setter的工厂类,用于创建带方法拦截的DataObject对象

public   class  SetterFactory {

    
private   static   final  SetterInterceptor setterInterceptor  =   new  SetterInterceptor();

    @SuppressWarnings(
" unchecked " )
    
public   static   < extends  BaseDO >  T getSetterInstance(Class < T >  clazz) {
    Enhancer enhancer 
=   new  Enhancer();
    enhancer.setSuperclass(clazz);
    enhancer.setCallback(setterInterceptor);
    
return  (T) enhancer.create();
    }

}


那么对于client调用,就非常简单了.
如:

public   class  Client {

    
private   static   final  Log log  =  LogFactory.getLog(Client. class );

    
private   static   final  String APP_CONFIG_FILE  =   " cn/zeroall/javalab/ibatis/app.xml " ;

    
public   static   void  main(String[] args) {
    ApplicationContext ctx 
=   new  ClassPathXmlApplicationContext(
        APP_CONFIG_FILE);
    MemberDAO memberDAO 
=  (MemberDAO) ctx.getBean( " memberDAO " );

    MemberDO setter 
=  SetterFactory.getSetterInstance(MemberDO. class );
    setter.setId(
1 );
    setter.setLoginId(
" stone1 " );
    setter.setName(
" stone1 " );
    memberDAO.updateById(setter);

    MemberDO member 
=  memberDAO.findById( 1 );
    log.info(member.getLoginId());

    }
}


sqlmap文件如下:

< update  id ="update-by-id"  parameterClass ="java.util.Map" >
    
<![CDATA[
      update member
      set gmt_modified = current_date
    
]]>
    
< dynamic >
      
< isPropertyAvailable  property ="loginId"  prepend ="," >
        
< isNotNull  property ="loginId" >
          
<![CDATA[
            login_id = #loginId#
          
]]>
        
</ isNotNull >
        
< isNull  property ="loginId" >
          
<![CDATA[
            login_id = null
          
]]>
        
</ isNull >
      
</ isPropertyAvailable >
      
< isPropertyAvailable  property ="password"  prepend ="," >
        
< isNotNull  property ="password" >
          
<![CDATA[
            password = #password#
          
]]>
        
</ isNotNull >
        
< isNull  property ="password" >
          
<![CDATA[
            password = null
          
]]>
        
</ isNull >
      
</ isPropertyAvailable >
      
< isPropertyAvailable  property ="name"  prepend ="," >
        
< isNotNull  property ="name" >
          
<![CDATA[
            name = #name#
          
]]>
        
</ isNotNull >
        
< isNull  property ="name" >
          
<![CDATA[
            name = null
          
]]>
        
</ isNull >
      
</ isPropertyAvailable >
      
< isPropertyAvailable  property ="profile"  prepend ="," >
        
< isNotNull  property ="profile" >
          
<![CDATA[
            profile = #profile#
          
]]>
        
</ isNotNull >
        
< isNull  property ="profile" >
          
<![CDATA[
            profile = null
          
]]>
        
</ isNull >
      
</ isPropertyAvailable >
    
</ dynamic >
    
<![CDATA[
        where id = #id#
    
]]>
  
</ update >



一旦采用了Setter对象,那么对于表记录的更新操作,仅仅需要一个sql,就能解决.比较方便.

附件中,把整个演示代码附上,有兴趣的朋友,可以了解下:
采用maven构建,workspace编码采用utf-8.数据库采用pgsql

demo附件

备注:
member表创建sql如下:

--  Table: member

--  DROP TABLE member;

CREATE   TABLE  member
(
  id serial 
NOT   NULL ,
  login_id 
character   varying ( 16 ),
  "password" 
character   varying ( 16 ),
  "name" 
character   varying ( 32 ),
  profile 
text ,
  gmt_created 
timestamp  without time zone,
  gmt_modified 
timestamp  without time zone,
  
CONSTRAINT  member_pkey  PRIMARY   KEY  (id)
)
WITH  (OIDS = FALSE);
ALTER   TABLE  member OWNER  TO  javalab;
分享到:
评论

相关推荐

    ibatis-common.jar包

    除此之外,ibatis-common.jar还提供了异常处理、日志记录、缓存管理等辅助功能,为开发者提供了一个完整的数据访问解决方案。在实际开发中,熟练掌握ibatis-common.jar包的使用,不仅可以提高开发效率,还能确保代码...

    iBATIS-SqlMaps-2_cn.pdf

    在XML描述文件中,SQL Maps定义了Java Bean、Map实现以及基本数据类型的包装类如何与数据库中的表和记录对应。这些映射文件通常包含SQL查询、存储过程以及事务管理等元素,使得开发者无需编写大量JDBC代码就能完成...

    ibatis-2.3.4.726.jar

    1. SQL Maps:这是iBATIS的核心部分,SQL Maps定义了如何在数据库中执行SQL查询以及如何处理返回的结果。它们是XML文件,其中包含了SQL语句和映射结果集到Java对象的规则。 2. Dynamic SQL:iBATIS支持动态SQL,...

    ibatis-sqlMap相关参考

    每个`&lt;sqlmap&gt;`元素代表一个数据库表或者视图,包含了多个操作(如查询、插入、更新、删除)的`&lt;select&gt;`, `&lt;insert&gt;`, `&lt;update&gt;`, 和 `&lt;delete&gt;`元素。这些元素可以包含动态SQL,使得SQL更具灵活性。例如,`&lt;if&gt;`...

    ibatis 配置文件详解

    ibatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 #### 二、ibatis配置文件解析 ibatis的核心配置文件是`SqlMapConfig.xml...

    使用ibatis操作两个有关系的表

    在实际应用中,我们还需要创建对应的Java模型类,这些类的属性应与数据库表的字段相对应。Ibatis会自动将查询结果转化为Java对象,方便进行业务逻辑处理。 为了实现上述功能,你需要在Ibatis的配置文件中引入数据源...

    Ibatis多表查询

    `book` 表存储书籍的信息,而 `user` 表记录作者信息,其中 `book_oid` 字段作为外键引用 `book` 表的主键 `oid`,表明了一本书可以有多个作者(一对多关系)。 为了实现 Ibatis 的多表查询,我们需要创建对应的 ...

    Mybatis拦截器记录数据更新历史记录到MongoDB

    在“Mybatis拦截器记录数据更新历史记录到MongoDB”这个项目中,我们需要创建一个自定义的拦截器类,该类需要实现`org.apache.ibatis.plugin.Interceptor`接口并覆写`intercept`方法。在这个方法里,我们可以捕获到...

    iBATIS实例小程序

    - `mbs_txn_dtll`表中的`ext_error_cd`字段与`mbs_param`表中的`param_nm`字段相匹配。 - 条件: - 账户号: `l.orig_acct_no=#acct#` - 交易类型: `l.type_cd='1000'` - 交易代码: `l.txn_code='D0012'` - 组织...

    abator插件,ibatis插件

    4. **实体类**:表示数据库表的 Java 类,通常包含属性和 getter/setter 方法,用于存储和读取数据库记录。 在实际使用 Abator 时,首先需要在项目中引入 Abator 的依赖,然后创建一个 Abator 配置文件,配置文件中...

    ibatis.util包

    `ibatis.util`包是Ibatis框架的一部分,提供了很多实用工具类,帮助开发者更好地进行数据库操作。在这个描述中,我们看到提到的是"EMIS文件中缺少的ibatis工具包",这可能意味着在EMIS(可能是企业信息管理系统)的...

    ibatis 一对多关系映射

    这样,当我们调用`SqlSession`的`selectList`方法执行这个查询时,Ibatis会自动将返回的多条记录按照一对多的关系映射成`User`对象,每个`User`对象都有一个包含所有关联订单的`orderList`。 此外,还可以通过使用`...

    iBatis操作MySQL增删改查

    4. **更新记录**:更新数据使用`&lt;update&gt;`标签,编写SQL更新语句,并在Java代码中调用Mapper接口的`update()`方法,传入需要更新的对象,iBatis会自动匹配字段和值。 为了更好地理解这些操作,你可以查看压缩包中的...

    ibatis环境搭建教程

    SQL Maps是ibatis的核心组成部分之一,它是数据库层配置的基础。通过使用SQL Maps,可以将复杂的SQL语句映射到XML配置文件中,进而实现对Java Beans和SQL Statements之间的映射。这种映射机制简化了开发过程中的数据...

    ibatis案例详解

    接下来是DAO(Data Access Object)接口,`IDAO`,它定义了对`ibatis`表进行CRUD(创建、读取、更新、删除)操作的方法。这些方法包括获取所有记录、根据名称或ID获取记录、保存新记录、删除记录和更新记录。 在...

    spring mvc+ibatis+oracle单表增删改(有包)

    在本项目中,我们主要探讨的是如何利用Spring MVC、iBATIS和Oracle数据库来实现一个基本的单表操作,包括增、删、改等常见功能。Spring MVC是Spring框架的一个模块,专门处理Web应用程序的模型-视图-控制器(MVC)...

    ibatis 一对多 多对多完整映射

    在IT行业中,数据库关系映射是开发Web应用时不可或缺的一部分,特别是对于ORM(对象关系映射)框架如iBATIS(现在称为MyBatis)。本文将深入探讨如何在iBATIS中实现一对多和多对多的关系映射,并提供相关的源码分析...

    常用ibatis配置

    通过上述知识点,我们可以了解到iBatis框架在配置和使用时如何帮助开发者实现数据的插入、查询、更新和删除操作,并且如何通过动态SQL标签来构建灵活且高效的数据库操作。这些知识不仅涵盖了iBatis的核心特性,也...

    06_ibatis教程_修改实体对象.rar

    总结来说,Ibatis教程中的"06_ibatis教程_修改实体对象"部分主要涵盖了如何使用Ibatis进行数据库记录的更新操作,包括配置SQL映射、定义接口方法、调用更新方法以及事务管理。理解并熟练掌握这些知识点,将有助于...

Global site tag (gtag.js) - Google Analytics