iBATIS系统学习笔记三

【路由交换】思科5506防火墙区域互通 思科 5506 inside outside dmz 互通 阅读详情

目录:
学习笔记零 - 起源
学习笔记一 - 概念与入门
学习笔记二 - 基础配置
学习笔记四 - 技巧与实践


高级特性:使用高速缓存提高性能,iBATIS数据访问对象,DAO使用进阶,扩展iBATIS


使用高速缓存提高性能

内容
- 高速缓存理念
- 高速缓存配置
- 高速缓存策略

1 一个简单的iBATIS高速缓存示例

iBATIS的高速缓存机制完全基于配置的。

<cacheModel id="categoryCache" type="MEMORY">
    <flushOnExecute statement="insert"/>
    <flushOnExecute statement="update"/>
    <flushOnExecute statement="delete"/>
    <property name="reference-type" value="WEAK"/>
</cacheModel>

<select id="getCategory" parameterClass="Category" resultClass="Category" cacheModel="categoryCache">
    SELECT *
    FROM Category
    WHERE categoryId=#categoryId#
</select>

MEMORY:高速缓存类型,直接将查询结果存储在内存中。
flushOnExecute:当某个特定高速缓存被访问时,其存储结果将被清除。

2 iBATIS高速缓存的理念

高速缓存通常用来存储那些长效的、不会发生改变的数据。高速缓存也可以用于那些可修改的对象。
此处的难点是,需要保证请求的数据是否存在于当前高速缓存中,如果不存在,需要自己将它保存到高速缓存中。需要保证高速缓存中的数据是否已经过时。
iBATIS的思想是建立SQL语句到对象间的映射,而不是数据库表到对象间的映射。

3 高速缓存模型

高速缓存模型时一种高速缓存配置。高速缓存通过标签<cacheModel>定义,包含以下属性:
- id : 必须,唯一ID用来调用。
- Type:必须,高速缓存类型,MEMORY、LRU、FIFO和OSCACHE。
- readOnly:可选。
- serialize:可选,表示是否进行深复制。

3.1 type属性

iBATIS提供了4个默认的高速缓存实现
- MEMORY : 将缓存数据保存在内存中,直到垃圾收集器将它移除。
- FIFO: 这个模型中,高速缓存的数据量是固定的,使用先进先出(first in first out)算法来移除高速缓存中的数据。
- LRU:这个模型的数据量也是固定的,使用最近最少使用算法来移除高速缓存中的数据(least recently used)。
- OSCACHE:这个模型使用OpenSymphony高速缓存

3.2 readOnly属性

该属性仅仅是一个为高速缓存模型提供指令的指示器,用于告诉高速缓存模型应该如何检索和保存已高速缓存对象。当设置为true时,那高速缓存模型就会返回某个对象引用。

3.3 serialize属性

serialize属性用于指示高速缓存对象该如何返回,当属性为true时,高速缓存所请求的每个对象都将作为一个深副本返回。

3.4 联合使用readOnly属性和serialize属性

readOnlyserialize结果原因
TrueFalse可以快速地检索出已高速缓存的对象。返回一个共享的实例。
FalseTrue返回一个缓存对象的深副本
FalseFalse警告高速缓存仅仅同调用线程会话的生命周期有关,且不能被其他线程调用。
TrueTure同False,True组合一样。

4 如何使用高速缓存模型中的标签

4.1 高速缓存的清除

高速缓存具有两个标签 <flushOnExecute> 和<flushInterval>标签

<flushOnExecute>标签
定义查询已映射语句,其执行将引起高速缓存的清除。

<sqlMap namespace="Category"><cacheModel id="categoryCache" type="MEMORY"><flushOnExecute statement="Category.insert"/></cacheModel><select id="getCategory" parameterClass="Category" resultClass="Category" cacheModel="categoryCache">
        SELECT *
        FROM Category
        WHERE parentCategoryId=#categoryId#
    </select><insert id="insert" parameterClass="Category" >
        INSERT INTO Category
        (title,description,sequence)
        VALUES
        (#title#,#description#,#sequence#)
    </insert></sqlMap>

<flushInterval>标签
定义一个时间间隔,高速缓存将以此间隔定期清除
属性:hours,minutes,seconds,millseconds,都是可选项。

示例:

<sqlMap namespace="Category"><cacheModel id="categoryCache" type="MEMORY"><flushInterval hours= "12" /></cacheModel><select id="getCategory" parameterClass="Category" resultClass="Category" cacheModel="categoryCache">
    SELECT *
    FROM Category
    WHERE parentCategoryId=#categoryId#
    </select></sqlMap>

4.2 设置高速缓存模型实现的特性

高速缓存模型是iBATIS框架中的组件,他允许用户自己定制,因此必须有一种方式能够为这些组件提供任意的值。<property>标签就是用来完成此任务的。
<property>标签的属性:Name,value

5 高速缓存模型的类型

高速缓存模型具备MEMORY,LRU,FIFO,OSCACHE

5.1 MEMORY

MEMORY高速远程基于引用,具备WEAK,SOFT,STRONG三种引用类型。
例子:

<cacheModel id="categoryCache" type="MEMORY">
    <flushInterval hours="24"/>
    <flushOnExecute statement="insert"/>
    <flushOnExecute statement="update"/>
    <flushOnExecute statement="delete"/>
    <property name="reference-type" value="WEAK"/>
</cacheModel>

5.2 LRU

LRU类型的高速缓存使用最近最少使用策略来管理高速缓存。
LRU的propery标签唯一能指定的是size,用来指定高速缓存中的对象的最大数目。

<cacheModel id="categoryCache" type="LRU">
    <flushInterval hours="24"/>
    <flushOnExecute statement="insert"/>
    <flushOnExecute statement="update"/>
    <flushOnExecute statement="delete"/>
    <property name="size" value="200"/>
</cacheModel>

LRU高速缓存对于那些数据的不同子集(subsets of data)都用在某段时间内的应用程序非常有用

5.3 FIFO

FIFO高速缓存模型采用先进先出的管理策略。唯一需要指定的property也是size。

<cacheModel id="categoryCache" type="FIFO">
    <flushInterval hours="24"/>
    <flushOnExecute statement="insert"/>
    <flushOnExecute statement="update"/>
    <flushOnExecute statement="delete"/>
    <property name="size" value="1000"/>
</cacheModel>

5.4 OSCACHE

该高速缓存模型采用了OpenSymphony公司的产品OSCache2.0,需要JAR文件依赖以及配置文件。

5.5 自己的高速缓存模型

需要了解两点,1,高速缓存模型实际上都是CacheController接口的实现。
2,the names are type aliases that map to the fully qualified names of those implementations.

6 确定高速缓存策略

当需要缓存只读的长效数据时,我们可以使用LRU策略。比如购物车的类别。

如果需要缓存的对象易变,就要好好考虑是否使用高速缓存技术,如果需要使用,可以用MEMORY模式,并且设置reference-type为WEAK

旧的静态数据,比如统计数据,可以用FIFO模式

iBATIS数据访问对象

内容
- DAO基本原理
- 配置
- SQLMapDAO示例

DAO模式用于隐藏API格子的独特实现。

1 iBATIS DAO的简单示例

iBATIS Dao:
![Alt text](./iBATIS DAO.png)

1.1 Dao.xml 配置文件

要配置DaoManager,必须从一个XML配置文件开始,该文件通常被命名为dao.xml

dao.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE daoConfig
PUBLIC
"-//ibatis.apache.org//DTD DAO Configuration 2.0//EN"
"http://ibatis.apache.org/dtd/dao-2.dtd">
<daoConfig>
    <context id="example">
        <transactionManager type="SQLMAP">
            <property name="SqlMapConfigResource" value="examples/SqlMapConfig.xml"/>
        </transactionManager>
        <dao interface="examples.dao.AccountDao" implementation="examples.dao.impl.AccountDao"/>
    </context>
</daoConfig>

1.2 创建DaoManager

public class DaoService {
    private static DaoManager daoManager;
    public static synchronized DaoManager getDaoManager(){
        String daoXmlResource = "dao.xml";
        Reader reader;
        if (null == daoManager){
            try {
                reader =
                Resources.getResourceAsReader(daoXmlResource);
                daoManager = DaoManagerBuilder.buildDaoManager(reader);
                return daoManager;
            } catch (IOException e) {
        throw new RuntimeException( "Unable to create DAO manager.", e);
            }
        } else {
            return daoManager;
        }
    }
    public static Dao getDao(Class interfaceClass){
        return getDaoManager().getDao(interfaceClass);
    }
}

要获取Dao可以直接调用以下代码:

AccountDao accountDao = (AccountDao) DaoService.getDao(AccountDao.class);

2 配置DAO

使用iBATIS DAO框架时,唯一需要的配置文件就是dao.xml文件。

2.1 <properties> 元素

他用来指定一个特性文件,该文件所列出的特性可以通过${name}语法使用在DAO层配置文件中

2.2 < context > 元素

一个DAO的上下文是指一组相关的DAO配置信息和一组DAO的实现。通过配置context可以很容易的将多个数据库访问配置集中。

2.3 < transactionManager> 元素

事务管理器,iBATIS DAO框架提供了7种不同的事务管理器:EXTERNAL,HIBERNATE,JDBC,JTA,OJB,SQLMAP,TOPLINK。
- EXTERNAL事务管理器:最易配置最难使用,需要自行对应用程序的所有事务负责
- HIBERNATE:易配置,任何名字以class开头的特性读背认为是应该被Hibernate管理的类,并将其添加到用于构建会话工厂的配置对象中。map.开头的特性被认为是映射文件
- JDBC:最难配置,DataSource特性是必须的,取值有SIMPLE,DBCP或JNDI。SIMPLE - 是iBATISD SimpleDataSource接口的实现。DBCP - Jakarta CDBCP。JNDI数据源 - 最简单的数据源。
- JTA事务管理器:允许为多个数据库提供分布式事务管理。
- OJB:O/RM工具
- SQLMAP:最常用的事务管理器。
- TOPLINK:另一个O/RM工具
- 自己的或其他的事务管理器:通过type属性指定类名

2.4 DAO元素

DAO仅有2个属性,interface和implementation。

<dao interface="com.mycompany.system.dao.AccountDao" implementation= "com.mycompany.system.dao.impl.AccountDaoImpl"/>

3 配置技巧

3.1 多个服务器

样例:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE daoConfig
PUBLIC
"-//ibatis.apache.org//DTD DAO Configuration 2.0//EN"
"http://ibatis.apache.org/dtd/dao-2.dtd">
<daoConfig>
    <properties resource="server.properties"/>
    <context>
        <transactionManager type="JDBC">
            <property name="DataSource" value="SIMPLE"/>
            <property name="JDBC.Driver" value="${jdbcDriver}" />
            <property name="JDBC.ConnectionURL" value="${jdbcUrl}" />
            <property name="JDBC.Username" value="${jdbcUser}" />
            <property name="JDBC.Password" value="${jdbcPassword}" />
            <property name="JDBC.DefaultAutoCommit" value="${jdbcAutoCommit}" />
        </transactionManager>
        <dao interface="..." implementation="..."/>
    </context>
</daoConfig>

所有的属性值保存在server.properties里。

3.2 多种数据库方言

和上例方法一样,可以

<dao interface="com.company.system.dao.AccountDao" implementation="${impl}.AccountDaoImpl"/>

3.3 运行时配置更改

public static DaoManager getDaoManager(Properties props){
    String daoXml = "/org/apache/mapper2/examples/Dao.xml";
    Reader reader;
    DaoManager localDaoManager;
    try {
        reader = Resources.getResourceAsReader(daoXml);
        localDaoManager =
        DaoManagerBuilder.buildDaoManager(reader, props);
    } catch (IOException e) {
    throw new RuntimeException("Unable to create DAO manager.", e);
    }
    return localDaoManager;
}

4 基于SQL Map的DAO实现示例

DAO就是关于如何在接口后面隐藏实际的数据访问实现。
构造接口:

public interface AccountDao {
    public void insert(Account account);
    public void update(Account account);
    public int delete(Account account);
    public int delete(Integer accountId);
    public List<Account> getAccountListByExample(Account account);
    public List<Map<String, Object>> getMapListByExample(Account account);
    public List<IdDescription> getIdDescriptionListByExample(Account account);
    public Account getById(Integer accountId);
    public Account getById(Account account);
}

4.1 配置iBATIS DAO

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE daoConfig
PUBLIC
"-//ibatis.apache.org//DTD DAO Configuration 2.0//EN"
"http://ibatis.apache.org/dtd/dao-2.dtd">
<daoConfig>
    <context id="sqlmap">
        <transactionManager type="SQLMAP">
            <property name="SqlMapConfigResource" value="SqlMapConfig.xml"/>
        </transactionManager>
        <dao interface="com.mycompany.system.dao.AccountDao"
implementation= "com.mycompany.system.dao.sqlmap.AccountDaoImpl"/>
</context>
</daoConfig>

4.2 创建DaoManager实例

private DaoManager getDaoManager() {
    DaoManager tempDaoManager = null;
    Reader reader;
    try {
        reader = Resources.getResourceAsReader("Dao.xml");
        tempDaoManager = DaoManagerBuilder.buildDaoManager(reader);
    } catch (Exception e) {
        e.printStackTrace();
        fail("Cannot load dao.xml file.");
    }
    return tempDaoManager;
}

4.3 定义事务管理器

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMapConfig
PUBLIC
"-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
    <properties resource="SqlMapConfig.properties" />
    <settings
        errorTracingEnabled="true"
        cacheModelsEnabled="true"
        enhancementEnabled="true"
        lazyLoadingEnabled="true"
        maxRequests="32"
        maxSessions="10"
        maxTransactions="5"
        useStatementNamespaces="true"
    />
    <transactionManager type="JDBC" >
        <dataSource type="SIMPLE">
            <property name="JDBC.Driver" value="${driver}"/>
            <property name="JDBC.ConnectionURL" value="${connectionUrl}"/>
            <property name="JDBC.Username" value="${username}"/>
            <property name="JDBC.Password" value="${password}"/>
        </dataSource>
    </transactionManager>
    <sqlMap resource= "com/mycompany/system/dao/sqlmap/Account.xml" />
</sqlMapConfig>

4.4 加载映射

<?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 namespace="Account">
    <typeAlias alias="Account" type="${BeanPackage}.Account" />
    <typeAlias alias="IdDescription" type="${BeanPackage}.IdDescription" />
    <insert id="insert" parameterClass="Account">
        <selectKey keyProperty="accountId" resultClass="int">
            SELECT nextVal('account_accountid_seq')
        </selectKey>
            INSERT INTO Account (
                accountId,
                username,
                password,
                firstName,
                lastName,
                address1,
                address2,
                city,
                state,
                postalCode,
                country
            ) VALUES(
                #accountId#,
                #username:varchar#,
                #password:varchar#,
                #firstName:varchar#,
                #lastName:varchar#,
                #address1:varchar#,
                #address2:varchar#,
                #city:varchar#,
                #state:varchar#,
                #postalCode:varchar#,
                #country:varchar#
            )
    </insert>
    <!-- delete & update-->

    <sql id="allFields">
        accountId as "accountId",
        username,
        password,
        firstName as "firstName",
        lastName as "lastName",
        address1,
        address2,
        city,
        state,
        postalCode as "postalCode",
        country
    </sql>

    <sql id="whereByExample">
        <dynamic prepend=" where ">
            <isNotEmpty property="city">
                city like #city#
            </isNotEmpty>
            <isNotNull property="accountId" prepend=" and ">
                accountId = #accountId#
            </isNotNull>
        </dynamic>
    </sql>

    <sql id="getByExample">
        select
        <include refid="allFields" />
            from Account
        <include refid="whereByExample" />
    </sql>

    <select id="getAccountListByExample"
        resultClass="Account">
        <include refid="getByExample" />
    </select>

    <select id="getMapListByExample" resultClass="hashmap">
        <include refid="getByExample" />
    </select>
</sqlMap>

4.5 DAO实现编码

public class AccountDaoImpl extends SqlMapDaoTemplate implements AccountDao {
    public AccountDaoImpl(DaoManager daoManager) {
        super(daoManager);
    }

    public Integer insert(Account account) {
        return (Integer) insert("Account.insert", account);
    }

    public int update(Account account) {
        return update("Account.update", account);
    }

    public int delete(Account account) {
        return delete(account.getAccountId());
    }

    public int delete(Integer accountId) {
        return delete("Account.delete", accountId);
    }

    public List<Account> getAccountListByExample(Account account) {
    return queryForList("Account.getAccountListByExample",account);
    }

    public List<Map<String, Object>> getMapListByExample(Account account) {
    return queryForList("Account.getMapListByExample",account);
    }

    public List<IdDescription> getIdDescriptionListByExample(Account account) {
return queryForList("Account.getIdDescriptionListByExample",account);
    }

    public Account getById(Integer accountId) {
        return (Account)queryForObject("Account.getById", accountId);
    }

    public Account getById(Account account) {
        return getById(account.getAccountId());
    }
}

注意SqlMapDaoTemplate 这个父类


DAO使用进阶

内容:
- DAO的更多样例
- 使用Spring替代iBATIS
- 从头开始创建DAO层

1 不是基于SQLMap的DAO实现

1.1 Hibernate版本的DAO实现

1、定义DAO上下文

<context id="hibernate">
    <transactionManager type="HIBERNATE">
        <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
        <property name="hibernate.connection.url" value="jdbc:postgresql:ibatisdemo" />
        <property name="hibernate.connection.username" value="ibatis" />
        <property name="hibernate.connection.password" value="ibatis" />
        <property name="hibernate.connection.pool_size" value="5" />
        <property name="hibernate.dialect" value= "net.sf.hibernate.dialect.PostgreSQLDialect" />
        <property name="map.Account" value= "${DaoHomeRes}/hibernate/Account.hbm.xml" />
    </transactionManager>
    <dao interface="${DaoHome}.AccountDao" implementation= "${DaoHome}.hibernate.AccountDaoImpl"/>
</context>

2、映射Account表

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
    <class name="org.apache.mapper2.examples.bean.Account" table="Account">
        <id name="accountId" type="int" column="accountid">
            <generator class="sequence">
                <param name="sequence">account_accountid_seq</param>
            </generator>
        </id>
        <property name="username" />
        <property name="password" />
        <property name="firstName" />
        <property name="lastName" />
        <property name="address1" />
        <property name="address2" />
        <property name="city" />
        <property name="state" />
        <property name="postalCode" />
        <property name="country" />
    </class>
</hibernate-mapping>

3、实际的DAO实现

public class AccountDaoImpl extends HibernateDaoTemplate implements AccountDao {
    private static final Log log =
    LogFactory.getLog(AccountDaoImpl.class);
    public AccountDaoImpl(DaoManager daoManager) {
        super(daoManager);
        if(log.isDebugEnabled()){
            log.debug("Creating instance of " + getClass());
        }
    }

    public Integer insert(Account account) {
        try {
            getSession().save(account);
        } catch (HibernateException e) {
            log.error(e);
            throw new DaoException(e);
        }
        return account.getAccountId();
    }
    //...

1.2 JDBC版本的DAO实现

    <context id="jdbc">
        <transactionManager type="JDBC">
            <property name="DataSource" value="SIMPLE"/>
            <property name="JDBC.Driver" value="org.postgresql.Driver" />
            <property name="JDBC.ConnectionURL" value="jdbc:postgresql:ibatisdemo" />
            <property name="JDBC.Username" value="ibatis" />
            <property name="JDBC.Password" value="ibatis" />
            <property name="JDBC.DefaultAutoCommit" value="true" />
        </transactionManager>
    <dao interface="${DaoHome}.AccountDao" implementation="${DaoHome}.jdbc.AccountDaoImpl"/>
    </context>

实现代码量远远多过Hibernate以及iBATIS


2 为其他数据源使用DAO模式

2.1 为LDAP使用DAO

LDAP是一个用于存储具有层次结构的数据的强大工具,经常被网络管理员用于追踪用户,组成员以及从属关系。
LDAP术语
构成LDAP目录的基本单元被称为记录项(entry),可以包含称为属性的数据,或者其他记录项,或者两者同时包含。每个记录项只有一个父记录项,并且被一个DN唯一标示。
存储在LDAP目录中的数据由若干属性组成,一个属性就是一个名/值对,实际上与Java中的Map非常相似。

从Java到LDAP记录项之间的映射

Bean特性LDAP属性
userIduid
mailmail
descriptiondescription
lastNamesn
firstNamegivenName

硬编码方式映射:

private Attributes getAttributes(Contact contact){
    Attributes returnValue = new BasicAttributes();
    returnValue.put("mail", contact.getMail());
    returnValue.put("uid", contact.getUserId());
    returnValue.put("objectClass", "inetOrgPerson");
    returnValue.put("description", contact.getDescription());
    returnValue.put("sn", contact.getLastName());
    returnValue.put("cn", contact.getUserId());
    returnValue.put("givenName", contact.getFirstName());
    return returnValue;
}

private Contact getContact(Attributes attributes) {
    Contact contact = new Contact();
    contact.setDescription(getAttributeValue(attributes, "description"));
    contact.setLastName(getAttributeValue(attributes, "sn"));
    contact.setFirstName(getAttributeValue(attributes, "givenName"));
    contact.setMail(getAttributeValue(attributes, "mail"));
    contact.setUserId(getAttributeValue(attributes, "uid"));
    return contact;
}

private String getAttributeValue(Attributes attributes, String attrID{
        Attribute attribute = attributes.get(attrID);
    try {
        return (null==attribute?"":(String)attribute.get());
    } catch (NamingException e) {
        throw new DaoException(e);
    }
}

Attributes接口来自sun的JDK的JNDI,使用BasicAttributes类实现。

获取目录上下文:

private DirContext getInitialContext() {
    DirContext ctx = null;
    try {
        ctx = new InitialDirContext(env);
    } catch (NamingException e) {
        log.error("Exception getting initial context", e);
        throw new DaoException(e);
    }
        return ctx;
}

实现方法:

public Contact getById(String id) {
    DirContext ctx = getInitialContext();
    Attributes attributes;
    try {
    attributes = ctx.getAttributes(getDn(id));
    } catch (NamingException e) {
    throw new DaoException(e);
    }
    return getContact(attributes);
}

2.2 为Web服务使用Dao

bean和接口:

public class SearchResult {
    private String url;
    private String summary;
    private String title;
    // getters and setters omitted...
}
public interface WebSearchDao {
    List<SearchResult> getSearchResults(String text);
}

dao实现:

public class GoogleDaoImpl implements WebSearchDao {
    private String googleKey;
    public GoogleDaoImpl(){
        this("insert-your-key-value-here");
    }

    public GoogleDaoImpl(String key){
        this.googleKey = key;
    }

    public List<SearchResult> getSearchResults(String text){
        List<SearchResult> returnValue = new
        ArrayList<SearchResult>();
        GoogleSearch s = new GoogleSearch();
        s.setKey(googleKey);
        s.setQueryString(text);
        try {
            GoogleSearchResult gsr = s.doSearch();
            for (int i = 0; i < gsr.getResultElements().length;i++){
                GoogleSearchResultElement sre =
                gsr.getResultElements()[i];
                SearchResult sr = new SearchResult();
                sr.setSummary(sre.getSummary());
                sr.setTitle(sre.getTitle());
                sr.setUrl(sre.getURL());
                returnValue.add(sr);
            }
                return returnValue;
        } catch (GoogleSearchFault googleSearchFault) {
            throw new DaoException(googleSearchFault);
        }
    }
}

3 使用Spring DAO

public class AccountDaoImplSpring extends SqlMapClientTemplate implements AccountDao{
    public Integer insert(Account account) {
        return (Integer) insert("Account.insert", account);
        delete(account.getAccountId());
    }

    public int delete(Integer accountId) {
        return delete("Account.delete", accountId);
    }

    public List<Account> getAccountListByExample(Account account) {
    return queryForList("Account.getAccountListByExample",account);
    }

    public List<Map<String, Object>> getMapListByExample(Account account) {
    return queryForList("Account.getMapListByExample",account);
    }

    public List<IdDescription> getIdDescriptionListByExample(Account account) {
    return queryForList("Account.getIdDescriptionListByExample", account);
}

    public Account getById(Integer accountId) {
        return (Account) queryForObject("Account.getById",accountId);
    }

    public Account getById(Account account) {
        return (Account) queryForList("Account.getById",account);
    }
}

扩展类不同SqlMapClientTemplate

4 创建自己的DAO层

创建一个DAO层,需要依次完成3件事情:
1、从实现中分离出接口。
2、用一个可外部配置的工厂来解耦实现。
3、提供事务管理和数据库连接管理。

4.1 从实现中分离出接口

4.2 创建一个工厂以解耦

如果不使用工厂,很有可能代码如下:
AccountDao accountDao = new AccountDaoImpl();
这样在通一个地方,同时引用了接口与实现,就失去了分离的价值。

更好的模式:
AccountDao accountDao = (AccountDao)DaoFactory.get(AccountDao.class);
这样代码就从实现中解耦,DaoFactory会处理一切,产生一个AccountDao接口。

DAO工厂实现:

public class DaoFactory {
    private static DaoFactory instance = new DaoFactory();
    private final String defaultConfigLocation = "DaoFactory.properties";
    private Properties daoMap;
    private Properties instanceMap;
    private String configLocation = System.getProperty("dao.factory.config",defaultConfigLocation);
    private DaoFactory(){
        daoMap = new Properties();
        instanceMap = new Properties();
        try {
            daoMap.load(getInputStream(configLocation));
        } catch (IOException e) {
        throw new RuntimeException(e);
        }
    }

    private InputStream getInputStream(String configLocation){
        return T    hread.currentThread().getContextClassLoader().getResourceAsStream(conf  igLocation);
    }

    public static DaoFactory getInstance() {
        return instance;
    }

    public Object getDao(Class daoInterface){
        if (instanceMap.containsKey(daoInterface)) {
            return instanceMap.get(daoInterface);
        }
        return createDao(daoInterface);
    }

    private synchronized Object createDao(Class daoInterface) {
        Class implementationClass;
        try {
            implementationClass = Class.forName((String)
            daoMap.get(daoInterface));
            Object implementation = implementationClass.newInstance();
            instanceMap.put(implementationClass, implementation);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return instanceMap.get(daoInterface);
    }
}

扩展iBATIS

内容
- 自定义类型处理器
- 高速缓存控制器
- 自定义数据源

1 可插拔组件的设计

一个可插拔组件的设计通常由3部分组成:接口实现工厂

可扩展的功能组件描述
TypeHandlerCallback实现自己的类型处理逻辑,以便处理非标准数据库、驱动程序和数据类型
CacheController用自己的高速缓存代码实现CacheController
DataSourceFactory实现任何标识的JDBC DataSource实现
TransactionConfig实现一个自定义事务管理器

2 使用自定义类型处理器

2.1 实现自定义类型处理器

要实现自定义的TypeHandler,只需要实现部分功能即可,此功能定义在一个被称为TypeHandlerCallback的简单接口中。

TypeHandlerCallback:

public interface TypeHandlerCallback {
    public void setParameter(ParameterSetter setter, Object parameter) throws SQLException;
    public Object getResult(ResultGetter getter) throws SQLException;
    public Object valueOf(String s);
}

如果一个数据库用YES和NO来代表布尔型,我们设计这样一个映射类:

public class User {
    private int id;
    private String username;
    private String passwordHashcode;
    private boolean enabled;
    // assume compliant JavaBeans properties
    // (getters/setters) below
}

enabled在数据库中是一个VARCHAR类型,存储YES和NO。

2.2 创建TypeHandlerCallback

骨架:

public class YesNoTypeHandlerCallback implements TypeHandlerCallback {
    private static final String YES = "YES";
    private static final String NO = "NO";
    public void setParameter(ParameterSetter setter, Object parameter) throws SQLException {}
    public Object getResult(ResultGetter getter) throws SQLException {}
    public Object valueOf(String s) {}
}

设置参数
如果布尔型为true则是YES,false则是NO,为空则抛出异常

private String booleanToYesNo(Boolean b) {
    if (b == null) {
        throw new IllegalArgumentException ("Could not convert null to a boolean value. " + "Valid arguments are 'true' and 'false'.");
    } else if (b.booleanValue()) {
        return YES;
    } else {
        return NO;
    }
}

setParameter

public void setParameter(ParameterSetter setter, Object parameter) throws SQLException {
    setter.setString(booleanToYesNo((Boolean) parameter));
}

获取结果

private Boolean yesNoToBoolean(String s) {
    if (YES.equalsIgnoreCase(s)) {
        return Boolean.TRUE;
    } else if (NO.equalsIgnoreCase(s)) {
        return Boolean.FALSE;
    } else {
        throw new IllegalArgumentException (
            "Could not convert " + s +
            " to a boolean value. " +
            "Valid arguments are 'YES' and 'NO'.");
    }
}

getResult

public Object getResult(ResultGetter getter) throws SQLException {
    return yesNoToBoolean(getter.getString());
}

处理空值
当数据库中使用一个可以为空的列,但却不需要对象模型中的可为空类型。

<result property="enabled" column="Enabled" nullValue="NO"/>

valueOf

public Object valueOf(String s) {
    return yesNoToBoolean(s);
}

2.3 注册TypeHandlerCallback以供使用

  • 在SqlMapConfig.xml文件中注册,以使它全局可用。
  • 在某个SqlMap.xml文件中注册,以使它局部可用。
  • 专门针对某个结果映射或参数映射进行注册。

全局使用:

<typeHandler callback="com.domain.package.YesNoTypeHandlerCallback" javaType="boolean" jdbcType="VARCHAR" />

3 使用CacheController

iBATIS提供了一个成为CacheController的接口,以允许你实现一个完全属于自己的自定义高速缓存解决方案。

public interface CacheController {
    public void configure(Properties props);
    public void putObject(CacheModel cacheModel, Object key, Object object);
    public Object getObject(CacheModel cacheModel, Object key);
    public Object removeObject(CacheModel cacheModel, Object key);
    public void flush(CacheModel cacheModel);
}

4 配置iBATIS不支持的DataSource

要配置一个新的DataSource,需要为iBATIS提供一个工厂,该工厂可以为框架提供DataSource实例。

public interface DataSourceFactory {
    public void initialize(Map map);
    public DataSource getDataSource();
}

简单的DataSource实现:

public class SimpleDataSourceFactory implements DataSourceFactory {
    private DataSource dataSource;
    public void initialize(Map map) {
        dataSource = new SimpleDataSource(map);
    }
    public DataSource getDataSource() {
        return dataSource;
    }
}

5 定制事务管理

iBATIS提供TransactionConfig和Transaction接口,来创建自己的事务适配器。

5.1 理解TransactionConfig接口

public interface TransactionConfig {
    public void initialize(Properties props) throws SQLException, TransactionException;
    public Transaction newTransaction(int transactionIsolation) throws SQLException, TransactionException;
    public int getMaximumConcurrentTransactions();
    public void setMaximumConcurrentTransactions(int max);
    public DataSource getDataSource();
    public void setDataSource(DataSource ds);
}

5.2 Transaction接口

public interface Transaction {
    public void commit() throws SQLException,TransactionException;
    public void rollback() throws SQLException,TransactionException;
    public void close() throws SQLException,TransactionException;
    public Connection getConnection() throws SQLException,TransactionException;
}

FCN---训练cityspaces 未经允许,不要随意转载! 最近想试试用FCN训练自己的数据集,想想标注是一件很费劲的事,于是就想到了用其他库里的数据,这里选用了cityspaces,默认已经配置好FCN. 1、下载cityspaces https://www.cityscapes-dataset.com/ 需要注册一个账号 cityspaces包含2... 阅读详情

相关推荐

基于STM32设计的环境监测系统(华为云IOT)_300

随着空气污染问题日益严峻,环境空气质量的监测变得愈加重要。为了解决这一问题,本项目设计并实现了一款基于STM32的空气质量监测设备,能够实时监测空气中的温湿度、二氧化碳浓度和甲醛浓度,并通过OLED显示屏展示数据。此外,设备支持通过WIFI模块将数据上传至云端,用户可以通过手机APP或Windows上位机查看实时数据。设备采用MQTT协议与华为云IOT物联网服务器进行数据通信,确保数据的实时性和可靠性。本项目还结合了低功耗设计和高灵敏度传感器,使得设备能够高效稳定地运行,并实现远程监控功能。

643

ibatis的cacheModel刷新失效问题

我在项目架构中为了达到减少配置的目的,将ibatis的*sql.xml文件路径配置放到了spring里面(spring2.5以上版本支持)   class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">     classpath:sql-map-config.xml           classpath:/sql/*/*S

songry的专栏 2286

Spec Kit:GitHub 官方推出的规范驱动开发工具包,让 AI 编程真正可控、高效、高质量

先明确“做什么”和“为什么”,再考虑“如何做”。它通过一系列标准化命令(如/specify/plan/implement可验证的功能规格(spec)可执行的技术方案(plan)可追溯的开发任务(tasks)高质量的实现代码(code)最终实现“规范即代码,代码即规范”的闭环。📌项目地址许可证:MIT(完全开源,欢迎贡献)Spec Kit 代表了 GitHub 对AI 原生开发(AI-Native Development)AI 不应替代开发者,而应放大开发者的意图。

lpfasd123的博客 1623

ibatis的四种高速缓存模型

[color=red]1.MEMORY[/color] MEMORY高速缓存是一种基于引用的高速缓存,高速缓存中的每一个对象都被赋予一个引用类型。 MEMORY的种引用类型: (1)[color=violet]WEAK[/color]: 将很快的废弃已高速缓存的对象。 (2)[color=violet]SOFT[/color]: 满足内存约束的情况下尽可能的保存高速缓存对...

黑色笔记 178

Ibatis的缓存机制

我们知道Hibernate有自己的缓存机制,Hibernate中分为一级缓存和二级缓存,其中的一级缓存是session缓存,是Hibernate封装好的,不需要我们做任何配置的,一级缓存 是与session绑定的,当session生命周期结束的时候对应的一级缓存也就消失了。Hibernate的二级缓存需要自己配置的,很遗憾,一直没去深入了解过,等过了这阶段比较忙 的时间一定得好好研究研究Hib

曹海成的专栏 7622

Ibatis.Net 学习手记二 缓存

Ibatis.Net 学习手记二 缓存Ibatis.Net 的缓存策略有几种:MEMORY、LRU、FIFOMEMORY MEMORY高速缓存是一种基于引用的高速缓存。有了STRONG、SOFT、WEAK这种引用类型,LRU LRU类型的高速缓存模型使用最近最少使用策略来管理高速缓存。该高速缓存的内部机制会在后台记录哪些对象最近最少使用,一旦超过高速缓存大小限制就...

weixin_30532973的博客 143

iBATIS系统学习笔记

基础知识,涉及到安装和配置,已映射语句,非查询语句,高级查询技术,事务,动态SQL

啊昕的博客 1499

ibatis学习笔记

fsdf SqlMapConfigExample.properties driver=oracle.jdbc.driver.OracleDriver url=jdbc:oracle:thin:@localhost:1521/orcl username=colin password=colin SqlMapConfig.xml <!DOCTYPE sqlMapCon

chunda 1521

IBATIS总结

iBATIS 学习总结 一、        了解iBATIS 1.什么是iBATIS “一个映射层,在对象和数据库间传递数据,并保持两者与映射层本身独立”  iBatis 不是直接在类和数据表或字段与列之间进行关联,而是把SQL语句的参数和返回结果映射至类。iBatis是出于类和数据表之间的一个中间层。这使得它在类和数据表之间进行映射时更加灵活。 iBATIS 是把SQL语句的参数和返回

duci2的专栏 2495

iBATIS In Action (iBATIS的安装和配置

译注:本章讲解的是iBATIS的安装和配置,原书使用的是Java版本,与.NET版本的安装、配置过程不尽相同,因此这里直接就.NET版本进行说明。主要参考的是iBATIS官方的DataMapper Guide文档,本章的配置主要针对DataMapper,DataAccess的配置将出现在第10章。 iBATIS的安装过程快速而简单。它是一个类库,而不是应用程序,所以实际上并不需要安装,但要在应...

weixin_30471065的博客 216

Ibaitsnet源码解读(4)--DataMapper的Cache

Ibatis有自己的灵活的,可扩展的Cache支持。其内置的Cache类型有种:基于内存的,LRU(最近最少使用算法)和FIFO(先进先出)。 一.基本概念 在配置文件中Cache的配置如下: id 用于唯一标志该cacheModel。 implementation 为ICacheController的具体实现类的全限定名或者框架内部定义的别名--LRU,FIFO,

zaocha321的专栏 705

ibatis 取消查询动态列的缓存

ibatis在查询结果列不确定(或是动态变化)的情况下,会因为列缓存的原因导致变化后的列数据查不出来 解决方法是: select标签有个属性remapResults,该属性默认值为false,设置成remapResults="true",即可解决 <select id="selectTableDataListByPage" resultClass="java.util.Ha...

weixin_30242907的博客 194

spring对ibatis的封装导致ibatis缓存cacheModel中的flushOnExecute失效,使增加和修改时不能清空缓存...

spring对ibatis的封装导致ibatis缓存cacheModel中的flushOnExecute失效,使增加和修改时不能清空缓存 原因:org.springframework.orm.ibatis.SqlMapClientFactoryBean 改变了ibatic的加载配置文件的顺序。 NodeletParser中letMap的执行顺序如下: / /sqlMapConfig ...

songpengxing的专栏 316

IBatisNet 缓存使用

参考:http://www.cnblogs.com/xiaogangqq123/archive/2011/06/30/2094905.html   &lt;?xml version="1.0" encoding="utf-8" ?&gt; &lt;sqlMap namespace="CacheAccount" xmlns="http://ibatis.apache.org/mapping...

weixin_33890499的博客 239

iBatis缓存的使用方法及解释

      最近开始重构公司一套手机论坛系统(为什么我不说wap论坛,是因为需要针对不同的手机浏览器,实现自动适配成wap、html以及wap2.0版本的页面)。原系统存在架构层次不清晰(表现层全jsp,直接配合数据层获取数据),访问速度慢的问题。其使用的OR映射框架是Hibernate,鉴于Hibernate的一些不满足需要情况下,我们在重构的时候换成了iBatis,为了加快访问速度,采用了iB

穿拖鞋写程序 4534

IBATIS标签详解

ibatis标签详解

Earl_yuan的专栏 1万+

ibatis小结

其实这个东西刚来这里的时候就已经看过了,现在已经快忘光了,还是来做个小小的总结吧。。。。 老规矩,还是先看看ibatis是干什么用的吧。 一:ibatis的作用: SQL Map能大大减少访问关系数据库的代码。SQL Map使用简单的XML配置文件将Java Bean映射成SQL语句,对比其他的数据库持久层和ORM框架,SQL Map最大的优点在于它简单易学。要使用SQL Map,只...

helloklzs 201

iBatis映射文件详解(一)

以下是iBatis映射文件的一个简单例子:    PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"         "http://ibatis.apache.org/dtd/sql-map-2.dtd">                                              

edifiergl的专栏 3780

IBatis学习关于缓存的使用范例

<br />    在特定硬件基础上(同时假设系统不存在设计上的缺漏和糟糕低效的SQL 语句)Cache往往是提升系统性能的最关键因素)。<br />    相对Hibernate 等封装较为严密的ORM 实现而言(因为对数据对象的操作实现了较为严密的封装,可以保证其作用范围内的缓存同步,而ibatis 提供的是半封闭的封装实现,因此对缓存的操作难以做到完全的自动化同步)。<br />    ibatis 的缓存机制使用必须特别谨慎。特别是flushOnExecute 的设定(见“ibatis配置”一节中的

303

iBatis中使用事务

先复习一下事务的特点:ACID Atomicity: 原子性 Consistency: 一致性 Isolation: 隔离性 Durability: 耐久性 iBatis中的事务分为: Automatic Transaction Local Transaction

xilangyuyun的专栏 1262

iBATIS缓存介绍

iBATIS缓存介绍 一.缓存介绍........................................................................................... 2 1.1缓存对象...........................................................................

虎子专栏 936

arcgis中文使用手册(上)

arcgis中文使用手册,文中详细介绍了ARCGIS的使用方法,是使用ARCGIS制作地图人员及二次开发人员不可缺少的中文资料

支付宝营销策略分析【基于ABTest进行数据分析实战】python

数据齐全,含详细的代码注释以及ABTest具体介绍。需要自行下载,诚不欺人。详见博文说明:https://blog.csdn.net/qq_44186838/article/details/120652083

上一篇: iBATIS系统学习笔记二
下一篇: iBATIS系统学习笔记四
啊昕Alan
博客等级 码龄13年 18粉丝 56原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值