<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    stone2083

    ibatis--部分更新表記錄字段的方法

    使用ibatis,如果要更新表記錄,一般常用的做法就是,查找出記錄,然后修改部分字段,進(jìn)行update操作.
    以member表為例:
    MemberDO member = memberDAO.findById(1);
    member.setName(
    "stone");
    memberDAO.update(member);

    這種是最常用的方法.不錯(cuò),在很多應(yīng)用場(chǎng)景下,這么干,完全沒有問題.
    但是(往往存在但是),如果member表中存在一個(gè)或者多個(gè)text(或者blob)字段.難道僅僅為了更新一個(gè)name字段,需要重新update那些本不需要更新的text/blob字段嗎?

    于是乎,人們又想出了一個(gè)辦法,參數(shù)采用map,把需要更新的字段put到map中,
    演示代碼(省略ibatis的sqlmap文件):
    Map<String,Object> map = new HashMap<String,Object>();
    map.put(
    "name","stone");
    memberDAO.update(map);

    沒錯(cuò),這種方法不錯(cuò).需要更新哪些字段,只需要?jiǎng)討B(tài)put到map中就可以.
    但是,對(duì)于這種方法,需要調(diào)用更新的地方,需要手工維護(hù)數(shù)據(jù)庫的字段名,如果在put的時(shí)候,一不小心拼錯(cuò)字段名,那么更新操作肯定和你預(yù)計(jì)的會(huì)有差別.
    比如上面的代碼:
    Map<String,Object> map = new HashMap<String,Object>();
    map.put(
    "nama","stone");
    memberDAO.update(map);
    不小心把name拼成了nama,那么新的name字段就無法保存到數(shù)據(jù)庫中.試想一下,任何需要更新字段的地方,都存在拼寫錯(cuò)誤的風(fēng)險(xiǎn).

    于是乎,人們又想到了參數(shù)類,比如就把MemberDO當(dāng)成參數(shù)類:
    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# 
    這方法貌似不錯(cuò),不會(huì)存在字段名拼寫錯(cuò)誤的風(fēng)險(xiǎn).并且需要更新哪些字段,動(dòng)態(tài)set一下就可以.
    但是,如果要把某個(gè)字段設(shè)置為null,那怎么辦?那沒轍咯...(sqlmap中約定,只有不為null的時(shí)候,才更新).

    那...那...那怎么辦呢?
    貌似只有Map才能滿足需求嘛...因?yàn)閟qlmap中有個(gè)
    "isPropertyAvailable"和"isNull"屬性支持.只要配合這兩個(gè)屬性,就能區(qū)分需要更新為null,還是不更新保持原字段內(nèi)容.
    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,那么更新的時(shí)候,就不會(huì)更新這個(gè)字段,如果map.put("loginId",null),那么就會(huì)把loginId更新為null.
    看來只有map能勝任.

    不是說,使用map,維護(hù)字段內(nèi)容很麻煩嘛.但是好像又只能使用它?
    于是乎,又想到了一種思路(也是本文要介紹的一個(gè)方法)
    通過方法攔截,在設(shè)置參數(shù)類的時(shí)候,把設(shè)置的屬性值put到map中.(cglib是很勝任這樣的場(chǎng)合的)

    首先,需要一個(gè)BaseDO.java DataObject的基類,僅僅用于維護(hù)一份Map對(duì)象.
    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,寫一個(gè)對(duì)set方法的攔截器:
    SetterInterceptor.java 用于對(duì)截獲set操作,把set的對(duì)象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);
        }

    }

    寫一個(gè)創(chuàng)建Setter的工廠類,用于創(chuàng)建帶方法攔截的DataObject對(duì)象
    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();
        }

    }

    那么對(duì)于client調(diào)用,就非常簡(jiǎn)單了.
    如:
    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對(duì)象,那么對(duì)于表記錄的更新操作,僅僅需要一個(gè)sql,就能解決.比較方便.

    附件中,把整個(gè)演示代碼附上,有興趣的朋友,可以了解下:
    采用maven構(gòu)建,workspace編碼采用utf-8.數(shù)據(jù)庫采用pgsql

    demo附件

    備注:
    member表創(chuàng)建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;


    特別說明:
    此方法原創(chuàng)作者為公司同事,本文只是盜用了他的創(chuàng)意.


    posted on 2008-06-26 22:46 stone2083 閱讀(7875) 評(píng)論(2)  編輯  收藏 所屬分類: java

    Feedback

    # re: ibatis--部分更新表記錄字段的方法[未登錄] 2013-01-29 14:35 JAKE

    不錯(cuò),學(xué)習(xí)了下  回復(fù)  更多評(píng)論   

    # re: ibatis--部分更新表記錄字段的方法 2014-08-31 23:48 yanick

    不錯(cuò)  回復(fù)  更多評(píng)論   

    主站蜘蛛池模板: 亚洲系列国产精品制服丝袜第| 性做久久久久免费看| 亚洲国产精品无码久久久不卡| 永久免费精品影视网站| 亚洲精品动漫人成3d在线 | 日本亚洲欧洲免费天堂午夜看片女人员| 亚洲av无码天堂一区二区三区| 一级成人a做片免费| 国产亚洲精品AA片在线观看不加载| 国产成人无码精品久久久免费| 亚洲国产综合无码一区二区二三区| 一级特黄a免费大片| 亚洲大成色www永久网站| 伊人久久免费视频| 亚洲综合激情九月婷婷| 免费毛片在线看片免费丝瓜视频 | 国产成人久久精品亚洲小说| 国产一区二区三区在线观看免费| 免费看一级高潮毛片| 亚洲日韩av无码| 亚洲高清视频免费| 久久久久亚洲国产AV麻豆| 亚洲国产a级视频| 免费女人高潮流视频在线观看| 亚洲jizzjizz在线播放久| 亚洲成a人片在线播放| 亚欧日韩毛片在线看免费网站| 亚洲综合色区中文字幕| 亚洲阿v天堂在线2017免费| 日韩免费视频一区二区| 亚洲情A成黄在线观看动漫软件| 国产免费私拍一区二区三区| a级男女仿爱免费视频| 亚洲中文字幕久久久一区| 亚洲成a人在线看天堂无码| 最近中文字幕mv免费高清在线| 亚洲熟妇无码八V在线播放 | 亚洲无线电影官网| 国产片免费在线观看| 日本中文字幕免费高清视频| 国产精品亚洲专区无码WEB|