1、Ibatis 工作原理,流程Ibatis 使用简单的 xml 描述文件将 javaBean,Map 实现和基本数据类型的封装类(String ,Integer 等)映射成 PreparedStatement 的输入参数和 ResultSet 结果集。具体工作流程如下:1、 在 sqlMapConfig 的 xml 配置文件中进行数据库链接的配置,xml 配置文件名称任意,比如 sql-map-config.xml2、 在 sqlMapConfig 的 xml 配置文件中引用 sqlMap 的 xml 配置文件有两种方式:如:推荐使用第一种方式。3、 在 sqlMap 的 xml 配置文件中进行
2、 SQL 文的配置,文件名称随意,一般是 javaBean 的类名+xml4、通过 SqlMapClient 生成具体的操作 sqlMap 配置文件中 SQL 文的 IBATIS 对象SqlMapClientString resource = “config/ibatis/sql-map-cofig.xml”;Reader reader = Resource.getResourceAsReader(resource);SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);以上代码是获取 SqlMapClient
3、对象的具体代码5、 SqlMapClient 对象提供函数,函数的参数对应替换 sqlMap 配置文件中的 id,parameter等等属性,完成 SQL 文的执行。具体参见 iBatis 的 API。public List queryForList(String statementName,Object parameterObject,int skipResult,int maxResults)statement:sqlMap 配置中 id 属性,parameterObject:sqlMap 配置中 parameterXXX 属性。Ibatis 的工作重点放在配置文件的做成上,尤其是 sql
4、Map 配置文件的做成是需要重点学习的。SqlMapConfig.xml配置例子如下,各个标签的说明参考官方文档。比较容易理解,这里不做整理以上,主要注意 DB 连接情报的配置方法,采用了 Java 的标准 Properties 文件。然后在 XML 中引用 properties 文件中的定义。四,SqlMap.xml 总体印象较复杂的例子:select * from PRODUCT where PRD_ID = ? 以上例子简化版:Select PRD_ID as id, PRD_DESCRIPTION as description From PRODUCT Where PRD_ID = #
5、id# 五,Statement 语法,类型,及其属性和特点1.语法select * from PRODUCT where PRD_ID = ?|#propertyName# order by $simpleDynamic$ 内为可选项,不是必须存在的。2.Statement 类型,属性,特点六,关于映射时输入值的匹配问题1. 类 SqlMapClient 如何从 SqlMap 的配置文件中找到对应的 SQL 文通过类函数的参数 statementName 与配置文件中 statement 配置的 id 相匹配2. bean 中的数据如何映射给 SQL 文中对应的输入参数a. 通过参数变量名称与
6、 bean 中对应属性名称相匹配insert into PRODUCT values (#id#, #description#, #price#) b. 通过参数变量的出现顺序相匹配insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?); 3. map 中的数据如何映射给 SQL 文中对应的输入参数a. 通过参数变量名称与 map 中对应 key 相匹配insert into PRODUCT values (#id#, #description#, #price#) HashMap hm = new HashMap();hm.put
7、(“id”,”value”);hm.put(“description”,”value”);hm.put(“price”,”value”);sqlMapClient.queryForList(“statementName”, hm,);4. 基本数据类型的数据如何映射给 SQL 文中对应的输入参数基本数据类型与参数 1 对 1,没啥匹配的问题。不过官方的开发指南中强调参数要写成#value#这种写法,原因不明。select * from PRODUCT where PRD_ID = #value# 七,关于映射时返回值的匹配问题1. 查询结果如何映射给 bean 中的对应属性a. 通过查询结果的
8、字段名称与 bean 中对应属性名称相匹配select PRD_ID as id, PRD_DESCRIPTION as description from PRODUCT where PRD_ID = #value# 官方的开发指南中说这种写法叫做隐式 ResultMapb. 指定查询结果的字段名称与 bean 中对应属性名称的映射关系以上,数据类型通过反射与对应的属性类型自动匹配,极少数时候可能需要通过 resultMap的 javaType 属性进行设定,参考后面关于 Result Map 外部形式中各个参数的说明2. 查询结果如何设定给 Mapa. 通过查询结果的字段名称与 map 中对
9、应 key 相匹配select * from PRODUCT b. 指定查询结果的字段名称与 bean 中对应属性名称的映射关系与 bean 基本相同,参考使用 bean 作为返回结果的写法3. 查询结果如何映射给基本数据类型只能指定一个返回值,名字可以随便,一般采用 value,val 等或者select count(1) as value from PRODUCT 八,关于 Parameter Map 外部形式中各个参数的说明1.JdbcType属性 jdbcType 用于显式地指定给本属性( property)赋值的数据库字段的数据类型。对于某些特定的操作,如果不指定字段的数据类型,某些
10、 JDBC Driver 无法识别字段的数据类型。正常情况下,只有当字段可以为 NULL 时才需要 jdbcType 属性。另一需要指定 jdbcType属性的情况是字段类型为日期时间类型的情况。因为 Java 只有一个 Date 类型(java.util.Date ) ,而大多数 SQL 数据库有多个通常至少有 3 种。因此,需要指定字段类型是 DATE 还是 DATETIME。注意!当使用 Oracle Driver 时,如果没有给可以为 NULL 的字段指定 jdbcType 属性,当试图给这些字段赋值 NULL 时,会出现“Invalid column type”错误。2.javaTy
11、pe属性 javaType 用于显式地指定被赋值参数 Java 属性的类名。正常情况下,这可以通过反射从 Java Bean 的属性获得3.nullValue, null用于指定 NULL 的替换值。就是说,当 Java Bean 的属性值等于指定值时,相应的字段将赋值 NULL。这个特性允许在应用中给不支持 null 的数据类型(即 int,double,float 等)赋值 null。当这些数据类型的属性值匹配 null 值(即匹配-9999)时,NULL 将代替 null 值写入数据库。 一个完整的例子insert into PRODUCT (PRD_ID, PRD_DESCRIPTIO
12、N) values (?,?); 简化写法 insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id:NUMERIC#, #description:VARCHAR#); 或者:insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (#id:NUMERIC:-999999#, #description:VARCHAR:NO_ENTRY#); 九,Result Map 外部形式中各个参数的说明1. columnIndex属性 columnIndex 是可选的,用于改善性能。属性 colum
13、nIndex 的值是 ResultSet 中用于赋值 Java Bean 属性的字段次序号。在 99的应用中,不太可能需要牺牲可读性来换取性能。使用 columnIndex,某些 JDBC Driver 可以大幅提高性能,某些则没有任何效果。 2.javaType属性 javaType 用于显式地指定被赋值的 Java Bean 属性的类型。正常情况下,这可以通过反射从 Java Bean 的属性获得,但对于某些映射(例如 Map 和 XML document) ,框架不能通过这种方法来获知。如果没有设置 javaType,同时框架也不能获知类型信息,类型将被假定为 Object。3.jdbc
14、Type,nullValue, null同 Parameter Map4.select属性 select 用于描述对象之间的关系,并自动地装入复杂类型(即用户定义的类型)属性的数据。属性 select 的值必须是另外一个 mapped statement 元素的名称。在同一个 result 元素中定义的数据库字段(column 属性)以及 property 属性,将被传给相关的 mapped statement 作为参数。因此,字段的数据类型必须是 SQL Map 支持的简单数据类型。关于简单数据类型和复杂类型之间映射/关系的信息,参照后面章节更详细的讨论。具体参考稍后关于复杂类型属性的例子十
15、,复杂类型属性说明1关于复杂类型属性的例子select * from PRODUCT where PRD_ID = #value# select * from CATEGORY where CAT_ID = #value# 避免 N1 Select(1:1) select * from PRODUCT, CATEGORY where PRD_CAT_ID=CAT_ID and PRD_ID = #value# 2关于复杂类型级和属性的例子select * from CATEGORY where CAT_ID = #value# select * from PRODUCT where PRD_C
16、AT_ID = #value# 避免 N1 Select(1:1) 暂时无解,在新版本中可能会对应3组合键值或多个复杂参数属性select * from PAYMENT where PAY_ORD_ID = #itemId# and PAY_CST_ID = #custId# 十一, 在查询 statement 中指定 cacheModel 属性select * from PRODUCT where PRD_CAT_ID = #value# 1Serializable 可读写缓存 正如您所知道的,只对当前 Session 有效的缓存对整体应用性能的提高作用有限。Serializable 可读写
17、缓存可以提高整体应用(而不仅仅是每个 Session)的性能。这种缓存为每一个 Session 返回缓存对象不同的实例(复本) 。因此每一个 Session 都可以安全修改返回的对象。不同之处在于,通常您希望从缓存中得到同一个对象,但这种情况下得到的是不同的对象。还有,每一个缓冲在 Serializable 缓存的对象都必须是 Serializable 的。这意味着不能同时使用 Serializable 缓存和延迟加载,因为延迟加载代理不是 Serializable 的。想知道如何把 Serializable 缓存,延迟加载和联合查询结合起来使用,最好的方法是尝试。要使用 Serializab
18、le 缓存,设置 readOnly=“false”和 serialize=“true”。缺省情况下,缓存是只读模式,不使用 Serializable 缓存。只读缓存不需要 Serializable。2Typea.type=”MEMORY”MEMORY cache 实现只认识一个 元素。这个名为 “reference-type”属性的值必须是 STRONG,SOFT 和 WEAK 三者其一。这三个值分别对应于 JVM 不同的内存reference 类型。b.type=”LRU”LRU Cache 实现用“近期最少使用”原则来确定如何从 Cache 中清除对象。c.type=”FIFO”FIFO
19、Cache 实现用“先进先出”原则来确定如何从 Cache 中清除对象。d.type=” OSCACHE” 没用过,没研究过。这个不太懂,哈OSCACHE Cache 实现是 OSCache2.0 缓存引擎的一个 Plugin。它具有高度的可配置性,分布式,高度的灵活性。OSCACHE 实现不使用 property 元素,而是在类路径的根路径中使用标准的oscache.properties 文件进行配置。在 oscache.properties 文件中,您可以配置 Cache 的算法(和上面讨论的算法很类似) ,Cache 的大小,持久化方法(内存,文件等)和集群方法。 要获得更详细的信息,请
20、参考 OSCache 文档。OSCache 及其文档可以从 OpenSymphony 网站上获取: http:/ 十二, 动态 Mapped Statementselect * from ACCOUNT where ACC_ID = #id# order by ACC_LAST_NAME 上面的例子中,根据参数 bean“id”属性的不同情况,可创建两个可能的语句。如果参数“id”大于 0,将创建下面的语句: select * from ACCOUNT where ACC_ID = ? 或者,如果“id”参数小于等于 0,将创建下面的语句: select * from ACCOUNT1二元条件
21、元素 二元条件元素将一个属性值和一个静态值或另一个属性值比较,如果条件为“真” ,元素体的内容将被包括在查询 SQL 语句中。 二元条件元素的属性: prepend 可被覆盖的 SQL 语句组成部分,添加在语句的前面(可选) property 被比较的属性(必选) compareProperty 另一个用于和前者比较的属性(必选或选择 compareValue) compareValue 用于比较的值(必选或选择 compareProperty) 比较属性值和静态值或另一个属性值是否相等。 比较属性值和静态值或另一个属性值是否不相等。 比较属性值是否大于静态值或另一个属性值。 比较属性值是否大
22、于等于静态值或另一个属性值。 比较属性值是否小于静态值或另一个属性值。 比较属性值是否小于等于静态值或另一个属性值。 例子: ADOLESCENT = TRUE 2一元条件元素 一元条件元素检查属性的状态是否符合特定的条件。一元条件元素的属性: prepend 可被覆盖的 SQL 语句组成部分,添加在语句的前面(可选) property 被比较的属性(必选) 检查是否存在该属性(存在 parameter bean 的属性) 。 检查是否不存在该属性(不存在 parameter bean 的属性) 。 检查属性是否为 null。 检查属性是否不为 null。 检查 Collection.size
23、()的值,属性的 String 或 String.valueOf()值,是否为 null 或空(“”或size() 检查 Collection.size()的值,属性的 String 或 String.valueOf()值,是否不为 null 或不为空(“”或 size() 0) 。 例子: FIRST_NAME=#firstName# 3其他元素Parameter Present:这些元素检查参数对象是否存在。 Parameter Present 的属性: prepend 可被覆盖的 SQL 语句组成部分,添加在语句的前面(可选) 检查是否存在参数对象(不为 null) 。 检查是否不存在参
24、数对象(参数对象为 null) 。 例子: EMPLOYEE_TYPE = DEFAULT 4Iterate:这属性遍历整个集合,并为 List 集合中的元素重复元素体的内容。 Iterate 的属性: prepend 可被覆盖的 SQL 语句组成部分,添加在语句的前面(可选) property 类型为 java.util.List 的用于遍历的元素(必选) open 整个遍历内容体开始的字符串,用于定义括号(可选) close 整个遍历内容体结束的字符串,用于定义括号(可选) conjunction 每次遍历内容之间的字符串,用于定义 AND 或 OR(可选) 遍历类型为 java.util
25、.List 的元素。 例子: username=#userNameList# 注意:使用时,在 List 元素名后面包括方括号非常重要,方括号将对象标记为List,以防解析器简单地将 List 输出成 String。 一,注意事项1.关于特殊字符因为 SQL 语句是嵌在 XML 文档中的,因此有些特殊的字符不能直接使用,例如大于号和小于号( 2.关于多个 SqlMap.xml 中 id 冲突问题问题描述:当 sql-map-config 中引用多个 sqlmap.xml,多个 sqlmap.xml 中存在相同的 statementname 的时候,ibatis 如何判断当前我准备使用哪一个 s
26、qlmap.xml 中的 statementname 对应的 sql 语句解决方法:在 SqlMapConfig.xml 中的 settings 标签中存在一个属性 useStatementNamespaces 当这个设定为 true 的时候,那么 iBatis 通过 SqlMap.xml 的 namespace.id 来查找对应的 sql 文 id,从而避免这个问题。二,其他1.自动生成的主健SELECT STOCKIDSEQUENCE.NEXTVAL AS ID FROM DUAL insert into PRODUCT (PRD_ID,PRD_DESCRIPTION) values (#
27、id#,#description#) insert into PRODUCT (PRD_DESCRIPTION) values (#description#) SELECT IDENTITY AS ID 2.调用存储过程call swap_email_address (?, ?) SELECT IDENTITY AS ID 十五, Sample1.java 类,生成 iBatis 数据库操作对象public class MyAppSqlConfig private static final SqlMapClient sqlMap; static try String resource = “com/ibatis/example/sql-map-config.xml”; Reader reader = Resources.getResourceAsReader (resource); sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader); catch (Exception e) e.printStackTrace(); throw new RuntimeException (“”); public static getSqlMapInstance () return sqlMap;