﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Tommy Jian 的博客-随笔分类-iBATIS</title><link>http://www.blogjava.net/tommyjian/category/23424.html</link><description>生活就是一个目标，接着一个目标。</description><language>zh-cn</language><lastBuildDate>Fri, 29 Jun 2007 16:45:55 GMT</lastBuildDate><pubDate>Fri, 29 Jun 2007 16:45:55 GMT</pubDate><ttl>60</ttl><item><title>翻译：iBATIS 3.0 草案——使用标注进行配置</title><link>http://www.blogjava.net/tommyjian/archive/2007/06/29/127054.html</link><dc:creator>Tommy Jian</dc:creator><author>Tommy Jian</author><pubDate>Fri, 29 Jun 2007 05:35:00 GMT</pubDate><guid>http://www.blogjava.net/tommyjian/archive/2007/06/29/127054.html</guid><wfw:comment>http://www.blogjava.net/tommyjian/comments/127054.html</wfw:comment><comments>http://www.blogjava.net/tommyjian/archive/2007/06/29/127054.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tommyjian/comments/commentRss/127054.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tommyjian/services/trackbacks/127054.html</trackback:ping><description><![CDATA[<p><strong>使用标注进行配置</strong></p>
<p>&nbsp;&nbsp;&nbsp;标注现在已经很流行了，许多人选择它作为XML的替代来进行元数据编程。标注中不应该包含配置信息，而iBATIS通过XML来进行的工作也不光是配置。</p>
<p>&nbsp;&nbsp;&nbsp;那么什么是配置，什么又不是呢？目前，iBATIS的XML文件包含了三方面：</p>
<ul>
    <li>配置信息</li>
    <li>元数据信息</li>
    <li>代码</li>
</ul>
<p>&nbsp;&nbsp;&nbsp;当您把环境设置改变后，您同时也需要更改配置，例如数据库连接配置、事务管理配置等等。当您将应用分发到不同的数据库，而且也使用了一些专有的SQL语句后，配置中可能还要包含SQL方言的一些配置信息。在iBATIS 3.0中我们可以将这些信息包含进去，因此，您需要针对多种方言进行编码（当然这是手工的），为它们命名，并将它们配置到适当的位置。配置信息不应该被包含在Java源文件中。</p>
<p>&nbsp;&nbsp;&nbsp;元数据信息包括诸如结果映射、参数映射和缓存模型之类的信息。这些信息控制iBATIS如何映射您的数据以及这些映射的具体表现。</p>
<p>&nbsp;&nbsp;&nbsp;编码包括SQL以及动态的SQL语句。</p>
<p>&nbsp;&nbsp;&nbsp;那么标注应该承担什么样的职责呢？</p>
<p>&nbsp;&nbsp;&nbsp;一般情况下，只有元数据信息比较适合使用标注来描述。配置应该通过属性文件或者XML文件来实现。编码也只能通过Java文件或者XML文件来实现。更进一步看，标注只能用来描述相对较简单的元数据信息。有时，标注（特别是在Java中）也会使事情变得更加复杂，使代码更加晦涩难懂。</p>
<p>&nbsp;&nbsp;&nbsp;因为上面的原因，所以我推荐只将标注作为约定配置的替代配置。这就是说，使用这种配置方式可以达到一定的效果，但是也仅仅限于此。</p>
<p>&nbsp;&nbsp;&nbsp;再一次强调，C#的Attribute在某些方面要强于Java的标注：</p>
<ul>
    <li>支持多行字符串，这使得内嵌SQL编码令人感到愉快</li>
    <li>支持使用同一标注多次，而在Java中则需要通过集合标注来实现</li>
    <li>支持顺序和命名参数，这使得代码变得更加简明扼要</li>
</ul>
<p>&nbsp;&nbsp;&nbsp;下面这个例子展示了如何使用Java中的标注来完成配置：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">//<br>// Simple select, string concatenation, inline results(!) and inline parameters<br>//<br>@Select("SELECT #id(EMP_ID:NUMERIC), #firstName(FIRST_NAME:VARCHAR), #lastName(LAST_NAME:VARCHAR) " +<br>"FROM EMPLOYEE")<br>List<employee> selectAllEmployees();<br>//<br>// Alternative syntax using an array of strings instead of string concatenation...can be "smarter" than concatenation<br>//<br>@Select({"SELECT #id(EMP_ID:NUMERIC), #firstName(FIRST_NAME:VARCHAR), #lastName(LAST_NAME:VARCHAR) ",<br>"FROM EMPLOYEE",<br>"WHERE EMP_ID = @id"})<br>Employee selectEmployee(int id);<br>//<br>// Inserts look as you might expect. We can use getGeneratedKeys to get autogen key values, selectkey still supported<br>//<br>@Insert({"INSERT INTO EMPLOYEE (EMP_ID, FIRST_NAME, LAST_NAME)",<br>"VALUES (@id, @firstName, @lastName)"})<br>void insertEmployee(Employee emp);<br>//<br>// Nothing special about update<br>//<br>@Update({"UPDATE EMPLOYEE SET",<br>"EMP_ID=@id(NUMERIC:IN), FIRST_NAME=@firstName(VARCHAR:IN), LAST_NAME=@lastName(VARCHAR:IN)"})<br>void updateEmployee(Employee emp);<br>//<br>// Delete is obvious.<br>//<br>@Delete("DELETE EMPLOYEE WHERE EMP_ID = @id")<br>void deleteEmployee(int id);<br></employee></div>
<br>
<p>&nbsp;&nbsp;&nbsp;下面这个例子要更加复杂一些，像这种使用了如此多的标注的情况就应该考虑使用XML文件来进行配置。这种情况下，我想象标注能够提供一切功能，即XML中实现的功能通过标注也能完成。然而，我们还是建议您在面对复杂的情况时使用XML来进行配置。或许某些人不是特别在意使用XML配置，所以我们为他们提供了标注配置方式。</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">//<br>// complex stuff<br>//<br>@ResultClass (Company.class)<br>@ConstructorResults({<br>@Result(property="id", column="C.COMP_ID"),<br>@Result(property="name", column="C.NAME")<br>})<br>@PropertyResults({<br>@Result(property="departments.id", column="D.DEPT_ID"),<br>@Result(property="departments.name", column="D.NAME"),<br>@Result(property="departments.employee.id", column="E.EMP_ID"),<br>@Result(property="departments.employee.firstName", column="E.FIRST_NAME"),<br>@Result(property="departments.employee.lastName", column="E.LAST_NAME")<br>})<br>@Collections ({<br>@Collection(type=Department.class, property="departments", groupBy="id"),<br>@Collection(type=Employee.class, property="departments.employees", groupBy="departments.id")<br>})<br>@Select("SELECT #id, #name, " +<br>"#departments.id, #departments.name, " +<br>"#departments.employees.id, #departments.employees.firstName, " +<br>"#departments.employees.lastName " +<br>"FROM COMPANY C, DEPARTMENT D, EMPLOYEE E " +<br>"WHERE D.DEPT_ID = E.DEPT_ID " +<br>"AND C.COMP_ID = D.COMP_ID")<br>List<company> selectAllCompaniesWithJoin();<br>/*<br>* NESTED QUERIES<br>*/<br>@ResultClass (Company.class)<br>@FieldResults({<br>@Result(property="id", column="COMP_ID"),<br>@Result(property="name", column="NAME")<br>})<br>@PropertyResults({<br>@Result(property="departments",<br>nestedQuery=@QueryMethod(type=CompanyMapper.class, methodName="getDepartmentsForCompany", parameters="id"))<br>})<br>@Select("SELECT #id, #name FROM COMPANY C ")<br>List<company> selectAllCompaniesWithNestedQueries();<br>@ResultClass (Department.class)<br>@PropertyResults({<br>@Result(property="id", column="DEPT_ID"),<br>@Result(property="name", column="NAME"),<br>@Result(property="employees",<br>nestedQuery=@QueryMethod(type=CompanyMapper.class, methodName="getEmployeesForDeparment", parameters="id"))<br>})<br>@Select("SELECT #id, #name FROM DEPARTMENT WHERE COMP_ID = @id ")<br>List<department> getDepartmentsForCompany(int id);<br>@ResultClass (Employee.class)<br>@PropertyResults({<br>@Result(property="id", column="EMP_ID"),<br>@Result(property="firstName", column="FIRST_NAME"),<br>@Result(property="lastName", column="LAST_NAME")<br>})<br>@Select("SELECT #id, #firstName, #lastName FROM EMPLOYEE WHERE EMP_ID = @id ")<br>List<employee> getEmployeesForDepartment(int id);<br></employee></department></company></company></div><img src ="http://www.blogjava.net/tommyjian/aggbug/127054.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tommyjian/" target="_blank">Tommy Jian</a> 2007-06-29 13:35 <a href="http://www.blogjava.net/tommyjian/archive/2007/06/29/127054.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>翻译：iBATIS 3.0 草案——约定俗成的配置方式</title><link>http://www.blogjava.net/tommyjian/archive/2007/06/26/126256.html</link><dc:creator>Tommy Jian</dc:creator><author>Tommy Jian</author><pubDate>Tue, 26 Jun 2007 01:47:00 GMT</pubDate><guid>http://www.blogjava.net/tommyjian/archive/2007/06/26/126256.html</guid><wfw:comment>http://www.blogjava.net/tommyjian/comments/126256.html</wfw:comment><comments>http://www.blogjava.net/tommyjian/archive/2007/06/26/126256.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tommyjian/comments/commentRss/126256.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tommyjian/services/trackbacks/126256.html</trackback:ping><description><![CDATA[<p><strong>约定俗成</strong></p>
<p>&nbsp;&nbsp;&nbsp;<strong>Clinton说：</strong>这一点是与我们以前所坚持的原则不相符合的。认识我的人都知道我基本上算是一个完美的人。但是如果我们从最佳实践的角度去考虑，我们必须在解决复杂问题的时候也使用尽量简单的解决方案。当然，那些不太喜欢约定俗成式配置的人可以忽略这种配置方式。但是我相信这是非常有用的，特别是对插入、删除和更新操作来说。使用这种配置方式，一些简单的查询也将从中受益。</p>
<p>&nbsp;&nbsp;&nbsp;默认情况下，iBATIS 3.0将使用约定俗成式的配置方式。Java 5的方法语义中已经包含了生成SQL、进行参数和结果映射足够的信息。例如：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">Employee getEmployee (int id);</div>
<br>
<p>&nbsp;&nbsp;&nbsp;这些信息对于生成以下SQL已经足够了：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">SELECT id, firstName, lastName FROM Employee WHERE id = ?</div>
<br>
<p>&nbsp;&nbsp;&nbsp;结果类型与方法的返回值类型是一致的。因为方法的返回值类型不是集合类型，所以我们知道正在处理&#8220;Select One&#8221;语义。表的名称被假定为与结果类型的名称一致。而查询参数就被假定为方法对应的参数。在使用其他的配置方式的时候，我们可以更改默认ID参数的配置。SQL语句中的各数据列假定与方法返回类型的同名属性一一对应，当然这些配置都是可以更改的。</p>
<p>&nbsp;&nbsp;&nbsp;集合类型也是以同样的方式工作：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">List<employee> listAllEmployees ();</employee></div>
<br>
<p>&nbsp;&nbsp;&nbsp;这个例子将产生以下SQL语句：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">SELECT id, firstName, lastName FROM Employee</div>
<br>
<p>&nbsp;&nbsp;&nbsp;我们可以将这个例子叫做&#8220;Select Many&#8221;，因为这个方法返回了一个集合类型。我们知道Where子句为空，因为这个方法没有任何参数。</p>
<p>&nbsp;&nbsp;&nbsp;如果我们想使用参数式查询，我们可以这样来做：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">List<employee> findEmployeesLike(Employee employee);</employee></div>
<br>
<p>&nbsp;&nbsp;&nbsp;假设只有参数的lastName，而其他引用类型都为null值，原始类型都被设置为非法无意义的值（比如-1），我们将得到以下的SQL语句：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">SELECT id, firstName, lastName FROM Employee WHERE lastName = 'Begin'</div>
<br>
<p>&nbsp;&nbsp;&nbsp;或者可以直接按参数来进行：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">List<employee> findEmployeeByLastNameAndFirstName (String last, String first);</employee></div>
<br>
<p>&nbsp;&nbsp;&nbsp;这将生成以下的SQL语句：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">SELECT id, firstName, lastName FROM Employee WHERE lastName = 'Begin' AND firstName = 'Clinton'</div>
<br>
<p>&nbsp;&nbsp;&nbsp;因为C#支持参数名称的反射，所以C#对这种方法提供了更好的支持。形式上也变得相对清晰，当然实质是一样的：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">// C#<br>IList<employee> FindEmployeesLike(string lastName, string firstName);<br>// And in C# 3.0, we can use anonymous types:<br>IList<employee> FindEmployeesLike(object obj);<br>//...<br>IList<employee> employees = mapper.FindEmployeesLike(new {LastName="Begin", FirstName="Clinton"});<br></employee></employee></employee></div>
<br>
<p>&nbsp;&nbsp;&nbsp;更新操作也以相同的方式操作：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">void insertEmployee (Employee emp);<br>void updateEmployee (Employee emp);<br>void deleteEmployee (Employee emp);</div>
<br>
<p>&nbsp;&nbsp;&nbsp;也可以自动接受集合参数：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">int insertEmployee (List<employee> emps); // returns rows inserted<br>int updateEmployee (List<employee> emps); // returns rows updated<br>int deleteEmployee (List<employee> emps); // returns rows deleted</employee></employee></employee></div>
<br>
<p>&nbsp;&nbsp;&nbsp;生成器相当的灵活，而且可以为大多数删除甚至更新操作生成一条SQL语句。</p><img src ="http://www.blogjava.net/tommyjian/aggbug/126256.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tommyjian/" target="_blank">Tommy Jian</a> 2007-06-26 09:47 <a href="http://www.blogjava.net/tommyjian/archive/2007/06/26/126256.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>翻译：iBATIS 3.0 草案——多种配置方式</title><link>http://www.blogjava.net/tommyjian/archive/2007/06/22/125784.html</link><dc:creator>Tommy Jian</dc:creator><author>Tommy Jian</author><pubDate>Fri, 22 Jun 2007 03:23:00 GMT</pubDate><guid>http://www.blogjava.net/tommyjian/archive/2007/06/22/125784.html</guid><wfw:comment>http://www.blogjava.net/tommyjian/comments/125784.html</wfw:comment><comments>http://www.blogjava.net/tommyjian/archive/2007/06/22/125784.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tommyjian/comments/commentRss/125784.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tommyjian/services/trackbacks/125784.html</trackback:ping><description><![CDATA[<p><strong>多种配置方式</strong></p>
<p>&nbsp;&nbsp;&nbsp;iBATIS中最古老的就是其配置方式。在项目开始的时候，XML被认为最好的配置方式。事实上，XML现在还是比较好的配置方法，因为它是进行复杂的多行SQL配置的最佳方式。因此，XML的配置方式将予以保留。但是它不再是默认的配置方式，而且也不见得是大多数应用的首选。</p>
<p>&nbsp;&nbsp;&nbsp;iBATIS 3.0将使用多种配置方式。这就是说iBATIS将可以使用多种方式进行配置，而且这些方式可以协同工作。按照实用性排序，有以下四种方法：</p>
<ul>
    <li>约定俗成</li>
    <li>Java的标识（可以覆盖前一种配置的配置信息）</li>
    <li>XML（可以覆盖前两种配置的配置信息）</li>
    <li>Java API（可以覆盖以上配置的配置信息）</li>
</ul><img src ="http://www.blogjava.net/tommyjian/aggbug/125784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tommyjian/" target="_blank">Tommy Jian</a> 2007-06-22 11:23 <a href="http://www.blogjava.net/tommyjian/archive/2007/06/22/125784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>翻译：iBATIS 3.0 草案——事务、会话和工厂类——MapperFactory</title><link>http://www.blogjava.net/tommyjian/archive/2007/06/20/125358.html</link><dc:creator>Tommy Jian</dc:creator><author>Tommy Jian</author><pubDate>Wed, 20 Jun 2007 08:00:00 GMT</pubDate><guid>http://www.blogjava.net/tommyjian/archive/2007/06/20/125358.html</guid><wfw:comment>http://www.blogjava.net/tommyjian/comments/125358.html</wfw:comment><comments>http://www.blogjava.net/tommyjian/archive/2007/06/20/125358.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tommyjian/comments/commentRss/125358.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tommyjian/services/trackbacks/125358.html</trackback:ping><description><![CDATA[<p><strong>事务、会话和工厂类——MapperFactory</strong></p>
<p>&nbsp;&nbsp;&nbsp;我们应该在何处获取&#8220;Mapper&#8221;的实例呢？我们仍然需要一个核心类来完成iBATIS的配置和控制。这个核心类的名称尚在争论之中，但是我们不妨先叫它MapperFactory。</p>
<p>&nbsp;&nbsp;&nbsp;通常情况下，MapperFactory负责构建事务和映射类的实例。而MapperFactory本身将由某个配置类来构建。</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">MapperFactory factory = someConfiguration.buildMapperFactory();<br>EmployeeMapper employeeMapper = factory.getMapper (EmployeeMapper.class);</div>
<p>&nbsp;&nbsp;&nbsp;对于这种方式是不是会使事情变得简单...或许会吧！至于事务，Clinton是这样说的：&#8220;会话的概念应该和事务的进行合并。在iBATIS中，会话和事务很多时候是一致甚至是一样的。但是它们因为一些人为的架构方面的原因而被分开了。会话或许能够完成不少任务，但是其中的80%并不适合用会话来解决。同样的，批处理操作也从事务中分离出来，因为事务在提供批处理功能是往往会导致令人生厌的try/finally的多重嵌套。因此在我们发现真实的需求之前应该尽量避免这些。&#8221;。</p>
<p>&nbsp;&nbsp;&nbsp;iBATIS或者其他第三方库及容器都可以进行事务处理。目前，事务的处理是由SqlMapClient实例中的ThreadLocal实例来处理的。因为这种处理方法，我们配到了不少问题。不是出于技术的原因而是因为代码更加清晰，我们可以使用以下的方法：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">Transaction tx = factory.startTransaction();<br>try <br>{<br>&nbsp;&nbsp;// do work<br>&nbsp;&nbsp;tx.commit();<br>}<br> finally<br> {<br>&nbsp;&nbsp;tx.end();<br>}</div>
<p>&nbsp;&nbsp;&nbsp;批处理操作可以简单地通过启动支持批处理操作的事务来进行：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">Transaction tx = factory.startBatch();<br>try <br>{<br>&nbsp;&nbsp;// do work<br>&nbsp;&nbsp;// balk executes current batch immediately, returns total rows updated<br>&nbsp;&nbsp;// (balks on non-batched transactions)<br>&nbsp;&nbsp;int totalRowCount = tx.flush();<br>&nbsp;&nbsp;// commit executes batch too, returns total rows updated and commits<br>&nbsp;&nbsp;totalRowCount = tx.commit();<br>} <br>finally<br> {<br>&nbsp;&nbsp;tx.end();<br>}</div>
<p>&nbsp;&nbsp;&nbsp;与现在的事务的API类似，我们对事务的隔离级别以及其他选项提供支持。</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">Transaction tx = factory.startTransaction(isolationLevel);<br>try <br>{<br>&nbsp;&nbsp;// do work<br>&nbsp;&nbsp;tx.commit();<br>}<br> finally<br> {<br>&nbsp;&nbsp;tx.end();<br>}</div>
<p>&nbsp;&nbsp;&nbsp;如果第三方的库提供了事务处理的支持，那么受托管理的连接对象可以作为参数传入：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">// Can be handled by encapsulating framework (e.g. Spring)<br>Transaction tx = factory.useConnection(conn);<br>try<br> {<br>&nbsp;&nbsp;//...do work...<br>&nbsp;&nbsp;tx.flush(); // executes batched updates immediately<br>&nbsp;&nbsp;// commit simply calls commit on the connection<br>&nbsp;&nbsp;// if local commits are allowed, otherwise it is ignored.<br>&nbsp;&nbsp;tx.commit();<br>}<br> finally<br> {<br>&nbsp;&nbsp;tx.end(); // Can also be handled by encapsulating framework (e.g. Spring)<br>}</div>
<p>&nbsp;&nbsp;&nbsp;总之，这样的API十分的简洁，而且易于与诸如Spring这样的第三方框架集成。MapperFactory可以被注入到需要事务管理、批处理和隔离级别的Spring的DAO对象中。为了进一步进行必要的分离，我们可以将事务管理功能从MapperFactory中分离出来，甚至于允许开发者定义自己的事务管理接口，同时将事务管理的功能绑定到类中（这样提供了更加松耦合的架构）。</p><img src ="http://www.blogjava.net/tommyjian/aggbug/125358.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tommyjian/" target="_blank">Tommy Jian</a> 2007-06-20 16:00 <a href="http://www.blogjava.net/tommyjian/archive/2007/06/20/125358.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>翻译：iBATIS 3.0 草案——接口绑定</title><link>http://www.blogjava.net/tommyjian/archive/2007/06/19/125161.html</link><dc:creator>Tommy Jian</dc:creator><author>Tommy Jian</author><pubDate>Tue, 19 Jun 2007 09:40:00 GMT</pubDate><guid>http://www.blogjava.net/tommyjian/archive/2007/06/19/125161.html</guid><wfw:comment>http://www.blogjava.net/tommyjian/comments/125161.html</wfw:comment><comments>http://www.blogjava.net/tommyjian/archive/2007/06/19/125161.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/tommyjian/comments/commentRss/125161.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tommyjian/services/trackbacks/125161.html</trackback:ping><description><![CDATA[<p><strong>接口绑定</strong></p>
<p>&nbsp;&nbsp;&nbsp;随着Java 5的推广，我们有机会来改善用户体验。其中最重要的是借助Java 5可以消除令人生惑的类型转换，可以消除SQL映射基于字符的调用方式。举例来说，现在在调用SQL映射的时候是这样的：</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">Employee employee = (Employee)sqlMapper.queryForList("getEmployee", 5);<br>//...and...<br>List employees = sqlMapper.queryForList("listAllEmployees");</div>
<p>&nbsp;&nbsp;&nbsp;问题是很明显的。第一，上面的两个例子中被映射的语句的名称都是基于字符串的，而这很容易导致错误。这种方式也不会得到IDE工具、编译器的支持和管理。</p>
<p>&nbsp;&nbsp;&nbsp;第二个问题是存在参数和返回值类型安全问题。在第一个例子中，谁能保证参数的类型一定是Integer？而谁又能保证您得到的返回值一定是Employee类型呢？这里，编译器也不会给出任何偿错误报告和提示。而只有运行时异常会被抛出。</p>
<p>&nbsp;&nbsp;&nbsp;最后，在集合的例子中问题也是相同的。在运行前，您可能会获得Dogs的集合，而不是Employees。</p>
<p>&nbsp;&nbsp;&nbsp;总之，这种方式虽然比JDBC强，但是也让人倍感难受，还是存在改善的空间。</p>
<p>&nbsp;&nbsp;&nbsp;在Java 5中我们可以充分使用范型来规范集合类型。这样，我们不需要进行特殊的配置就可以为集合类型建立一致的API。我们不需要在XML文件中声明类型，不需要通过字符名称来调用被映射的语句，相反，我们可以充分利用表达好且类型安全的接口类型。没有什么新东西需要学习，只是普通的接口就可以了。</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">public interface EmployeeMapper <br>{&nbsp; <br>&nbsp;&nbsp;Employee getEmployee (int employeeId);&nbsp; <br>&nbsp;&nbsp;List<employee> listAllEmployees();<br>}</employee></div>
<p>&nbsp;&nbsp;&nbsp;这就够了！iBATIS来帮我们实现这个接口。</p>
<p>&nbsp;&nbsp;&nbsp;现在我们可以以一种更加简洁和安全的方式来调用被映射的语句了。</p>
<div style="border: 2px dotted ; background-color: #99ccff; font-family: Courier New,Courier; font-size: small;">Employee emp = empMapper.getEmployee(5);<br>//...and...<br>List<employee> employees = empMapper.listAllEmployees();</employee></div>
<p>&nbsp;&nbsp;&nbsp;在上面的调用中没有类型转换、没有字符串，而且参数和返回值的类型是、安全的。额外的代码就是针对接口使用XML或者Java的标识进行配置。最多我们只需要配置SQL语句、需要进行重载的参数或者返回值类型。</p>
<p>&nbsp;&nbsp;&nbsp;接口描述了所需要的一切。</p>
<ul>
    <li>语句的名称（默认情况下与方法的名字一致）</li>
    <li>参数类型（如果存在的话）</li>
    <li>返回值类型（包括范型集合的元素的类型）</li>
</ul>
<p>&nbsp;&nbsp;&nbsp;而其中最有趣的就是我们可以基于方法名称这样的约定来生成SQL映射。以后关于配置的章节中将详细讨论这些细节。</p>
<p>&nbsp;&nbsp;&nbsp;接口绑定的方法使得诸如Spring这样的框架将映射类注入其他类变得容易，同时也不需要将事务管理的过多细节公开。</p><img src ="http://www.blogjava.net/tommyjian/aggbug/125161.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tommyjian/" target="_blank">Tommy Jian</a> 2007-06-19 17:40 <a href="http://www.blogjava.net/tommyjian/archive/2007/06/19/125161.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>