codecamp

iBatis开发详解(3)---详细配置

    iBatis的简单增删改查操作非常容易掌握,下面我们来看看iBatis的详细配置。虽然iBatis小巧灵活,但是其可扩展性也非常强。iBatis的核心配置文件就是SqlMapConfig.xml了,下面我们来看看iBatis的核心配置结构。


    SqlMapConfig配置文件在前面我们知道要配置JDBC连接,SqlMap映射文件等信息,当然这都是非常基本的配置,现在我们要探究一下SqlMapConfig的详细配置。主要包括以下内容: 


    <properties>元素的配置,它提供了允许在主配置文件之外的一个“名值对”列表,可以将其中的配置信息加载进来,而这些配置信息可以放在任何一个地方。使用properties元素,其中有两个属性,分别是:resource和url。 


    使用resource属性时,类加载器会从类路径开始定位该资源;而使用url属性时,则是用java.net.URL类来处理的,提供一个有效的URL即可。之前的示例中,我们使用了resource属性来配置数据库连接信息,如: 

<properties resource="jdbc.properties" />
   而在jdbc.properties中,我们配置了数据库的驱动属性,连接url,用户名和密码,这样它们就可以被properties元素加载进来,使用起来非常方便。而properties配置文件中是以“名值对”的方式存储的,那么我们使用名称即可引用,这是很多人都熟悉的语法,比如:${driver}就能获取到com.mysql.jdbc.Driver,这里我们使用的是MySQL数据库。 


    <settings>元素的配置,这个元素即设置iBatis的全局配置信息。下面我们逐一来看其中可配置的属性信息。 


    lazyLoadingEnabled,从名字即可看出是否进行延迟加载。通俗来说,延迟加载就是只加载必要信息而推迟加载其他未明确请求的数据,这里要和Hibernate中延迟加载区分开。那也就是说,除非绝对必须,否则程序加载的数据越少越好。iBatis默认使用了延迟加载,即不配置时也是默认为true的。 


    cacheModelsEnabled,这是数据缓存的配置,缓存可以提高程序的性能,这是显而易见的。和延迟加载一样,缓存也是默认启用的。 


    enhancementEnabled,该配置是来说明是否使用cglib中那些优化的类来提高延迟加载的性能,默认值为true,也就是启用。但是之前的示例中,并没有在lib中加入cglib的类库,那么iBatis没有在类路径上发现cglib时,该功能也就不能起作用了。这里多说一点,对于增强框架,除非必须,尽量避免使用。 


    useStatementNamespaces,该配置说明是否使用语句的命名空间,默认是不使用的,但是在大型应用时,使用命名空间来作为限定就比较清楚了。使用方法是在<sql-map>标记上加namespace属性即可,在程序中就使用“命名空间.SQL映射语句”这种语法来执行。 


    settings还可以设置maxRequests,maxSessions和maxTransactions信息,但它们都已经被废弃了,也就是说我们可以不用设置它们,使用默认的就可以了。如果必须要进行设置,那就要保证maxRequests大于maxSessions,而maxSessions要大于maxTransactions。 


    下面我们来看<typeAlias>元素,就是起别名,很容易理解,我们不想使用过长的类名时,可以用它来起个别名,之后我们使用别名就可以了。比如:

<typeAlias alias="User" type="ibatis.model.User" />
    很容易看出type属性是原始的类名,而alias属性配置我们希望使用的名字即可。 


    iBatis已经为我们设置了一些类型的别名,我们就可以直接使用了,比如事务管理器的JDBC,JTA和EXTERNAL;数据类型的string,byte,long,short,int等;数据源工厂的SIMPLE,DBCP,JNDI;高速缓存控制器的FIFO,LRU,MEMORY,OSCACHE和XML结果类型的DOM,domCollection,Xml,XmlCollection,它们是可以直接使用的。 


    transactionManager元素,没错,它就是来做事务的。iBatis内置的事务管理器有JDBC,JTA和EXTERNAL。EXTERNAL表示事务管理器是应用程序本身负责,而不是iBatis。使用type属性就能在transactionManager元素中配置事务管理器了。比如: 

<transactionManager type="JDBC"></transactionManager>  
    它还有一个可以配置的属性是commitRequired,来配置在某个连接释放之前必须提交或者回滚的情况。 


    在transactionManager元素中还可以继续配置<properties>元素和<dataSource>元素。properties元素用于指定transactionManager的配置项,而后者用于配置数据源工厂,默认提供三种SIMPLE,DBCP和JNDI。 


    typeHandler元素,即类型处理器,用于将数据库中的数据类型转换成应用程序中使用的数据类型。假如数据库中不支持布尔值,那么只能以0/1来代表,而Java应用程序中支持布尔值,这里就需要一个类型处理的过程。使用时需要创建两个类,一个是类型处理类,一个是类型处理回调类。iBatis预先设置了大量的类型处理器,如果不是必须,为了程序的简单,那么尽量不要使用。 


    最后来看一下sqlMap元素,它就是配置SQL语句的了,是我们最常用到的一个标签。可以使用namespace来确定一个命名空间,这在之前已经说到了,可以将同一流程的SQL语句写在一起,放到一个命名空间下,在程序中使用更加清晰。在sqlMap之中,就是对数据库具体操作的实现了,包括增删改查等标记。 


    下面是iBatis的配置关系图:可以加深对iBatis的理解。 

API的查询:

   先说点基础的内容,iBatis并不是真正意义上的ORM,官方文档中称其为dataMapper,是数据映射器,也就是一种映射查询工具。iBatis不是万能的,在某些它不能处理的问题时,不能放弃使用JDBC API,那才是根本中的根本。 


    在iBatis中,建议使用JavaBean,因为我们是面向对象的设计,那么在系统设计时肯定创建了很多刻画具体对象的类,使用JavaBean就可以直接操作getter方法来获取内容。就像是hibernate中的PO一样。下面来说一种如何获取Bean中属性名称和属性类型的方法,这在开发时可能会用到。 


    先定义一个JavaBean,刻画用户模型吗,如下: 

package ibatis.model;  
public class User implements java.io.Serializable {  
    private Integer userId;  
    private String userName;  
    private String password;  
    private String mobile;  
    private String email;  
    public User() {  
        super();  
    }  
    public User(Integer userId, String userName, String password,  
            String mobile, String email) {  
        super();  
        this.userId = userId;  
        this.userName = userName;  
        this.password = password;  
        this.mobile = mobile;  
        this.email = email;  
    }  
// 省略getter和setter方法  
    @Override  
    public String toString() {  
        return "User [email=" + email + ", mobile=" + mobile + ", password="  
                + password + ", userId=" + userId + ", userName=" + userName  
                + "]";  
    }  
}  
 写一个方法来测试,如下:
public static void main(String[] args) {  
    try {  
        PropertyDescriptor[] pd = Introspector.getBeanInfo(User.class).getPropertyDescriptors();  
        for (int i = 0; i < pd.length; i++) {  
            System.out.println(pd[i].getName() + " ("  
                    + pd[i].getPropertyType().getName() + ")");  
        }  
    } catch (IntrospectionException e) {  
        e.printStackTrace();  
    }  
}  
 在控制台,我们获得如下输出:

class (java.lang.Class)  
email (java.lang.String)  
mobile (java.lang.String)  
password (java.lang.String)  
userId (java.lang.Integer)  
userName (java.lang.String)
    在定位BUG时,这是很好的一种手段。 


    接下来,我们来说一下三个常用的查询方法,它们的命名和Spring的JdbcTemplate/SqlMapClientTemplate很像,但是要区分开。 


    首先是queryForObject()方法,它返回数据库查询的一条结果,并放入到Java对象中,这里的一条记录可以是一个JavaBean,也可以是Java的集合类型。它可以根据<select>标签中配置的resultClass属性来确定的,如果不指定resultClass属性,那么查询结果就是null了,因为iBatis不知道怎么处理这个结果,而且我们也没有配置结果映射(resultMap)。 


    首先我们根据上面的User类型,将resultClass设置为User,代码如下: 

<sqlMap namespace="User">  
    <typeAlias alias="User" type="ibatis.model.User" />  
    <select id="getUserByName" parameterClass="java.lang.String"  
        resultClass="User">  
        select *  
        from users  
        where USERNAME=#VARCHAR#  
    </select>  
</sqlMap>  
    这时要求User类中必须要有一个默认的构造方法,否则将不能实例化这个对象,抛出异常,这一点不能忘记(如果重载了构造方法的话)。我们写一个程序:
System.out  
        .println(sqlMap.queryForObject("User.getUserByName", "sarin").getClass().getName());  
    此时,输出内容为:ibatis.model.User,这就很清楚的看到了,查询的结果类型是由<select>中的resultClass来确定的。 


    queryForObject()的另外一个重载方法是Object queryForObject(String id, Object parameter, Object resultObject) throws Exception,这种方法是为对象不能轻易创建的情况使用的(如没有默认的构造方法的对象),那么使用前面那种格式就会抛出异常,就需要使用这种方法,看下面代码:(这里去掉User类中的默认构造方法) 

User user=new User(null, null, null, null, null);  
user = (User) sqlMap.queryForObject("User.getUserByName", "sarin",  
                user);  
System.out.println(user); 
   这样才能获得user对象。 


    第二个方法是queryForMap()方法,返回结果可以是一条,也可以是多条。它的方法签名有两种形式:第一种是Map queryForMap(String id, Object parameter, String key) throws SQLException,第二种是再多一个参数String value。前面两个参数好理解,就是select标签的id和传入的参数,而后面的key和value是什么意思呢?key指定了Map中存储的键,而value确定了存储的值,不设置value时则存储查询的一个对象,如下面代码(此时已经将select的resultClass设置为hashmap了): 

Map map = sqlMap.queryForMap("User.getAllUsers", null,"userId");  
System.out.println(map);  
    正如你所想,这段代码的输出为: 
{1={email=gmail@gmail.com, userId=1, userName=sarin, password=123, mobile=15940912345}, 2={email=gmail@gmail.com, userId=2, userName=sarin, password=123, mobile=15940912345}}  
   这里的1和2就是key,是键,那么它们是什么类型的呢?我们使用如下代码来看看: 
System.out.println(map.keySet().iterator().next().getClass());  
  得到结果:class java.lang.Integer,说明这是字段相对应的,因为这里我们没有将查询结果和JavaBean相关联。那么HashMap中存储的value是什么类型呢?我们来看,代码如下:
System.out.println(map.get(1).getClass());  
 打印得到:class java.util.HashMap,说明存储的还是HashMap。而queryForMap()的第二个重载方法则是指定了value的内容,我们来看: 
Map map = sqlMap.queryForMap("User.getAllUsers", null, "userId",  
        "mobile");  
System.out.println(map);
    这将打印:{1=15940912345, 2=15940912345},这回就清楚了吧,而且得到的mobile的类型是String,也就容易理解了。记住一点,queryForMap()方法返回的可以是一条也可以是多条记录。但是在实践中往往用它来获取一条完整的记录,那么使用Map的get()方法就能获取到其中的值了,非常方便。 


    下面来看queryForList()方法,同样,该方法的方法签名也有两类形式:第一类是queryForList(String id, Object parameter) throws SQLException,或者不需要参数,这很好理解了。看个例子:(SqlMap中的resultClass设置为hashmap) 

List users = sqlMap.queryForList("User.getAllUsers");  
System.out.println(users);  
  打印的结果是:
[{email=gmail@gmail.com, userId=1, userName=sarin, password=123, mobile=15940912345}, {email=gmail@gmail.com, userId=2, userName=sarin, password=123, mobile=15940912345}]  
   就是List中装入的是HashMap对象,在SqlMap中将hashmap换为User,那么得到:
[User [email=gmail@gmail.com, mobile=15940912345, password=123, userId=1, userName=nanlei], User [email=gmail@gmail.com, mobile=15940912345, password=123, userId=2, userName=sarin]]  
     queryForList()的第二类方法是queryForList(String id, Object parameter, int skip, int max) throws SQLException,可以看出后面多了两个int类型的参数,那么SQL中使用两个int类型的参数能干什么?分页,没错,这是主要应用。iBatis在queryForList()中提供了为分页提供支持的方法。记着skip是从0开始计算的,而max就是取出的条数,那么取前10条就是(0,10),取11~20条就是(10,10),以此类推。 

iBatis开发详解(2)---增删改查
iBatis开发详解(4)---select详解
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }