- 浏览: 162300 次
- 性别:
- 来自: 成都
文章分类
- 全部博客 (134)
- JAVA Collection,Map (6)
- JAVA IO (6)
- JAVA 线程 (12)
- JAVA 反射机制 (6)
- JSP (2)
- JAVASCRIPT (6)
- JAVA OOP (4)
- Struts (4)
- Hibernate (5)
- Spring (9)
- IBatis (8)
- HTML (1)
- CSS (1)
- ORACLE (1)
- Servlet (4)
- DATABASE (5)
- JAVA逻辑 (1)
- JVM学习 (8)
- 设计模式 (13)
- JDBC (1)
- JAVA XML (6)
- Jquery (4)
- IT生活 (2)
- JAVA Web Servece (2)
- EJB (2)
- C语言基础 (3)
- JAVA数据结构和算法 (4)
- C数据结构和算法 (0)
- JAVA Collection (5)
- Map (5)
- Inner Class (1)
- JVM (0)
- tomcat (0)
- 版本控制 (1)
最新评论
-
baukh789:
...我们公司最近也在推这个东西,SVN用了四五年了,猛的换一 ...
git 初使用 -
BuN_Ny:
时序图???????????????????
EA入门-4 -
308202251:
308202251 写道308202251 写道3082022 ...
Java 反射机制中 getMethod()和getDeclaredField()区别 -
308202251:
308202251 写道308202251 写道3082022 ...
Java 反射机制中 getMethod()和getDeclaredField()区别 -
308202251:
308202251 写道308202251 写道3082022 ...
Java 反射机制中 getMethod()和getDeclaredField()区别
前段时间ibatis3.0发布出来了,迫不及待,将其源码下载拜读。相对ibatis 2.x来说,3.0已是完全改变。具体我就不在这细说,论坛中有一个帖子介绍了ibatis 3.0的新特征及使用。
由于其他模块的源码我还未细读,在这篇中,先来讨论Dynamic Sql在ibatis 3.0中的实现并比较2.x对应模块的设计。
写在前头的话:
其实如从设计模式应用角度去看待ibatis 3.0中Dynamic Sql的实现,这篇跟我的上篇(HtmlParser设计解析(1)-解析器模式 )相同,都是使用Interpreter模式。
这篇权当Interpreter模式的另一个demo,认我们体会这些开源项目中设计模式的使用。学习都是从模仿开始的,让 我们吸收高人们的经验,应用于我们实践项目需求中。
从总结中提高:
一、对比2.x中与3.0的Sqlmap中dynamic sql配置
2.x:
- < select id = "dynamicGetAccountList" parameterClass = "Account" resultClass = "Account" >
- select ACC_ID as id,
- ACC_FIRST_NAME as firstName,
- ACC_LAST_NAME as lastName,
- ACC_EMAIL as emailAddress from ACCOUNT
- < dynamic prepend = "WHERE" >
- < isNotNull prepend = "AND" property = "emailAddress" >
- ACC_EMAIL = #emailAddress#
- </ isNotNull >
- < isNotNull property = "idList" prepend = " or ACC_ID in " >
- < iterate property = "idList" conjunction = "," open = "(" close = ")" >
- #id#
- </ iterate >
- </ isNotNull >
- </ dynamic >
- </ select >
<select id="dynamicGetAccountList" parameterClass="Account" resultClass="Account"> select ACC_ID as id, ACC_FIRST_NAME as firstName, ACC_LAST_NAME as lastName, ACC_EMAIL as emailAddress from ACCOUNT <dynamic prepend="WHERE"> <isNotNull prepend="AND" property="emailAddress"> ACC_EMAIL = #emailAddress# </isNotNull> <isNotNull property="idList" prepend=" or ACC_ID in "> <iterate property="idList" conjunction="," open="(" close=")" > #id# </iterate> </isNotNull> </dynamic> </select>
3.0:
- < select id = "dynamicGetAccountList" parameterType = "Account" resultType = "Account" >
- select ACC_ID as id,
- ACC_FIRST_NAME as firstName,
- ACC_LAST_NAME as lastName,
- ACC_EMAIL as emailAddress from ACCOUNT
- < where >
- < if test = "emailAddress != null" > ACC_EMAIL = #{emailAddress} </ if >
- < if test = "idList != null" >
- or ACC_ID IN
- < foreach item = "id" index = "index" open = "(" close = ")" separator = "," collection = "idList" >
- #{idList[${index}]}
- </ foreach >
- </ if >
- </ where >
- </ select >
<select id="dynamicGetAccountList" parameterType="Account" resultType="Account"> select ACC_ID as id, ACC_FIRST_NAME as firstName, ACC_LAST_NAME as lastName, ACC_EMAIL as emailAddress from ACCOUNT <where> <if test="emailAddress != null">ACC_EMAIL = #{emailAddress}</if> <if test="idList != null"> or ACC_ID IN <foreach item="id" index="index" open="(" close=")" separator="," collection="idList"> #{idList[${index}]} </foreach> </if> </where> </select>
从上面这个简单的比较中,第一感觉3.0了中其dynamic sql更加简洁明了。
其二,test="emailAddress != null" 添加了OGNL的解释支持,可以动态支持更多的判断,这将不限于原2.x中提供
的判断逻辑,更不需要为每个判断条件加个标签进行配置。
例如:<if test="id > 10 && id < 20"> ACC_EMAIL = #{emailAddress}</if>
<if test="Account.emailAddress != null "> ACC_EMAIL = #{emailAddress}</if> ……
二、2.x Dynamic Sql的设计
2.1、2.x中dynamic流程。
这里帖出,我先前在分析ibatis 2.3时画的一个对dynamic sql的整体使用的时序图,可能会显得乱而复杂。
2.2、主要类设计
在这,我们只关注这几个类:XMLSqlSource、DynamicSql、SqlTagHandler (具体类结构图见后)
XMLSqlSource:相当于一个工厂类,其核心方法parseDynamicTags(),用于解析sql Tag,并判断是否是动态SQL标签。如果true,返回一个DynamicSql对象并创建多个SqlChildt对象添加至动态SQL列表中(addChild());false,返回RawSql对象(简单的SQL语句) 。
DynamicSql:核心的动态SQL类。其动态条件判断逻辑,参数映射等都发生在这个类中。
SqlTagHandle:动态条件判断接口,其每个动态SQL标签对应其一个子类。
接下来,我们具体看下在DynamicSql类中核心方法。
DynamicSql:
- private void processBodyChildren(StatementScope statementScope, SqlTagContext ctx, Object parameterObject, Iterator localChildren, PrintWriter out) {
- while (localChildren.hasNext()) { //XMLSqlSource 生成的动态SQL列表
- SqlChild child = (SqlChild) localChildren.next();
- if (child instanceof SqlText) {
- ... ... //组装SQL语句及映射SQL参数
- } else if (child instanceof SqlTag) {
- SqlTag tag = (SqlTag) child;
- SqlTagHandler handler = tag.getHandler(); //得到动态SQL标签处理器
- int response = SqlTagHandler.INCLUDE_BODY;
- do {
- response = handler.doStartFragment(ctx, tag, parameterObject); //处理开始片段
- if (response != SqlTagHandler.SKIP_BODY) { //是否跳过,意思该判断的条件为false
- processBodyChildren(statementScope, ctx, parameterObject, tag.getChildren(), pw); //递归处理
- StringBuffer body = sw.getBuffer();
- response = handler.doEndFragment(ctx, tag, parameterObject, body); //处理结束片段
- handler.doPrepend(ctx, tag, parameterObject, body); //组装SQL
- }
- } while (response == SqlTagHandler.REPEAT_BODY);
- ... ... }
- }
private void processBodyChildren(StatementScope statementScope, SqlTagContext ctx, Object parameterObject, Iterator localChildren, PrintWriter out) { while (localChildren.hasNext()) { //XMLSqlSource 生成的动态SQL列表 SqlChild child = (SqlChild) localChildren.next(); if (child instanceof SqlText) { ... ... //组装SQL语句及映射SQL参数 } else if (child instanceof SqlTag) { SqlTag tag = (SqlTag) child; SqlTagHandler handler = tag.getHandler(); //得到动态SQL标签处理器 int response = SqlTagHandler.INCLUDE_BODY; do { response = handler.doStartFragment(ctx, tag, parameterObject); //处理开始片段 if (response != SqlTagHandler.SKIP_BODY) { //是否跳过,意思该判断的条件为false processBodyChildren(statementScope, ctx, parameterObject, tag.getChildren(), pw); //递归处理 StringBuffer body = sw.getBuffer(); response = handler.doEndFragment(ctx, tag, parameterObject, body); //处理结束片段 handler.doPrepend(ctx, tag, parameterObject, body); //组装SQL } } while (response == SqlTagHandler.REPEAT_BODY); ... ... } }
2.3、SqlTagHandle设计
首先看下SqlTagHandle处理类的结果图:
- public abstract class ConditionalTagHandler extends BaseTagHandler {
- ... ...
- public abstract boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject);
- public int doStartFragment(SqlTagContext ctx, SqlTag tag, Object parameterObject) {
- ctx.pushRemoveFirstPrependMarker(tag);
- if (isCondition(ctx, tag, parameterObject)) {
- return SqlTagHandler.INCLUDE_BODY;
- } else {
- return SqlTagHandler.SKIP_BODY;
- }
- }
- ... ...
- }
public abstract class ConditionalTagHandler extends BaseTagHandler { ... ... public abstract boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject); public int doStartFragment(SqlTagContext ctx, SqlTag tag, Object parameterObject) { ctx.pushRemoveFirstPrependMarker(tag); if (isCondition(ctx, tag, parameterObject)) { return SqlTagHandler.INCLUDE_BODY; } else { return SqlTagHandler.SKIP_BODY; } } ... ... }
IsNullTagHandler:
- public class IsNullTagHandler extends ConditionalTagHandler {
- private static final Probe PROBE = ProbeFactory.getProbe();
- public boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject) {
- if (parameterObject == null ) {
- return true ;
- } else {
- String prop = getResolvedProperty(ctx, tag);
- Object value;
- if (prop != null ) {
- value = PROBE.getObject(parameterObject, prop);
- } else {
- value = parameterObject;
- }
- return value == null ;
- }
- }
- }
public class IsNullTagHandler extends ConditionalTagHandler { private static final Probe PROBE = ProbeFactory.getProbe(); public boolean isCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject) { if (parameterObject == null) { return true; } else { String prop = getResolvedProperty(ctx, tag); Object value; if (prop != null) { value = PROBE.getObject(parameterObject, prop); } else { value = parameterObject; } return value == null; } } }
至于其他的相关类,不在这列出了,有兴趣的可以找其源码了解下。
2.4、总结ibatis 2.X Dynamic Sql 的设计
从上面的分析中,可以体会出作者的dynamic sql这模块的设计思路。从装载sqlmap.xml中各sql配置(时序图中的1步),通过工厂创建DynamicSql和RawSql(时序图中的3步),然后分发之不同的处理器。
在DynamicSql中则调用SqlTagHandle判断其条件(时序图中的10步)。而SqlTagHandle的设计使用策略者模式,让其不同的子类来处理这个判断逻辑。
通过一系列的加工,最终组装一个Sql对象,将值set至MappedStatement(时序图中的14步)中,然后MappedStatement对象执行executeQueryWithCallback查询数据(时序图中的17步),这儿会调用先前组装的Sql对象(时序图中的19步)。至于这其中的细节已不在这篇的研究这内。
三、3.0 Dynamic Sql的设计
至于3.0其基本流程跟2.x是一样的,从装载 -> 参数映射 -> 执行SQL -> 返回结果。我们直接切入主题,分析是核心部分。先从一个简单的Dynamic Sql的测试用例开始。
3.1、 测试用例
dynamic sql test:
- @Test
- public void shouldTrimWHEREInsteadOfORForSecondCondition() throws Exception {
- /* SELECT * FROM BLOG
- <where>
- <if test="id != false"> and ID = #{id} </if>
- <if test="name != false"> or NAME = #{name} </if>
- </where>
- */
- final String expected = "SELECT * FROM BLOG WHERE NAME = ?" ;
- DynamicSqlSource source = createDynamicSqlSource(
- new TextSqlNode( "SELECT * FROM BLOG" ),
- new WhereSqlNode(mixedContents(
- new IfSqlNode(
- mixedContents( new TextSqlNode( " and ID = ? " )), "false" ), new IfSqlNode(mixedContents( new TextSqlNode( " or NAME = ? " )), "true" ))));
- BoundSql boundSql = source.getBoundSql( null );
- assertEquals(expected, boundSql.getSql());
- }
- private DynamicSqlSource createDynamicSqlSource(SqlNode... contents)
- throws IOException, SQLException {
- createBlogDataSource();
- final String resource = ".../MapperConfig.xml" ;
- final Reader reader = Resources.getResourceAsReader(resource);
- SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder()
- .build(reader);
- Configuration configuration = sqlMapper.getConfiguration();
- MixedSqlNode sqlNode = mixedContents(contents);
- return new DynamicSqlSource(configuration, sqlNode);
- }
- private MixedSqlNode mixedContents(SqlNode... contents) {
- return new MixedSqlNode(Arrays.asList(contents));
- }
@Test public void shouldTrimWHEREInsteadOfORForSecondCondition() throws Exception { /* SELECT * FROM BLOG <where> <if test="id != false"> and ID = #{id} </if> <if test="name != false"> or NAME = #{name} </if> </where> */ final String expected = "SELECT * FROM BLOG WHERE NAME = ?"; DynamicSqlSource source = createDynamicSqlSource( new TextSqlNode("SELECT * FROM BLOG"), new WhereSqlNode(mixedContents( new IfSqlNode( mixedContents(new TextSqlNode(" and ID = ? ")),"false"), new IfSqlNode(mixedContents(new TextSqlNode(" or NAME = ? ")), "true")))); BoundSql boundSql = source.getBoundSql(null); assertEquals(expected, boundSql.getSql()); } private DynamicSqlSource createDynamicSqlSource(SqlNode... contents) throws IOException, SQLException { createBlogDataSource(); final String resource = ".../MapperConfig.xml"; final Reader reader = Resources.getResourceAsReader(resource); SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder() .build(reader); Configuration configuration = sqlMapper.getConfiguration(); MixedSqlNode sqlNode = mixedContents(contents); return new DynamicSqlSource(configuration, sqlNode); } private MixedSqlNode mixedContents(SqlNode... contents) { return new MixedSqlNode(Arrays.asList(contents)); }
有经验的人,我想一眼就能看出其3.0中的设计思想,从Test中可以看出,或者我上一篇介绍的HtmlParser NodeFilter。
YES,在ibatis 3.0 dynamic sql设计正是应用了解释器模式,替换了原在这种需求下相对显得笨拙的策略者模式。
下面具体看下类结构图。
3.2、类结构图
SqlNode Class Diagram :
SqlSource Class Diagram :
3.3、配置文件的解析
在这,我就顺便提下ibatis解析组件对dynamic sql的解析方式,以代码见分晓吧。
XMLStatementBuilder:
- public void parseStatementNode(XNode context) {
- ... ...
- List<SqlNode> contents = parseDynamicTags(context);
- MixedSqlNode rootSqlNode = new MixedSqlNode(contents); //再次包装dynamic sql处理链
- SqlSource sqlSource = new DynamicSqlSource(configuration, rootSqlNode); //默认初始化DynamicSqlSource
- ... ...
- builderAssistant.addMappedStatement(id, sqlSource, statementType,
- sqlCommandType, fetchSize, timeout, parameterMap,
- parameterTypeClass, resultMap, resultTypeClass,
- resultSetTypeEnum, flushCache, useCache, keyGenerator,
- keyProperty); //将解析的所有属性构建成相应的对象存入全局的申明对象(MappedStatement)中,后面只传递该对象。
- }
- private List<SqlNode> parseDynamicTags(XNode node) {
- List<SqlNode> contents = new ArrayList<SqlNode>();
- NodeList children = node.getNode().getChildNodes();
- for ( int i = 0 ; i < children.getLength(); i++) {
- XNode child = node.newXNode(children.item(i));
- String nodeName = child.getNode().getNodeName();
- if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE
- || child.getNode().getNodeType() == Node.TEXT_NODE) {
- String data = child.getStringBody( "" );
- contents.add( new TextSqlNode(data));
- } else {
- NodeHandler handler = nodeHandlers.get(nodeName);
- if (handler == null ) {
- throw new BuilderException( "Unknown element <" + nodeName "> in SQL statement." );
- }
- handler.handleNode(child, contents);
- }
- }
- return contents;
- }
- private Map<String, NodeHandler> nodeHandlers = new HashMap<String, NodeHandler>() {
- {
- put( "where" , new WhereHandler());
- put( "set" , new SetHandler());
- put( "foreach" , new ForEachHandler());
- put( "if" , new IfHandler());
- ... ...
- }
- };
- private interface NodeHandler {
- void handleNode(XNode nodeToHandle, List<SqlNode> targetContents);
- }
- private class WhereHandler implements NodeHandler {
- public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
- List<SqlNode> contents = parseDynamicTags(nodeToHandle); // 遍历
- MixedSqlNode mixedSqlNode = new MixedSqlNode(contents); //对应测试用例中的mixedContents方法
- WhereSqlNode where = new WhereSqlNode(mixedSqlNode);
- targetContents.add(where);
- }
- }
- private class IfHandler implements NodeHandler {
- public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
- List<SqlNode> contents = parseDynamicTags(nodeToHandle); //遍历
- MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
- String test = nodeToHandle.getStringAttribute( "test" );
- IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test); //初始化对应的处理器
- targetContents.add(ifSqlNode); //
- }
- } // 其他的Handle详见ibatis源码~
public void parseStatementNode(XNode context) { ... ... List<SqlNode> contents = parseDynamicTags(context); MixedSqlNode rootSqlNode = new MixedSqlNode(contents);//再次包装dynamic sql处理链 SqlSource sqlSource = new DynamicSqlSource(configuration, rootSqlNode); //默认初始化DynamicSqlSource ... ... builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, keyGenerator, keyProperty); //将解析的所有属性构建成相应的对象存入全局的申明对象(MappedStatement)中,后面只传递该对象。 } private List<SqlNode> parseDynamicTags(XNode node) { List<SqlNode> contents = new ArrayList<SqlNode>(); NodeList children = node.getNode().getChildNodes(); for (int i = 0; i < children.getLength(); i++) { XNode child = node.newXNode(children.item(i)); String nodeName = child.getNode().getNodeName(); if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) { String data = child.getStringBody(""); contents.add(new TextSqlNode(data)); } else { NodeHandler handler = nodeHandlers.get(nodeName); if (handler == null) { throw new BuilderException("Unknown element <" + nodeName "> in SQL statement."); } handler.handleNode(child, contents); } } return contents; } private Map<String, NodeHandler> nodeHandlers = new HashMap<String, NodeHandler>() { { put("where", new WhereHandler()); put("set", new SetHandler()); put("foreach", new ForEachHandler()); put("if", new IfHandler()); ... ... } }; private interface NodeHandler { void handleNode(XNode nodeToHandle, List<SqlNode> targetContents); } private class WhereHandler implements NodeHandler { public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) { List<SqlNode> contents = parseDynamicTags(nodeToHandle);// 遍历 MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);//对应测试用例中的mixedContents方法 WhereSqlNode where = new WhereSqlNode(mixedSqlNode); targetContents.add(where); } } private class IfHandler implements NodeHandler { public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) { List<SqlNode> contents = parseDynamicTags(nodeToHandle);//遍历 MixedSqlNode mixedSqlNode = new MixedSqlNode(contents); String test = nodeToHandle.getStringAttribute("test"); IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);//初始化对应的处理器 targetContents.add(ifSqlNode);// } } // 其他的Handle详见ibatis源码~
上面是其解析代码的一部分,我想从这几行代码中,可以看出作者的思想了(遍历XML各节点,以节点名查找相应对应的处理器,分发之该处理器执行"业务分析" — 策略者模式,这样在XML中定义了多少标签,这里就需要多少个类与之对应,但如果策略类太多,这种方式就显得笨拙了)。
以下就是其核心类的一部分源码,先看再说。
3.4、DynamicSqlSource(核心类)
- public class DynamicSqlSource implements SqlSource {
- public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
- this .configuration = configuration;
- this .rootSqlNode = rootSqlNode;
- }
- public BoundSql getBoundSql(Object parameterObject) {
- DynamicContext context = new DynamicContext(parameterObject); //组装后的结果存储类
- rootSqlNode.apply(context); //调用SqlNode解释sql,并组装成完整的sql(SqlNode的客户端调用就在这)
- SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
- Class parameterType = parameterObject == null ? Object. class : parameterObject.getClass();
- SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType);
- BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
- for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
- boundSql.setAdditionalParameter(entry.getKey(), entry.getValue());
- }
- return boundSql;
- }
- }
public class DynamicSqlSource implements SqlSource { public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) { this.configuration = configuration; this.rootSqlNode = rootSqlNode; } public BoundSql getBoundSql(Object parameterObject) { DynamicContext context = new DynamicContext(parameterObject);//组装后的结果存储类 rootSqlNode.apply(context);//调用SqlNode解释sql,并组装成完整的sql(SqlNode的客户端调用就在这) SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) { boundSql.setAdditionalParameter(entry.getKey(), entry.getValue()); } return boundSql; } }
3.5、SqlNode
public interface SqlNode { public boolean apply(DynamicContext context); }
MixedSqlNode.class
- public class MixedSqlNode implements SqlNode {
- ... ....
- public boolean apply(DynamicContext context) {
- //遍历组装的解析内容
- for (SqlNode sqlNode : contents) {
- // 转发至相关解释器处理
- sqlNode.apply(context);
- }
- return true ;
- }
- }
public class MixedSqlNode implements SqlNode { ... .... public boolean apply(DynamicContext context) { //遍历组装的解析内容 for (SqlNode sqlNode : contents) { // 转发至相关解释器处理 sqlNode.apply(context); } return true; } }
IfSqlNode.class
发表评论
-
slf4j的使用
2011-10-30 21:25 828最近在利用ibatis3开发项目,从ibatis3的压缩包中发 ... -
mybatis3学习笔记(五)之高级查询
2011-04-07 17:56 9281.修改StudentMapper.xml文件,增加动态sql ... -
深入分析 iBATIS 框架之系统架构与映射原理
2011-04-03 19:47 1185本文出自IBM:http://www.ib ... -
ibatis的含有外键的OR映射
2011-04-03 19:42 601对于有外键的主表映射,在查询返回结果时要使用resultmap ... -
ibatis打印sql
2011-03-20 17:02 1119为了方便跟踪调试,利用log4j把ibatis执行的sql语句 ... -
There is no statement named xxx in this SqlMap 让我很莫名
2011-02-12 15:45 3097com.ibatis.sqlmap.client.SqlMap ... -
ibatis 属性详细分析
2011-02-10 14:31 1076insert 返回的为插入的主键值,但必须在配置文件中加入&l ...
相关推荐
标题和描述均聚焦于ibatis 3.0 Dynamic Sql的设计解析以及它与2.x版本的差异,这是一个关于ORM(对象关系映射)框架ibatis在处理动态SQL方面的重要升级和改进的主题。以下是对该主题的深入探讨: ### 重要概念:...
ibatis-3-core-3.0.0.242.jar.zipibatis-3-core-3.0.0.242.jar.zipibatis-3-core-3.0.0.242.jar.zipibatis-3-core-3.0.0.242.jar.zipibatis-3-core-3.0.0.242.jar.zip
《深入解析iBatis 3.0:基于mybatis-jpetstore-6.0.1示例》 iBatis,又称MyBatis,是一款优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。iBatis 3.0版本(也称为MyBatis 3.0)引入了许多新特性,极大地...
Ibatis 是一款轻量级的Java持久层框架,它提供了SQL映射框架,使得开发者能够将SQL语句直接写在配置文件中,从而避免了Java代码与SQL的耦合,提高了开发效率。在这个"最新的ibatis 3.0(包含源码)"压缩包中,我们...
【标题】"ibatis3.0+jsp(demo)"是一个基于Java Web的示例项目,它结合了iBATIS 3.0数据访问框架和JSP(JavaServer Pages)技术来展示如何在实际应用中进行数据库操作。这个项目提供了一个完整的数据库交互流程,包括...
ibatis3.0的中文版文档,pdf格式,很适合ibatis学习使用
在事务管理方面,Mybatis3.x与Spring的集成更加紧密,可以利用Spring的事务管理功能,实现声明式事务,提升了事务处理的规范性和可维护性。此外,3.x版本还支持使用ExecutorType执行器类型,如SIMPLE、REUSE和BATCH...
在iBatis的配置文件中指定日志实现,例如`<settings><logging implementation="org.apache.ibatis.logging.log4j.Log4jImpl"/></settings>`。 6. **资源加载问题**:iBatis尝试加载Mapper XML文件时可能会出错。...
ibatis,ibatis,ibatis,ibatis,ibatis
在探讨ibatis中的动态SQL(Dynamic SQL)及`prepend`的使用时,我们首先需要对ibatis有一个基本的理解。ibatis是一种开源的数据访问层框架,它简化了Java应用程序与数据库之间的交互过程。通过使用XML配置文件来定义...
Ibatis 是一个优秀的持久层框架,它允许开发者将SQL语句直接写在XML配置文件中,与Java代码解耦,提高了开发效率和代码可维护性。 首先,我们来看如何进行插入操作,即“增”。在Ibatis中,插入数据通常通过`...
《深入解析iBatis核心库:ibatis-core-3.0.jar》 iBatis,一个优秀的持久层框架,以其轻量级、易用性、灵活性等特性深受开发者喜爱。在Java开发领域,iBatis作为数据访问层的解决方案,为数据库操作提供了强大的...
`org.apache.ibatis.annotations.Param`是MyBatis中的一个重要注解,用于处理方法参数映射。 `@Param`注解主要用于SQL查询中的动态参数绑定,尤其是在动态SQL语句中。在MyBatis的映射文件或者Mapper接口中,当我们...
《深入解析iBatis 3.0.0.227核心框架》 iBatis,作为一款优秀的Java持久层框架,一直以来都是开发者们青睐的工具。本文将围绕"ibatis-3-core-3.0.0.227.z"这个压缩包,详细介绍其包含的元素以及相关的知识要点。 ...
DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTD SQL Map Config 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-config-2.dtd"> ``` 这样,XML解析器就能够识别并验证配置文件的结构,确保其遵循Ibatis的规范...
### ibatis3.0中`in`的用法详解 #### 一、引言 在进行数据库查询时,经常会遇到需要根据多个值进行查询的情况,这时`IN`语句就显得尤为重要。`IN`语句可以用于判断某个字段的值是否在一个指定的列表之中,非常适用...
本文将深入探讨Ibatis3.0的核心知识点,包括其设计理念、配置、SQL映射文件、动态SQL、事务管理以及与Spring的整合。 1. **设计理念**:Ibatis的目标是简化数据访问层的开发,将SQL语句和Java代码分离,通过XML或...
ibatis-3-core-3.0.0.242.zip ibatis-3-core-3.0.0.242.zip ibatis-3-core-3.0.0.242.zip ibatis-3-core-3.0.0.242.zip
### Ibatis3.0 + Spring2.5 + Struts2 整合实践 #### 一、项目背景与目的 在本篇文章中,我们将探讨如何将 Ibatis3.0(实际上是 MyBatis 的早期版本,这里可能是指 MyBatis 3.0)、Spring2.5 和 Struts2 这三个...
Ibatis3.0是Mybatis的前身,它提供了一种灵活的方式来映射SQL语句,使得数据库交互变得更加简单。在这个“增删改查(二)”的主题中,我们将继续上一部分的内容,详细介绍如何执行数据库的基本操作。 首先,我们...