iBatis開(kāi)發(fā)詳解(6)---Spring的數(shù)據(jù)庫(kù)訪問(wèn)

2018-10-13 12:04 更新

    現(xiàn)在我們介紹Spring對(duì)iBatis的支持。 


    相對(duì)于Hibernate等ORM框架的全自動(dòng)SQL,那么iBatis則屬于半自動(dòng)化的ORM框架,我們需要編寫(xiě)SQL語(yǔ)句,由iBatis進(jìn)行數(shù)據(jù)庫(kù)訪問(wèn),返回結(jié)果。而iBatis可以為我們做的更多,比如對(duì)查詢結(jié)果的封裝等等。雖然不如全自動(dòng)SQL方便,但是SQL的主動(dòng)權(quán)卻在我們開(kāi)發(fā)人員的手中,對(duì)SQL優(yōu)化的掌控則是很直接的。對(duì)于Hibernate和iBatis的其它討論,不是我們探究的范圍。 


   當(dāng)前iBatis的版本為3,其名稱也已經(jīng)更改為MyBatis。而Spring更新到3.1都沒(méi)有對(duì)MyBatis進(jìn)行支持,但是MyBatis團(tuán)隊(duì)已經(jīng)自行開(kāi)發(fā)了Spring的支持。我們以Spring為主,仍然使用對(duì)iBatis2的支持來(lái)進(jìn)行說(shuō)明。 


   首先是構(gòu)建開(kāi)發(fā)環(huán)境,我們?nèi)匀皇褂肕aven作為構(gòu)建環(huán)境,創(chuàng)建項(xiàng)目,本文的示例基于“聯(lián)系人管理”功能來(lái)展示: 

package org.ourpioneer.contact.bean;  
public class Contact {  
    private Long id;  
    private String name;  
    private String gender;  
    private String mobile;  
    private String address;  
    //省略getter和setter方法  
    @Override  
    public String toString() {  
        return "Contact [id=" + id + ", name=" + name + ", gender=" + gender  
                + ", mobile=" + mobile + ", address=" + address + "]";  
    }  
}  
   編寫(xiě)一個(gè)Contact類來(lái)描述聯(lián)系人的一些特征,為了簡(jiǎn)便,我們使用5個(gè)字段就夠了,實(shí)體類是很簡(jiǎn)單的。下面是添加類庫(kù)了,要訪問(wèn)數(shù)據(jù)庫(kù),不能少了數(shù)據(jù)庫(kù)驅(qū)動(dòng),我們使用MySQL數(shù)據(jù)庫(kù),在pom.xml中添加依賴: 
<dependency>  
    <groupId>mysql</groupId>  
    <artifactId>mysql-connector-java</artifactId>  
    <version>5.1.14</version>  
    <type>jar</type>  
    <scope>compile</scope>  
</dependency>  
  同時(shí)在數(shù)據(jù)庫(kù)中建表,因?yàn)閕Batis還沒(méi)有自動(dòng)建表的功能: 
CREATE TABLE `contact` (  
`ID`  int(11) NOT NULL AUTO_INCREMENT ,  
`NAME`  varchar(20) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL ,  
`GENDER`  varchar(10) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL ,  
`MOBILE`  varchar(11) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL ,  
`ADDRESS`  varchar(100) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL ,  
PRIMARY KEY (`ID`)  
)  
ENGINE=InnoDB  
DEFAULT CHARACTER SET=latin1 COLLATE=latin1_swedish_ci  
AUTO_INCREMENT=1  
ROW_FORMAT=COMPACT  
;  
  加好驅(qū)動(dòng),創(chuàng)建好數(shù)據(jù)庫(kù)表,那么程序訪問(wèn)需要配置連接池,這里我們使用BoneCP連接池,在pom.xml中加入相關(guān)依賴: 
<repositories>  
    <repository>  
        <releases>  
            <updatePolicy>always</updatePolicy>  
        </releases>  
        <snapshots>  
            <updatePolicy>always</updatePolicy>  
        </snapshots>  
        <id>Jolbox</id>  
        <name>Jolbox Repositories</name>  
        <url>http://jolbox.com/bonecp/downloads/maven</url>  
    </repository>  
</repositories>  
    因?yàn)锽oneCP的Maven倉(cāng)庫(kù)不在Maven的中央倉(cāng)庫(kù)中,所以必須加入以上代碼到pom.xml中,這點(diǎn)可以在BoneCP的官方網(wǎng)站(http://jolbox.com/)中獲得,下面就是加入依賴了,就沒(méi)有什么多說(shuō)的了: 
<dependency>  
    <groupId>com.jolbox</groupId>  
    <artifactId>bonecp</artifactId>  
    <version>0.7.1.RELEASE</version>  
</dependency>  
  下面配置系統(tǒng)日志,因?yàn)橐隑oneCP而引入了slf4j,如果自動(dòng)添加的版本過(guò)低,這里我們要重新設(shè)置slf4j的版本為1.6.4。那么我們添加logback來(lái)設(shè)置日志系統(tǒng):
<dependency>  
    <groupId>ch.qos.logback</groupId>  
    <artifactId>logback-core</artifactId>  
    <version>1.0.0</version>  
    <type>jar</type>  
    <scope>compile</scope>  
</dependency>  
<dependency>  
    <groupId>ch.qos.logback</groupId>  
    <artifactId>logback-classic</artifactId>  
    <version>1.0.0</version>  
    <type>jar</type>  
    <scope>compile</scope>  
</dependency>  
    下面配置logback.xml來(lái)配置日志具體項(xiàng),logback.xml文件需要放置到類路徑的根路徑下:
<?xml version="1.0" encoding="UTF-8"?>  
<configuration>  
    <jmxConfigurator />  
    <!--輸出到控制臺(tái),方便調(diào)試,應(yīng)用時(shí)切換到文件Log -->  
    <appender name="ConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">  
        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">  
            <pattern>%date %-5level [%logger{80}:%L] - %msg%n  
            </pattern>  
            <charset>UTF-8</charset>  
        </encoder>  
    </appender>  
    <!-- 需要記錄日志的包 -->  
    <logger name="org.ourpioneer">  
        <level value="debug" />  
    </logger>  
    <logger name="org.springframework">  
        <level value="warn" />  
    </logger>  
    <root>  
        <level value="warn" />  
        <appender-ref ref="ConsoleAppender" />  
    </root>  
</configuration>  
   這里我們只創(chuàng)建了控制臺(tái)的Appender,其中設(shè)置了日志的格式,編碼和需要記錄日志的包,并配置響應(yīng)日志的級(jí)別,這都很好理解。下面是添加Spring和iBatis的類庫(kù):
<dependency>  
    <groupId>org.apache.ibatis</groupId>  
    <artifactId>ibatis-sqlmap</artifactId>  
    <version>2.3.4.726</version>  
    <scope>compile</scope>  
</dependency>  
   Spring的類庫(kù)添加core,beans,context,jdbc和orm模塊即可,其它依賴則會(huì)自動(dòng)添加過(guò)來(lái),最終的類庫(kù)如下圖所示: 
 下面就是構(gòu)建項(xiàng)目的目錄結(jié)構(gòu): 
    我們采用分層開(kāi)發(fā)的思想,DAO控制訪問(wèn)數(shù)據(jù),Service調(diào)用DAO方法,同時(shí)在Service層做事務(wù),因?yàn)槲覀儾皇荳eb項(xiàng)目,這里沒(méi)有Web層的框架和Action。Bean包下的實(shí)體類Contact前面解釋過(guò)了,common包下的BaseDAO提供操作iBatis的方法,ParameterMap是我們?yōu)閕Batis提供參數(shù)的對(duì)象,dao包下就是DAO對(duì)象,service包下放置Service類,sqlMaps包下放置iBatis用到的SQL映射文件。App類是我們的測(cè)試類。類路徑的根目錄下的beans.xml是Spring的配置文件,logback.xml是日志配置文件,sqlMapConfig.xml是iBatis的總配置文件,首先來(lái)看sqlMapConfig.xml:
<?xml version="1.0" encoding="UTF-8" ?>   
<!DOCTYPE sqlMapConfig   
    PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN"   
    "http://www.ibatis.com/dtd/sql-map-config-2.dtd">  
<sqlMapConfig>  
    <settings cacheModelsEnabled="true" enhancementEnabled="true"  
        lazyLoadingEnabled="true" errorTracingEnabled="true" maxRequests="32"  
        maxSessions="10" maxTransactions="5" />  
        <sqlMap resource="org/ourpioneer/contact/sqlMaps/contact.xml" />  
</sqlMapConfig>  
  其中就是對(duì)iBatis的一些設(shè)置,并包含sqlMap文件,很簡(jiǎn)單,這沒(méi)有什么可多說(shuō)的,logback文件前面給出了,下面是Spring的配置文件,首先配置數(shù)據(jù)源dataSource:
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource"  
    destroy-method="close">  
    <property name="driverClass" value="com.mysql.jdbc.Driver" />  
    <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />  
    <property name="username" value="root" />  
    <property name="password" value="123" />  
    <property name="maxConnectionsPerPartition" value="30" />  
    <property name="minConnectionsPerPartition" value="10" />  
    <property name="partitionCount" value="3" />  
    <property name="acquireIncrement" value="5" />  
    <property name="statementsCacheSize" value="100" />  
    <property name="releaseHelperThreads" value="3" />  
</bean>  
   關(guān)于BoneCP的介紹網(wǎng)上也有很多,這里不再詳細(xì)解釋各個(gè)配置項(xiàng)的含義了,配置好數(shù)據(jù)源,下面是SqlMapClient,使用Spring的bean工廠來(lái)創(chuàng)建,參數(shù)是iBatis的總配置文件和數(shù)據(jù)源,這里我們需要注入配置好的數(shù)據(jù)源dataSource: 
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">  
    <property name="configLocation" value="classpath:sqlMapConfig.xml" />  
    <property name="dataSource" ref="dataSource" />  
</bean>  
   Spring在對(duì)iBatis的支持上提供了SqlMapClientTemplate,也就是操作SqlMapClient的模板,這個(gè)jdbcTemplate類似,其中的方法使用方式也是類似的,為我們操作iBatis提供了便捷的接口: 
<bean id="sqlMapClientTemplate" class="org.springframework.orm.ibatis.SqlMapClientTemplate">  
        <constructor-arg>  
            <ref bean="sqlMapClient" />  
        </constructor-arg>  
    </bean>  
   數(shù)據(jù)庫(kù)操作的bean都配置好了,下面是事務(wù)模塊的配置,我們抽象出Service層,也是為了方便事務(wù)操作,可能一組業(yè)務(wù)需要操作多個(gè)DAO,那么顯然不能在DAO層做事務(wù),而在業(yè)務(wù)層做事務(wù)是非常合適的,也符合邏輯,我們使用Spring提供的DataSourceTransactionManager來(lái)配置事務(wù)管理器: 
<bean id="transactionManager"  
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    <property name="dataSource">  
        <ref bean="dataSource" />  
    </property>  
</bean>  
  下面是事務(wù)攔截的方法和AOP切入點(diǎn):
<tx:advice id="txAdvice" transaction-manager="transactionManager">  
    <tx:attributes>  
        <tx:method name="get*" read-only="true" />  
        <tx:method name="insert*" rollback-for="Exception" />  
        <tx:method name="add*" rollback-for="Exception" />  
        <tx:method name="addOrUpdate*" rollback-for="Exception" />  
        <tx:method name="del*" rollback-for="Exception" />  
        <tx:method name="update*" rollback-for="Exception" />  
    </tx:attributes>  
</tx:advice>  
<aop:config proxy-target-class="true">  
    <aop:pointcut id="serviceMethod"  
        expression="execution(* org.ourpioneer.service.*Service.*(..))" />  
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethod" />  
</aop:config>  
   這樣,我們對(duì)org.ourpioneer.service.*Service中方法名以insert/add/del/update等開(kāi)頭的方法都做上事務(wù)了。因?yàn)槲覀兪褂肧pring作為bean容器,那么將DAO和Service也納入Spring 的管理之中:
<bean id="baseDAO" class="org.ourpioneer.contact.common.BaseDAO">  
    <property name="sqlMapClientTemplate" ref="sqlMapClientTemplate" />  
</bean>  
<bean id="contactDAO" class="org.ourpioneer.contact.dao.impl.ContactDAOImpl"  
    parent="baseDAO" />  
  這里我們將sqlMapClientTemplate配置到BaseDAO中,而ContactDAO繼承BaseDAO即可,同時(shí)這里要注意這里我們使用了接口和實(shí)現(xiàn)相分離的做法,class中是實(shí)現(xiàn)類而不是接口,下面是Service: 
<bean id="contactService" class="org.ourpioneer.contact.service.ContactService">  
    <property name="contactDAO" ref="contactDAO" />  
</bean>
   配置文件都沒(méi)有問(wèn)題了,我們需要把這些涉及到的類都給寫(xiě)出來(lái): 
package org.ourpioneer.contact.dao;  
import java.util.Map;  
import org.ourpioneer.contact.bean.Contact;  
public interface ContactDAO {  
    public Contact getContactById(Map<Object, Object> parameterMap);  
} 
  DAO接口僅僅是方法的描述,而實(shí)現(xiàn)類中編寫(xiě)具體實(shí)現(xiàn)代碼:
package org.ourpioneer.contact.dao.impl;  
import java.util.Map;  
import org.ourpioneer.contact.bean.Contact;  
import org.ourpioneer.contact.common.BaseDAO;  
import org.ourpioneer.contact.dao.ContactDAO;  
public class ContactDAOImpl extends BaseDAO implements ContactDAO {  
    public Contact getContactById(Map<Object, Object> parameterMap) {  
        return (Contact) getSqlMapClientTemplate().queryForObject("getContactById",  
                parameterMap);  
    }  
}  
   這里涉及到了BaseDAO,我們來(lái)看一下: 
package org.ourpioneer.contact.common;  
import org.springframework.orm.ibatis.SqlMapClientTemplate;  
public class BaseDAO {  
    private SqlMapClientTemplate sqlMapClientTemplate;  
    public SqlMapClientTemplate getSqlMapClientTemplate() {  
        return sqlMapClientTemplate;  
    }  
    public void setSqlMapClientTemplate(  
            SqlMapClientTemplate sqlMapClientTemplate) {  
        this.sqlMapClientTemplate = sqlMapClientTemplate;  
    }  
}  
   調(diào)用DAO的Service代碼如下:
package org.ourpioneer.contact.service;  
import java.util.Map;  
import org.ourpioneer.contact.bean.Contact;  
import org.ourpioneer.contact.common.ParameterMap;  
import org.ourpioneer.contact.dao.ContactDAO;  
public class ContactService {  
    private ContactDAO contactDAO;  
    public ContactDAO getContactDAO() {  
        return contactDAO;  
    }  
    public void setContactDAO(ContactDAO contactDAO) {  
        this.contactDAO = contactDAO;  
    }  
    public Contact getContactById(long id) {  
        Map<Object, Object> parameterMap = new ParameterMap("ID", id);  
        return getContactDAO().getContactById(parameterMap);  
    }  
}  
  從Spring的配置文件我們不難理解這些代碼的真正含義,就不過(guò)多解釋,這里用到了一個(gè)ParameterMap對(duì)象,我們來(lái)看一下它的定義:
package org.ourpioneer.contact.common;  
import java.util.HashMap;  
public class ParameterMap extends HashMap<Object, Object> {  
    private static final long serialVersionUID = 1L;  
    public ParameterMap(Object... parameters) {  
        for (int i = 0; i < parameters.length - 1; i += 2) {  
            super.put(parameters[i], parameters[i + 1]);  
        }  
    }  
}  
    非常的簡(jiǎn)單,這樣我們?cè)谑褂玫臅r(shí)候就可以按照[名,值,名,值....]這樣的格式來(lái)放置參數(shù)了。本例中涉及到了一個(gè)查詢叫“getContactById”,它定義在sqlMaps下的contact.xml中,我們來(lái)看一下: 
<?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="parameterMap" type="org.ourpioneer.contact.common.ParameterMap" />  
    <typeAlias alias="contact" type="org.ourpioneer.contact.bean.Contact" />  
    <select id="getContactById" parameterClass="parameterMap"  
        resultClass="contact">  
        select *  
        from contact  
        where ID=#ID:LONG#  
    </select>  
</sqlMap>  
    首先對(duì)ParameterMap和Contact進(jìn)行別名,為了下面的方便調(diào)用,這里我們有一個(gè)查詢,SQL語(yǔ)句很好理解,select元素的id屬性就是它的標(biāo)識(shí)符了,也是sqlMapClientTemplate的queryForObject方法第一個(gè)參數(shù),parameterClass指定了參數(shù)類,我們使用的是自定義的ParameterMap,resultClass結(jié)果類型是我們的實(shí)體類對(duì)象,這樣我們執(zhí)行這個(gè)查詢,iBatis會(huì)自動(dòng)為我們封裝成一個(gè)bean返回,易于調(diào)用。 

    為了測(cè)試,我們首先在數(shù)據(jù)表中插入一條記錄: 
INSERT INTO `contact` VALUES ('1', 'Sarin', 'male', '15940912345', 'Dalian');  
  下面來(lái)編寫(xiě)測(cè)試代碼: 
package org.ourpioneer.contact;  
import org.ourpioneer.contact.bean.Contact;  
import org.ourpioneer.contact.service.ContactService;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
public class App {  
    private static final Logger logger = LoggerFactory.getLogger(App.class);  
    public static void main(String[] args) {  
        ApplicationContext context = new ClassPathXmlApplicationContext(  
                "beans.xml");  
        ContactService contactService = (ContactService) context  
                .getBean("contactService");  
        Contact contact = contactService.getContactById(1);  
        logger.info("{}",contact);  
    }  
}  
   我們從Spring的ApplicationContext中獲取到Service對(duì)象,然后調(diào)用getContactById方法獲取結(jié)果,下面是運(yùn)行的結(jié)果:
    我們繼續(xù)來(lái)研究spring和iBatis的整合訪問(wèn)數(shù)據(jù)。下面首先來(lái)看看插入操作,數(shù)據(jù)的插入操作屬于更新操作的一種,是比較簡(jiǎn)單的一種操作,就是將符合數(shù)據(jù)表字段規(guī)范且對(duì)應(yīng)用程序無(wú)害的數(shù)據(jù)插入到數(shù)據(jù)表中。
 
    我們分兩種方式來(lái)進(jìn)行插入操作,第一種是Bean的方式進(jìn)行,首先來(lái)編寫(xiě)iBatis的插入SQL語(yǔ)句: 
<insert id="insertContact" parameterClass="contact">  
    insert into  
    contact(NAME,GENDER,MOBILE,ADDRESS)  
    values  
(#name:VARCHAR#,#gender:VARCHAR#,#mobile:VARCHAR#,#address:VARCHAR#)  
</insert>  
   我們使用<insert>標(biāo)簽表示插入語(yǔ)句,為該語(yǔ)句起個(gè)名字,就是id屬性中的insertContact,之后聲明我們使用的參數(shù)類型,也就是我們聲明過(guò)的Contact。需要注意的是這里的參數(shù)設(shè)置,#name:VARCHAR#,小寫(xiě)的name是Bean中的字段名稱,大小寫(xiě)要完全一致才行,VARCHAR表示的是數(shù)據(jù)類型,不用多說(shuō)。在數(shù)據(jù)表中的這四個(gè)字段我們都聲明為VARCHAR類型,而插入時(shí)不需要設(shè)置ID,是因?yàn)槲覀兪褂肕ySQL數(shù)據(jù)庫(kù)的自增主鍵了,如果是其它類型的數(shù)據(jù)庫(kù),請(qǐng)使用相應(yīng)的主鍵生成策略來(lái)為主鍵賦值。 

    編寫(xiě)完SQL語(yǔ)句,我們來(lái)寫(xiě)DAO: 
package org.ourpioneer.contact.dao;  
import java.util.Map;  
import org.ourpioneer.contact.bean.Contact;  
public interface ContactDAO {  
    public Contact getContactById(Map<Object, Object> parameterMap);  
    public int insertContact(Contact contact);  
}  
   我們多加了一個(gè)insertContact(Contact contact)方法,返回值類型是int,也就是更新的行數(shù),這都是JDBC規(guī)范中的內(nèi)容,下面來(lái)實(shí)現(xiàn)這個(gè)新加的方法: 
package org.ourpioneer.contact.dao.impl;  
import java.util.Map;  
import org.ourpioneer.contact.bean.Contact;  
import org.ourpioneer.contact.common.BaseDAO;  
import org.ourpioneer.contact.dao.ContactDAO;  
public class ContactDAOImpl extends BaseDAO implements ContactDAO {  
    public Contact getContactById(Map<Object, Object> parameterMap) {  
        return (Contact) getSqlMapClientTemplate().queryForObject(  
                "getContactById", parameterMap);  
    }  
    public int insertContact(Contact contact) {  
        return getSqlMapClientTemplate().update("insertContact", contact);  
    }  
}  
   該方法的實(shí)現(xiàn)也非常簡(jiǎn)單,但是注意這里,我們并沒(méi)有使用sqlMapClientTemplate的insert方法,而是update方法來(lái)進(jìn)行操作的。原因是insert方法不會(huì)返回int類型的結(jié)果,而insert也是更新操作的一種,使用update方法也是可以的。下面在Service類中對(duì)應(yīng)添加代碼: 
public int insertContact(Contact contact) {  
    return getContactDAO().insertContact(contact);  
}  
    之后我們開(kāi)始編寫(xiě)測(cè)試類,代碼如下: 
package org.ourpioneer.contact;  
import org.ourpioneer.contact.bean.Contact;  
import org.ourpioneer.contact.service.ContactService;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
public class App {  
    private static final Logger logger = LoggerFactory.getLogger(App.class);  
    public static void main(String[] args) {  
        ApplicationContext context = new ClassPathXmlApplicationContext(  
                "beans.xml");  
        ContactService contactService = (ContactService) context  
                .getBean("contactService");  
        // Contact contact = contactService.getContactById(1);  
        Contact contact = new Contact("Tom", "male", "15940990001", "Dalian");  
        int recordsOfUpdates = contactService.insertContact(contact);  
        logger.info("{}", recordsOfUpdates);  
    }  
}  
   這里需要注意,我們創(chuàng)建Bean時(shí)使用了帶有參數(shù)的構(gòu)造方法(且不含ID),那么還需要在Contact類中聲明出無(wú)參數(shù)的構(gòu)造方法,也就是在Contact類中添加如下兩個(gè)構(gòu)造方法: 
public Contact() {  
    super();  
}  
public Contact(String name, String gender, String mobile, String address) {  
    super();  
    this.name = name;  
    this.gender = gender;  
    this.mobile = mobile;  
    this.address = address;  
}  
  運(yùn)行測(cè)試程序,我們會(huì)得到如下輸出: 

  可以看出update語(yǔ)句的返回值是1,也就是說(shuō)我們成功地更新了一行數(shù)據(jù),打開(kāi)數(shù)據(jù)表,我們可以看到這條數(shù)據(jù)已經(jīng)成功添加進(jìn)去了: 

   下面來(lái)看第二種參數(shù)設(shè)置方式,就是使用我們之前的ParameterMap方式。使用Bean是ORM特性的體現(xiàn),而如果在一個(gè)事務(wù)中,需要向多個(gè)表中插入數(shù)據(jù),顯然使用Bean的方式存在不足,因?yàn)橹虚g表可能沒(méi)有對(duì)應(yīng)的Bean存在,而且構(gòu)造Bean是消耗系統(tǒng)資源的,特別是在批量操作時(shí),是不建議使用Bean的方式的。那么我們可以使用ParameterMap的方式來(lái)統(tǒng)一設(shè)置傳入?yún)?shù)。 

     修改SQL語(yǔ)句: 
<insert id="insertContact" parameterClass="parameterMap">  
    insert into  
    contact(NAME,GENDER,MOBILE,ADDRESS)  
    values  
(#NAME:VARCHAR#,#GENDER:VARCHAR#,#MOBILE:VARCHAR#,#ADDRESS:VARCHAR#)  
</insert> 
  之后在DAO中重載一個(gè)insertContact方法: 
package org.ourpioneer.contact.dao;  
import java.util.Map;  
import org.ourpioneer.contact.bean.Contact;  
public interface ContactDAO {  
    public Contact getContactById(Map<Object, Object> parameterMap);  
    public int insertContact(Contact contact);  
    public int insertContact(Map<Object, Object> parameterMap);  
}  
  然后編寫(xiě)實(shí)現(xiàn)代碼:
public int insertContact(Map<Object, Object> parameterMap) {  
        return getSqlMapClientTemplate().update("insertContact", parameterMap);  
    } 
 和之前的完全類似,只是參數(shù)不同,就是重載了一個(gè)方法而已。下面是Service方法: 
public int insertContact(String name, String gender, String mobile,  
        String address) {  
    Map<Object, Object> parameterMap = new ParameterMap("NAME", name,  
            "GENDER", gender, "MOBILE", mobile, "ADDRESS", address);  
    return getContactDAO().insertContact(parameterMap);  
}  
    這里我們將傳入的四個(gè)參數(shù)重新構(gòu)造成一個(gè)ParameterMap類型的變量,為什么要在Service中完成這步操作,就是出于事務(wù)捆綁的操作。在Service層我們將操作視為一個(gè)具體的業(yè)務(wù),那么它可能向下要調(diào)用多個(gè)DAO來(lái)向不同數(shù)據(jù)表進(jìn)行操作,那么在這層構(gòu)造數(shù)據(jù)調(diào)用各自的DAO完成SQL操作是最合理的,所以我們將數(shù)據(jù)的構(gòu)造操作放在了Service層來(lái)進(jìn)行,之后重新改寫(xiě)測(cè)試代碼: 
package org.ourpioneer.contact;  
import org.ourpioneer.contact.service.ContactService;  
import org.slf4j.Logger;  
import org.slf4j.LoggerFactory;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
public class App {  
    private static final Logger logger = LoggerFactory.getLogger(App.class);  
    public static void main(String[] args) {  
        ApplicationContext context = new ClassPathXmlApplicationContext(  
                "beans.xml");  
        ContactService contactService = (ContactService) context  
                .getBean("contactService");  
        // Contact contact = contactService.getContactById(1);  
        // Contact contact = new Contact("Tom", "male", "15940990001",  
        // "Dalian");  
        int recordsOfUpdates = contactService.insertContact("Tom", "male","15940990001", "Dalian");  
        logger.info("{}", recordsOfUpdates);  
    }  
}  
     我們?nèi)匀坏玫搅烁乱恍袛?shù)據(jù)的結(jié)果,可以看到數(shù)據(jù)庫(kù)中就又多了一條數(shù)據(jù)。 
     下面是數(shù)據(jù)更新操作,也就是SQL的update操作,還是先來(lái)編寫(xiě)SQL語(yǔ)句: 
<update id="updateContactById" parameterClass="contact">  
    update contact   
    set NAME=#name:VARCHAR#,GENDER=#gender:VARCHAR#,MOBILE=#mobile:VARCHAR#,ADDRESS=#address:VARCHAR#  
    where ID=#id:LONG#  
</update>  
 可以看出,這里也是使用Bean的方式來(lái)進(jìn)行更新,那么DAO代碼如下: 
public int updateContactById(Contact contact) {  
    return getSqlMapClientTemplate().update("updateContactById", contact);  
}  
然后是Service代碼: 
public int updateContact(Contact contact) {  
    return getContactDAO().updateContactById(contact);  
}  
 而測(cè)試時(shí),我們是先將一條記錄給查出來(lái),之后更改幾個(gè)屬性,再給更新數(shù)據(jù),那么測(cè)試代碼為: 
public class App {  
    private static final Logger logger = LoggerFactory.getLogger(App.class);  
    public static void main(String[] args) {  
        ApplicationContext context = new ClassPathXmlApplicationContext(  
                "beans.xml");  
        ContactService contactService = (ContactService) context  
                .getBean("contactService");  
        Contact contact = contactService.getContactById(2);  
        System.out.println(contact);  
        contact.setMobile("15900000001");  
        contact.setAddress("Beijing");  
        int recordsOfUpdates = contactService.updateContact(contact);  
        logger.info("{}", recordsOfUpdates);  
    }  
 運(yùn)行測(cè)試代碼,我們得到如下結(jié)果: 

 之后查看數(shù)據(jù)庫(kù),發(fā)現(xiàn)ID為2的記錄已經(jīng)更改了: 

    和插入操作一樣,我們還可以使用ParameterMap的方式來(lái)實(shí)現(xiàn)更新,應(yīng)用場(chǎng)景也是和前面類似的。這里就不再給出演示了,直接看最后一個(gè)操作,就是刪除操作。刪除應(yīng)該是最簡(jiǎn)單的一種操作了,我們編寫(xiě)一個(gè)SQL: 
<delete id="deleteContactById" parameterClass="parameterMap">  
    delete from contact where ID=#ID:LONG#  
</delete>  
  我們使用的是parameterMap作為傳入的參數(shù)類型,那么DAO代碼如下: 
public int deleteContactById(Map<Object, Object> parameterMap) {  
    return getSqlMapClientTemplate().update("deleteContactById", parameterMap);  
} 
  在Service中,我們構(gòu)造出parameerMap對(duì)象: 
public int deleteContactById(long id) {  
    Map<Object, Object> parameterMap = new ParameterMap("ID", id);  
    return getContactDAO().deleteContactById(parameterMap);  
} 
  下面是測(cè)試代碼,我們直接指定要?jiǎng)h除的記錄ID即可: 
public class App {  
    private static final Logger logger = LoggerFactory.getLogger(App.class);  
  
    public static void main(String[] args) {  
        ApplicationContext context = new ClassPathXmlApplicationContext(  
                "beans.xml");  
        ContactService contactService = (ContactService) context  
                .getBean("contactService");  
        int recordsOfUpdates = contactService.deleteContactById(3);  
        logger.info("{}", recordsOfUpdates);  
    }  
}  
    運(yùn)行測(cè)試代碼,我們可以看到成功更新了一條記錄,也就是將第三條記錄刪除,那么再看看數(shù)據(jù)庫(kù),也就只有兩條記錄了。 
    本部分內(nèi)容也就全部介紹完了。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)