朗志工作室(Langzhi Studio)

江浙沪一带找工作中,欢迎联系
方向:爬虫、搜索 技术:python,rails,node.js

  博客园 :: 首页 :: 联系 :: 订阅 订阅 :: 管理
  5662 Posts :: 2 Stories :: 515 Comments :: 7 Trackbacks

公告

2012年2月12日 #

IBatis.Net学习笔记十二:发现一个好用的IBatis.Net生成工具

发现一个好用的IBatis.Net生成工具,可以根据数据库自动生成domain和xml文件,名称是MyGeneration

我试用了一下,效果不错。
详细介绍参见它的主页:http://www.mygenerationsoftware.com/portal/default.aspx

支持的语言为:C#,vb.net
支持的数据库有:Microsoft SQLOracleIBM DB2,   PostgreSQLMicrosoft AccessFireBirdInterbaseVistaDBSQLiteMySQL,  Advantage and Pervasive
支持的架构有:dOOdadsEntitySpacesEasyObjects.NET/EntLibGentle.NETOpf3NHibernateMicrosoft's DAAB,  DotNetNukeiBatis

也就是说这个工具是根据模板配置的,你也可以写一个自己的模板,来生成自己需要的格式的代码文件,比较方便灵活。
目前已经提供了一些常用的ORM框架的模板

下载地址:http://www.download.com/3001-10252_4-10685426.html?spi=76243c3b641e877670346e8d0bffceb9

IBatis模板的下载地址:http://www.mygenerationsoftware.com/TemplateLibrary/Archive/?guid=19d6d575-13f0-4aad-b887-e8ff7b6b17b2

posted @ 2012-02-12 22:52 lexus 阅读(69) 评论(0) 编辑

[置顶] ibatis 实现 物理级别的 分页 兼容多种数据库(转载)

分类: spring.net+ibatis.net+codeSmith软件框架开发及应用 299人阅读 评论(0) 收藏 举报

最近在看iBatis时,想做用动态Sql做个分布。因为在做项目时用iBator工具生成没有分页的功能,只有一些我们常用的功能。所以要对生成后的代码做修改。我在Java高手真经的一书中看到有做了MySql SqlServer Oracle的分页。实现如下:
MySql-->
首先说说MySql的分页语句

Sql代码
  1. select  *  from   user   where ... order   by ... limit 10,25     
    根据以上的语句我们可以对ibator生成后的代码进行修改。
    第一修改User_sqlMap.xml
    修改前
Xml代码
  1. < select   id = "ibatorgenerated_selectByExample"           resultMap = "ibatorgenerated_BaseResultMap"   
  2.      parameterClass = "com.demo.ibatis.beans.UserExample" >   
  3.     select ID, LOGIN_NAME, PASSWORD   
  4.     from user   
  5.      < isParameterPresent >   
  6.          < include   refid = "user.ibatorgenerated_Example_Where_Clause"   />   
  7.                 < isNotNull   property = "orderByClause" >   
  8.                 order by $orderByClause$   
  9.                         </ isNotNull >   
  10.          </ isParameterPresent >   
  11. </ select >   


修改后

Xml代码
  1. < select   id = "ibatorgenerated_selectByExample"   resultMap = "ibatorgenerated_BaseResultMap"   
  2.          parameterClass = "com.demo.ibatis.beans.UserExample" >   
  3.         select ID, LOGIN_NAME, PASSWORD   
  4.         from user   
  5.      < isParameterPresent >   
  6.          < include   refid = "user.ibatorgenerated_Example_Where_Clause"   />   
  7.              < isNotNull   property = "orderByClause" >   
  8.                 order by $orderByClause$   
  9.                          </ isNotNull >   
  10.             [b] < isNotNull   property = "limitClauseStart" >   
  11.                 limit   
  12.                 $limitClauseStart$,$limitClauseCount$   
  13.              </ isNotNull > [/b]   
  14.      </ isParameterPresent >   
  15. </ select >   


重要的是黑色的字体是添加到原来的xml中的。接下来修改UserExample.java
在该类中添加两个字段和相应的getter/setter方法

Java代码
  1. protected  String limitClauseStart; //起始参数   
  2. protected  String limitClauseCount; //数量参数   


接下来就可以通过Dao调用selectByExample()方法测试,好的以上就是MySql的分页。SqlServer的分页比较难了,因为 SqlServer中没有limit的关键字。
看看SqlServer的分页语句,那当然 SqlServer人分布方法有很多种。这里我采用其中的一种。
语句如下:

Sql代码
  1.    SELECT   TOP  页大小 *   
  2.    FROM  TestTable   
  3.    WHERE  (ID  NOT   IN   
  4.           ( SELECT   TOP  页大小*页数 id   
  5.           FROM  表   
  6.           ORDER   BY  id))   
  7. ORDER   BY  ID  


接下来和上面的MySql一样也进行修改
修改xml

Xml代码
  1. < select   id = "ibatorgenerated_selectByExample"   resultMap = "ibatorgenerated_BaseResultMap"   
  2.          parameterClass = "com.demo.ibatis.beans.UserExample" >   
  3.         [b]  < isNotNull   property = "limitClauseStart" >   
  4.             SELETE TOP $limitClauseCount$ * FROM user where (ID NOT IN    
  5.                        (SELECT TOP $limitClauseStart$ ID    
  6.                    </ isNotNull > [/b]   
  7.                     < isNull   property = "limitClauseStart" >   
  8.             SELETE *    
  9.            </ isNull >   
  10.                     FROM user    
  11.         from user   
  12.      < isParameterPresent >   
  13.          < include   refid = "user.ibatorgenerated_Example_Where_Clause"   />   
  14.              < isNotNull   property = "orderByClause" >   
  15.                 order by $orderByClause$   
  16.                                [b]   < isNotNull   property = "limitClauseStart" >   
  17.                      ))order by $orderByClause$   
  18.                      </ isNotNull > [/b]   
  19.                          </ isNotNull >   
  20.      </ isParameterPresent >   
  21. </ select >   
    接下来是ORacle的,和上面都是差不多的这里不多说。
    语法:
    select* from(select rownum tid,user.* FROM (select * from user where id>1 order by ID desc)user where where rownum<35) where tid>10;
    修改Xml,
Xml代码
  1. < select   id = "ibatorgenerated_selectByExample"       resultMap = "ibatorgenerated_BaseResultMap"   
  2.          parameterClass = "com.demo.ibatis.beans.UserExample" >   
  3.         [b]  < isNotNull   property = "limitClauseStart" >   
  4.             select* from(select rownum tid,user.* FROM (   
  5.                    </ isNotNull > [/b]   
  6.                    select * from user   
  7.      < isParameterPresent >   
  8.          < include   refid = "user.ibatorgenerated_Example_Where_Clause"   />   
  9.              < isNotNull   property = "orderByClause" >   
  10.                 order by $orderByClause$                 
  11.                          </ isNotNull >   
  12.                         [b]   < isNotNull   property = "limitClauseStart" >   
  13.                     <![[CDATA )user where where rownum<$limitClauseCount$+$limitClauseStart$+1) where tid>$limitClauseStart$;]]>   
  14.                   </ isNotNull > [/b]   
  15.      </ isParameterPresent >   
  16. </ select >    

posted @ 2012-02-12 22:46 lexus 阅读(15) 评论(0) 编辑

[置顶] ibatis 实现 物理级别的 分页 兼容多种数据库(转载)

分类: spring.net+ibatis.net+codeSmith软件框架开发及应用 299人阅读 评论(0) 收藏 举报

最近在看iBatis时,想做用动态Sql做个分布。因为在做项目时用iBator工具生成没有分页的功能,只有一些我们常用的功能。所以要对生成后的代码做修改。我在Java高手真经的一书中看到有做了MySql SqlServer Oracle的分页。实现如下:
MySql-->
首先说说MySql的分页语句

Sql代码
  1. select  *  from   user   where ... order   by ... limit 10,25     
    根据以上的语句我们可以对ibator生成后的代码进行修改。
    第一修改User_sqlMap.xml
    修改前
Xml代码
  1. < select   id = "ibatorgenerated_selectByExample"           resultMap = "ibatorgenerated_BaseResultMap"   
  2.      parameterClass = "com.demo.ibatis.beans.UserExample" >   
  3.     select ID, LOGIN_NAME, PASSWORD   
  4.     from user   
  5.      < isParameterPresent >   
  6.          < include   refid = "user.ibatorgenerated_Example_Where_Clause"   />   
  7.                 < isNotNull   property = "orderByClause" >   
  8.                 order by $orderByClause$   
  9.                         </ isNotNull >   
  10.          </ isParameterPresent >   
  11. </ select >   


修改后

Xml代码
  1. < select   id = "ibatorgenerated_selectByExample"   resultMap = "ibatorgenerated_BaseResultMap"   
  2.          parameterClass = "com.demo.ibatis.beans.UserExample" >   
  3.         select ID, LOGIN_NAME, PASSWORD   
  4.         from user   
  5.      < isParameterPresent >   
  6.          < include   refid = "user.ibatorgenerated_Example_Where_Clause"   />   
  7.              < isNotNull   property = "orderByClause" >   
  8.                 order by $orderByClause$   
  9.                          </ isNotNull >   
  10.             [b] < isNotNull   property = "limitClauseStart" >   
  11.                 limit   
  12.                 $limitClauseStart$,$limitClauseCount$   
  13.              </ isNotNull > [/b]   
  14.      </ isParameterPresent >   
  15. </ select >   


重要的是黑色的字体是添加到原来的xml中的。接下来修改UserExample.java
在该类中添加两个字段和相应的getter/setter方法

Java代码
  1. protected  String limitClauseStart; //起始参数   
  2. protected  String limitClauseCount; //数量参数   


接下来就可以通过Dao调用selectByExample()方法测试,好的以上就是MySql的分页。SqlServer的分页比较难了,因为 SqlServer中没有limit的关键字。
看看SqlServer的分页语句,那当然 SqlServer人分布方法有很多种。这里我采用其中的一种。
语句如下:

Sql代码
  1.    SELECT   TOP  页大小 *   
  2.    FROM  TestTable   
  3.    WHERE  (ID  NOT   IN   
  4.           ( SELECT   TOP  页大小*页数 id   
  5.           FROM  表   
  6.           ORDER   BY  id))   
  7. ORDER   BY  ID  


接下来和上面的MySql一样也进行修改
修改xml

Xml代码
  1. < select   id = "ibatorgenerated_selectByExample"   resultMap = "ibatorgenerated_BaseResultMap"   
  2.          parameterClass = "com.demo.ibatis.beans.UserExample" >   
  3.         [b]  < isNotNull   property = "limitClauseStart" >   
  4.             SELETE TOP $limitClauseCount$ * FROM user where (ID NOT IN    
  5.                        (SELECT TOP $limitClauseStart$ ID    
  6.                    </ isNotNull > [/b]   
  7.                     < isNull   property = "limitClauseStart" >   
  8.             SELETE *    
  9.            </ isNull >   
  10.                     FROM user    
  11.         from user   
  12.      < isParameterPresent >   
  13.          < include   refid = "user.ibatorgenerated_Example_Where_Clause"   />   
  14.              < isNotNull   property = "orderByClause" >   
  15.                 order by $orderByClause$   
  16.                                [b]   < isNotNull   property = "limitClauseStart" >   
  17.                      ))order by $orderByClause$   
  18.                      </ isNotNull > [/b]   
  19.                          </ isNotNull >   
  20.      </ isParameterPresent >   
  21. </ select >   
    接下来是ORacle的,和上面都是差不多的这里不多说。
    语法:
    select* from(select rownum tid,user.* FROM (select * from user where id>1 order by ID desc)user where where rownum<35) where tid>10;
    修改Xml,
Xml代码
  1. < select   id = "ibatorgenerated_selectByExample"       resultMap = "ibatorgenerated_BaseResultMap"   
  2.          parameterClass = "com.demo.ibatis.beans.UserExample" >   
  3.         [b]  < isNotNull   property = "limitClauseStart" >   
  4.             select* from(select rownum tid,user.* FROM (   
  5.                    </ isNotNull > [/b]   
  6.                    select * from user   
  7.      < isParameterPresent >   
  8.          < include   refid = "user.ibatorgenerated_Example_Where_Clause"   />   
  9.              < isNotNull   property = "orderByClause" >   
  10.                 order by $orderByClause$                 
  11.                          </ isNotNull >   
  12.                         [b]   < isNotNull   property = "limitClauseStart" >   
  13.                     <![[CDATA )user where where rownum<$limitClauseCount$+$limitClauseStart$+1) where tid>$limitClauseStart$;]]>   
  14.                   </ isNotNull > [/b]   
  15.      </ isParameterPresent >   
  16. </ select >    

posted @ 2012-02-12 22:46 lexus 阅读(10) 评论(0) 编辑

数据存储层:Oracle

业务层:.Net

UI:Flex

术语:Oracle,.Net,IBatis,Castle,Flex,CodeSmith

建立Oracle数据表

image

生成代码

用CodeSmith 建立Oracle连接 

image

打开定义好的MapsConfig.cst模板 生成IBatis 使用的 SQLMap  SQL定义的XML文件

 

image

把另存为的XML文件,重新命名复制到UI项目的Maps目录下

image

再选择下面模板文件生成,方式一样都是选择相同的表

ServiceTemplate.cst

DaoTemplate.cst

IDaoTemplate.cst

DoMainTemplate.cst

2009-10-27_131831

 

 

把Dao和IDao文件复制到的相应项目新建目录下

image

把Service文件复制到相应的项目新建目录下

image

把DoMainTemplate.cst复制到Po项目中

将生成好的文件也改名字,与原有系统命名一致,开始项目调试,此时编译会出错。

image

开始调试

1.SVN在更新项目的时候如果把csproj项目文件冲突之后,会造成项目加载不起来

可以右键编辑删除这个项目的csproj文件中冲突的部分,再重新加载项目即可成功。

2.SVN在提交的时候遇到冲突的问题

可以右键红色的冲突项目,选择回滚或者更新至最新版本尝试

image

提交和更新完版本之后,开始调试项目中刚刚加入的文件

打开Po项目中的Suppliers.cs文件

更新命名空间

namespace Ebao51Net.Po.SuppliersModule

更新生成中错误的地方

        /// <summary>
        /// 0 未启用
1 已启用
2 暂停中
        /// </summary>
        private Int32 status;
        /// <summary>
        /// 0 未启用
1 已启用
2 暂停中
        /// </summary>
        public Int32  Status
        {
            get{return status;}
            set{status = value;}
        }    

更新后

/// <summary>
        /// 0 未启用
        /// 1 已启用
        /// 2 暂停中
        /// </summary>
        private Int32 status;
        /// <summary>
        /// 
        /// </summary>
        public Int32  Status
        {
            get{return status;}
            set{status = value;}
        }    

 

打开Persistence项目ISuppliersDao.cs与其他项目对比

image

添加Po的项目引用

using Ebao51Net.Po.SuppliersModule;

替换CodeSmith根据数据表名生成的实体及方法名称,使用当前文件替换成类名即可

image

修改SuppliersDao.cs文件

更改命名空间和添加引用空间名

using Ebao51Net.Po.SuppliersModule;
using Ebao51Net.Persistence.DataAccess;

namespace Ebao51Net.Persistence.SuppliersModule

 

 

 

 

 

替换成员名

image

打开Service项目的SuppliersManager.cs文件

删除错误的引用

using Payment.Persistence.PayMentModule;
using Payment.Po.PayMentModule;

修改命名空间,添加代码引用

using Ebao51Net.Po.SuppliersModule;
using Ebao51Net.Persistence.SuppliersModule;

namespace Ebao51Net.Services.SuppliersModule

替换

image

将SuppliersDAO 修改成SuppliersDao 有三处要修改

编译一下整个解决方案,发现有几处错误,不是与刚才的过程有关的,是由于之前其他同事修改造成的

签入一下代码

配置部分

 

image

配置 SqlMap.config 添加SQLMap的XML定义,添加:

<!--供应商-->
        <sqlMap resource="${root}Suppliers.xml" />
 
配置 Daos.config 添加定义,
<!--供应商-->
        <component id="SuppliersDao" service="Ebao51Net.Persistence.SuppliersModule.ISuppliersDao, Ebao51Net.Persistence"  type="Ebao51Net.Persistence.SuppliersModule.SuppliersDao, Ebao51Net.Persistence"  >
            <parameters>
                <commonMapperFactory>${commonMapperFactory}</commonMapperFactory>
            </parameters>
        </component>
 
SuppliersDao是在以下用的的名字
namespace Ebao51Net.Services.SuppliersModule
{
    public class SuppliersManager : ServiceBase
    {
        private ISuppliersDao SuppliersDao;
        public SuppliersManager()
        {
            SuppliersDao = GetDao<ISuppliersDao>("SuppliersDao");
        }
 

修改生成的XML需要修改Suppliers.xml 文件,在ServiceUI的Maps目录下

删掉

<typeAlias alias="SuppliersTab" type="IBCS.Domain.ContractUI.Maps.Suppliers, IBCS.Domain" />
换成
 <typeAlias alias="Suppliers" type="Ebao51Net.Po.SuppliersModule.Suppliers, Ebao51Net.Po" />

替换

image

修改

 

<insert id="Suppliers.Insert" parameterClass="Suppliers">
            INSERT INTO PD_SUPPLIERS_TAB (ID,INSURE_ID,CODE,NAME,SHORT_NAME,PROVINCE,CITY,AREA,STATUS,REMARK,CREATE_TIME,UPDATE_TIME,PHONE,LINKMAN,BANKNAME,BANKNUMBER,CLEARINGMODE,COOPERATEMODE)
             VALUES (#Id#,#InsureId#,#Code#,#Name#,#ShortName#,#Province#,#City#,#Area#,#Status#,#Remark#,#CreateTime#,#UpdateTime#,#Phone#,#Linkman#,#Bankname#,#Banknumber#,#Clearingmode#,#Cooperatemode#)
            <selectKey resultClass="int" type="pre" property="Id" >
           修改这句为下图 -->    SELECT SEQ_PD_SUPPLIER.NEXTVAL AS VALUE FROM DUAL
            </selectKey> 
        </insert>
image 
方法功能就是主键自增量
 

修改Properties.config文件,查看连接数据库字符串是否正确

<settings>
    <add key="provider" value="oracleClient2.0"/>
    <add key="connectionString" value="Data Source=11;Persist Security Info=True;User ID=11;Password=11;Unicode=True"/>
    <add key="root" value="Maps\" />
    <add key="assembly" value="ebao51.ServiceUI"/>
</settings>

 

 

 

 

 

使用测试

添加一条记录,看一下结果

using Ebao51Net.Services.SuppliersModule;
using Ebao51Net.Po.SuppliersModule;

namespace ServiceUI
{
    public partial class EditSuppliers : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            SuppliersManager sm = new SuppliersManager();
            Suppliers su=new Suppliers();
            su.Name = "Name1";
            sm.AddSuppliers(su);
        }
    }
}
posted @ 2012-02-12 22:40 lexus 阅读(10) 评论(0) 编辑

关于IBatisNet的两个简单CodeSmith模板

2006-08-25 12:47 by Anders Cui, 2297 visits, 收藏, 编辑

最近使用了下IBatisNet,感受到了它的灵活和强大,但是如果手工去写配置文件和实体类,确实很麻烦。
我参考CodeSmith的范例文件,做出了两个简单模板,分别生成简单的实体类和基本的SQL语句。
CodeTemplates.rar
文件包中包含两个模板,IBatis.cst用于生成实体类;IBatisStatements.cst用于生成SQL语句。
使用的数据表的脚本在CreateTable.sql中,生成的代码和SQL在Book.cs和BookMapper.xml中。
注意:
1.这里生成实体类只能跟数据表列对应,如有额外需要,还需手动添加。
2.生成的SQL脚本只是<resultMap>和<statements>两部分内容,Data Map的其它部分需手动添加。

希望对大家使用IBatisNet有所帮助。
posted @ 2012-02-12 22:39 lexus 阅读(98) 评论(0) 编辑

iBATIS中的单元测试

DAO消费者

持久化逻辑

     单元测试已经成为了现代软件开发方法中的一个非常重要的组成部分。即使不赞成极限编程(eXtreme Programming, XP)或者其他敏捷方法能够带来好处,单元测试也应该成为你的软件开发生命周期中的一个基础实践。
从概念上说,持久层可以分为3层,而iBATIS使得对这些不同的层进行单元测试都变得非常简单,如图13-1所示。

SQL映射

  • BATIS至少在以下3个方面可以使得你对这些不同层进行单元测试变得更容易:
  • 测试映射层(mapping layer)本身,包括各个映射、所有的SQL语句,以及这些SQL语句被映射到的那些领域对象。
  • 测试DAO层,这使你可以对DAO层中的任何特定于持久化的逻辑进行测试。
  • 在DAO的消费层中进行测试。

13.1.1 对映射层进行单元测试
      对映射层所进行的单元测试,可能是在大部分应用程序中所发生的最低层次的单元测试了。此过程包括对SQL语句以及这些语句所映射到的领域对象进行测试。这意味着我们将需要一个用于进行测试的数据库实例。

2 1. 测试用数据库实例

     测试用数据库实例可能是创建于你实际使用的数据库管理系统(例如,Oracle或者微软的SQL Server)中的一个真实实例。如果你的环境对于单元测试是友好的,那么只需要简单地更改一下配置就可以运行单元测试了。如果打算使用非标准数据库特征 (例如,存储过程),那么就可能有必要使用真实的数据库实例。存储过程和其他一些非可移植的数据库设计时选择,会使得对数据库进行单元测试变得很难,除非 使用真实的数据库实例。
      使用真实的数据库实例的缺点是,只有连接到网络才能进行单元测 试。或者也可以使用某个真实数据库的一个本地实例,但这意味着单元测试在运行之前将需要额外的本地环境设置。无论使用这两种方法中的哪一种,你都将面对同 一个问题,即每次测试都必须重建测试数据,甚至可能需要重建测试套件(test                           suite)之间的模式,或者是每个单元测试之间的模式。即使是在大型的企业级的数据库服务器上,要完成以上任务也需要花费很长时间。另一个问题是,由于 使用的数据库是集中式的,多个开发人员同时进行单元测试时就可能会导致冲突。所以,必须使用不同的数据库模式来隔离每一个开发人员。正如你所见,这种方法 的普遍问题就是,单元测试取决于相当多的基础设施,而这对于大多数经验丰富的测试驱动程序的开发人员来说是不够完美的。
     Java开发人员是非常幸运的,因为他们至少有一种非常棒的内存 (in-memory)数据库可以使用,这种数据库可以使得对相对标准的数据库设计进行单元测试变得非常简单。HSQLDB是一个完全用Java写成的内 存数据库。它既不需要磁盘上的任何文件也不需要连接网络就能够正常工作。此外,它还能够重新生成来自典型数据库(例如Oracle和微软的SQL Server)的大部分数据库设计。即使由于设计过于复杂(例如使用了存储过程)而导致HSQLDB不能重建整个数据库,它也仍然能够重新生成该数据库的 绝大部分。HSQLDB允许快速重建数据库,包括数据库模式和测试数据。iBATIS自己的单元测试套件就是使用HSQLDB在每个单独的测试之间重建数 据库模式和测试数据。我们亲自使用HSQLDB测试了由将近1000个数据库相关的测试构成的测试套件,运行时间不到30秒。
      有关HSQLDB的更多信息,请访问网页http://hsqldb.sourceforge.net/。另外,可能会让微软的.NET高兴的一个消息是,已经有人发起对HSQLDB的移植了,同时也有人开始创建其他的内存数据库了。


3 2. 数据库脚本
      现在已经有了数据库实例,那么数据库模式和测试数据应该如何构造和创建呢?你可能已经有了可以用来创建数据库模式以及测试数据的数据库脚本了。理想情况 下,你应该将这些脚本纳入到版本控制系统(例如CVS或者Subversion)中。这些脚本应该和应用程序中的其他代码一样被同等地对待。即使你对自己 使用的数据库没有控制权,你也应该定期从拥有控制权的人那里获得相应的更新。应用程序的源代码与数据库脚本应该始终保持同步,并且单元测试本来就是确保它 们同步的。每当运行单元测试套件时,你还应该运行这些脚本来重新创建数据库模式。使用这种方法,可以很容易地将数据库创建脚本需要的新集提交给版本控制系 统,然后运行单元测试以便确定脚本更新是否给应用程序带来了问题。这是最理想的情况。如果使用内存关系数据库(例如HSQLDB)来运行测试,则可能需要 另外一个步骤来转换数据库模式。可以考虑使这个转换过程自动化,以便避免手工编程可能出现的错误,加快集成的速度。

4 3. iBATIS配置文件(例如SqlMapConfig.xml)
     为了进行单元测试,你可能想要使用一个独立的iBATIS配置文件。配置文件用于控制数据源和事务管理器的配置,它在测试环境和产品环境中可能会完全不 同。例如,产品环境可能会是一个像J2EE应用程序服务器这样的受管理环境。在这样的环境下,一个受管理的DataSource实例可能是从JNDI中检 索得到的。你还可能会在产品环境中利用全局事务。然而,在测试环境中,你的应用程序可能不会运行在服务器中;而只是配置了一个简单DataSource, 使用的也是局部事务。分别进行测试环境配置和产品环境配置的最简单的方式就是,使用不同的iBATIS配置文件,这两份配置文件引用相同的一组SQL映射 文件。

5 4. iBATIS SqlMapClient单元测试
      现在所有的先决条件都已经准备好了,这些先决条件包括数据库实例、自动构建数据库的脚本,以及用于测试的配置文件,接下来可以开始创建单元测试了。代码清单13-1即是一个使用JUnit来创建简单单元测试的例子。
代码清单13-1 SqlMapClient单元测试示例
设置单元测试和测试数据

利用主键值测试单个person对象的检索

     代码清单13-1中的示例使用了针对Java的JUnit单元测试框架。(可以在www.junit.org上找到 更多有关JUnit的信息。对于.NET Framework,也有相似的工具,包括NUnit,可以从网页www.nunit.org上下载得到。)在我们的设置方法中,首先删除了测试涉及的那 些数据库表,然后再重建它们并对它们重新填充测试数据。为每一个测试都重建所有的东西可以确保各个测试间相互独立,但是如果在像Oracle或者SQL Server这样的RDBMS上这样删删建建地做测试那就太慢了。在这种情况下,可以使用类似于HSQLDB这样的内存关系数据库。在我们实际的测试案例 中,我们从数据库中读取一条记录,将其映射到一个bean上,然后断言(assert)bean中各字段的值都是所预期的值。                     

以上就是测试映射层所需做的全部工作了。接下来要测试的层是DAO层,假定你的应用程序有DAO层。

13.1.2 对DAO进行单元测试

      DAO层是一个抽象层,因此根据其本质,DAO应该非常容易测试。DAO也使得对DAO层用户的测试变得更加简单。 本节,将讨论测试DAO本身。DAO通常被分离为一个接口和一个实现。由于我们将直接测试DAO,因此接口将不起作用。我们将直接对DAO实现进行测试。 这可能同DAO模式的工作方式是相反的,但是这恰好体现了单元测试的好处——它把那些坏习惯清除出我们的系统!
      如果可能的话,对DAO层的测试应该不涉及数据库以及底层的基础设施。DAO层是持久化实现的一个接口,但是在测试DAO层时,我们更感兴趣的是测试DAO层内部的东西,而不是测试DAO层之外的东西。
      测试DAO的复杂度仅仅取决于DAO实现。例如,测试一个JDBC DAO可能非常困难。你需要一个很好的模拟框架来代替所有典型的JDBC组件,如Connection、ResultSet和Prepared-   Statement等。即使是这样,要利用模拟对象来管理这样复杂的API也非常麻烦。而模拟iBATIS SqlMapClient接口则简单得多。下面就来试一试。

6 1. 利用模拟对象来对DAO进行单元测试

      模拟对象是指为了进行单元测试而用来替换实际实现的对象。模拟对象通常没有很强的功能性;它们只用于满足某个单一的情况,以使得单元测试仅仅关注其应该关注的部分,而不需要担心复杂度的增加。我们将在下面的例子中使用这些模拟对象来示范一种测试DAO层的方法。
      在我们的示例中,将使用一个简单的DAO。我们将不考虑iBATIS DAO框架,因此就不需要担心事务以及诸如此类的东西了。这个示例的目的就是,示范如何测试DAO层,无论你使用的是哪一种DAO框架(只要确实使用了它)。
      首先,来考察一下要进行测试的DAO。代码清单13-2给出了一个SqlMapPersonDao实现,它调用了一个和13.1.1节中给出的示例相似的SQL映射文件。
      代码清单13-2 测试一个简单的DAO

      请注意在代码清单13-2中我们是如何把SqlMapClient注入到DAO的构造函数中的。这为对DAO进行单元测试提供了一种简易的方式,因为我们 只需要模拟SqlMapClient接口就可以了。显然,这是一个非常简单的示例,没有对其进行太多的测试,但是每一个测试都非常重要。代码清单13-3 显示了用来模拟SqlMapClient并且测试getPerson()方法的单元测试。
代码清单13-3 含有模拟SqlMapClient的PersonDao单元测试

     代码清单13-3中给出的示例使用了JUnit以及JMock这个Java对象模拟框架。正如代码清单13-3中加粗的部分所显示的那样,利用JMock 来模拟SqlMapClient接口实现,使我们能够单独测试DAO的行为,而无需顾虑实际的SqlMapClient实现,也就不需要考虑与其相关的 SQL语句、XML文件,还有数据库了。JMock是一个非常好用的工具,可以在www.jmock.org上找到更多有关它的信息。你可能已经猜到了, 还有一个针对.NET的模拟框架,称为NMock,有关它的更多信息请参考http://nmock.org

13.1.3 对DAO的消费层进行单元测试
      应用程序中那些使用DAO层的其他层称为DAO层的消费者(consumer)。DAO模式使得你可以在不依赖于持久层的任何功能的情况下测试这些消费者 的功能。一个好的DAO实现应该有一个能够很好地描述其可用功能的接口。测试消费层的关键在于获得此接口。考察代码清单13-4中的接口,你就会发现上一 节中所描述的getPerson()方法。
代码清单13-4 简单的DAO接口

      要开始测试DAO层的消费者,所需要的就只是代码清单13-4中所给出的接口。我们甚至根本不需要一个完整的实现。利用JMock,我们能够很轻松地模拟getPerson()方法所预期的行为。考虑如下这个使用了PersonDao接口的服务(见代码清单13-5)。
代码清单13-5 使用PersonDao接口的服务


      我们的单元测试的目标并不是DAO——而是getValidatedPerson()方法中的业务逻辑,例如它所执行的各种验证。方法中的每一个验证可能都是一个私有方法,为了便于讨论,假设此处我们只测试私有接口。
      多亏了之前的PersonDao接口,在没有数据库的情况下测试 getValidatedPerson()方法也很容易。所需要做的只是模拟PersonDao接口实现,然后将该模拟实现传递给服务的构造函数,最后调 用getValidatedPerson()方法即可。代码清单13-6给出了完成上述工作的单元测试。
代码清单13-6 使用模拟而不是真实的DAO,以避免访问数据库

     我们再一次同时使用了JUnit和JMock。正如你在代码清单13-6中所见到的那样,这种测试方式在应用程序的各个层都是一致的。这是很有好处的,因为它可以带来易于维护的凝练的单元测试。      
     有关iBATIS中的单元测试,我们就介绍到这。实际上网上有很多很好的关于单元测试资源。使用Google搜索一下“unit test(单元测试)”,就可以找到很多相关的资源,它们可以帮助你迅速提高单元测试的能力,甚至你还可能发现比本书使用的方法更好的单元测试方法。

posted @ 2012-02-12 22:37 lexus 阅读(82) 评论(0) 编辑

8.1.1   iBATIS开发步骤

iBATIS是Java应用和关系数据库之间的桥梁,它负责Java对象和关系数据之间的映射。iBATIS内部封装了通过JDBC访问数据库的操作,向上层应用提供了面向对象的数据访问API。在Java应用中使用iBATIS包含以下步骤:

(1)创建iBATIS的配置文件:该文件负责初始化iBATIS配置,包括数据库配置和映射文件配置;

(2)创建iBATIS映射文件:每一个数据表对应一个映射文件,该文件描述了数据库中表的信息,也描述了对应的持久化类的信息;

(3)创建持久化类:每一个类对应一个数据库表,通过映射文件进行关联;

以上三步是开发iBATIS要实现的关键内容。接下来就要面向Web应用层进行编码,通常会分为DAO层和Service层:

(1)编写DAO层:通过iBATIS API编写访问数据库的代码;

(2)编写Service层:编写业务层实现,调用DAO层类代码;

图8-1显示了调用的过程及iBATIS在应用中所处的位置。

 

 

 

          图8-1 iBATIS开发流程图

posted @ 2012-02-12 22:30 lexus 阅读(97) 评论(0) 编辑

深入剖析SolrCloud(一)

 

         SolrCloud是基于SolrZookeeper的分布式搜索方案,是正在开发中的Solr4.0的核心组件之一,它的主要思想是使用Zookeeper作为集群的配置信息中心。它有几个特色功能:1)集中式的配置信息 2)自动容错 3)近实时搜索 4)查询时自动负载均衡 

 

基本可以用上面这幅图来概述,这是一个拥有4Solr节点的集群,索引分布在两个Shard里面,每个Shard包含两个Solr节点,一个是Leader节点,一个是Replica节点,此外集群中有一个负责维护集群状态信息的Overseer节点,它是一个总控制器。集群的所有状态信息都放在Zookeeper集群中统一维护。从图中还可以看到,任何一个节点都可以接收索引更新的请求,然后再将这个请求转发到文档所应该属于的那个ShardLeader节点,Leader节点更新结束完成,最后将版本号和文档转发给同属于一个Shardreplicas节点。

下面我们来看一个简单的SolrCloud集群的配置过程。

首先去https://builds.apache.org/job/Solr-trunk/lastSuccessfulBuild/artifact/artifacts/下载Solr4.0的源码和二进制包,注意Solr4.0现在还在开发中,因此这里是Nightly Build版本。

示例1,简单的包含2Shard的集群

这个示例中,我们把一个collection的索引数据分布到两个shard上去,步骤如下:

为了弄2solr服务器,我们拷贝一份example目录 

cp -r example example2

然后启动第一个solr服务器,并初始化一个新的solr集群, 

cd example
java -Dbootstrap_confdir=./solr/conf -Dcollection.configName=myconf -DzkRun -DnumShards=2 -jar start.jar

-DzkRun参数是启动一个嵌入式的Zookeeper服务器,它会作为solr服务器的一部分,-Dbootstrap_confdir参数是上传本地的配置文件上传到zookeeper中去,作为整个集群共用的配置文件,-DnumShards指定了集群的逻辑分组数目。 

然后启动第二个solr服务器,并将其引向集群所在位置

cd example2
java -Djetty.port=7574 -DzkHost=localhost:9983 -jar start.jar

-DzkHost=localhost:9983就是指明了Zookeeper集群所在位置

我们可以打开http://localhost:8983/solr/collection1/admin/zookeeper.jsp 或者http://localhost:8983/solr/#/cloud看看目前集群的状态,

现在,我们可以试试索引一些文档,

cd exampledocs
java -Durl=http://localhost:8983/solr/collection1/update -jar post.jar ipod_video.xml
java -Durl=http://localhost:8983/solr/collection1/update -jar post.jar monitor.xml
java -Durl=http://localhost:8983/solr/collection1/update -jar post.jar mem.xml

最后,来试试分布式搜索吧:

http://localhost:8983/solr/collection1/select?q

Zookeeper维护的集群状态数据是存放在solr/zoo_data目录下的。

现在我们来剖析下这样一个简单的集群构建的基本流程:

先从第一台solr服务器说起:

1)       它首先启动一个嵌入式的Zookeeper服务器,作为集群状态信息的管理者,

2 将自己这个节点注册到/node_states/目录下

3 同时将自己注册到/live_nodes/目录下

4)创建/overseer_elect/leader,为后续Overseer节点的选举做准备,新建一个Overseer

5) 更新/clusterstate.json目录下json格式的集群状态信息

6) 本机从Zookeeper中更新集群状态信息,维持与Zookeeper上的集群信息一致

7)上传本地配置文件到Zookeeper中,供集群中其他solr节点使用

8) 启动本地的Solr服务器,

9) Solr启动完成后,Overseer会得知shard中有第一个节点进来,更新shard状态信息,并将本机所在节点设置为shard1leader节点,并向整个集群发布最新的集群状态信息。

10)本机从Zookeeper中再次更新集群状态信息,第一台solr服务器启动完毕。

然后来看第二台solr服务器的启动过程:

1) 本机连接到集群所在的Zookeeper

2) 将自己这个节点注册到/node_states/目录下

3)  同时将自己注册到/live_nodes/目录下

4) 本机从Zookeeper中更新集群状态信息,维持与Zookeeper上的集群信息一致

5) 从集群中保存的配置文件加载Solr所需要的配置信息

6) 启动本地solr服务器,

7) solr启动完成后,将本节点注册为集群中的shard,并将本机设置为shard2Leader节点,

8) 本机从Zookeeper中再次更新集群状态信息,第二台solr服务器启动完毕。

示例2,包含2shard的集群,每个shard中有replica节点

如图所示,集群包含2shard,每个shard中有两个solr节点,一个是leader,一个是replica节点,

cp -r example exampleB
cp -r example2 example2B
cd exampleB
java -Djetty.port=8900 -DzkHost=localhost:9983 -jar start.jar
cd example2B
java -Djetty.port=7500 -DzkHost=localhost:9983 -jar start.jar

我们可以打开http://localhost:8983/solr/collection1/admin/zookeeper.jsp  看看包含4个节点的集群的状态,

 

  

 

这个集群现在就具备容错性了,你可以试着干掉一个Solr服务器,然后再发送查询请求。背后的实质是集群的ov erseer会监测各个shardleader节点,如果leader节点挂了,则会启动自动的容错机制,会从同一个shard中的其他replica节点集中重新选举出一个leader节点,甚至如果overseer节点自己也挂了,同样会自动在其他节点上启用新的overseer节点,这样就确保了集群的高可用性。

示例3 包含2shard的集群,带shard备份和zookeeper集群机制

 

上一个示例中存在的问题是:尽管solr服务器可以容忍挂掉,但集群中只有一个zookeeper服务器来维护集群的状态信息,单点的存在即是不稳定的根源。如果这个zookeeper服务器挂了,那么分布式查询还是可以工作的,因为每个solr服务器都会在内存中维护最近一次由zookeeper维护的集群状态信息,但新的节点无法加入集群,集群的状态变化也不可知了。因此,为了解决这个问题,需要对Zookeeper服务器也设置一个集群,让其也具备高可用性和容错性。

有两种方式可选,一种是提供一个外部独立的Zookeeper集群,另一种是每个solr服务器都启动一个内嵌的Zookeeper服务器,再将这些Zookeeper服务器组成一个集群。 我们这里用后一种做示例:

cd example
java -Dbootstrap_confdir=./solr/conf -Dcollection.configName=myconf -DzkRun -DzkHost=localhost:9983,localhost:8574,localhost:9900 -DnumShards=2 -jar start.jar
cd example2
java -Djetty.port=7574 -DzkRun -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar
cd exampleB
java -Djetty.port=8900 -DzkRun -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar
cd example2B
java -Djetty.port=7500 -DzkHost=localhost:9983,localhost:8574,localhost:9900 -jar start.jar

我们可以打开http://localhost:8983/solr/collection1/admin/zookeeper.jsp  看看包含4个节点的集群的状态,可以发现其实和上一个没有任何区别。

 

后续的文章将从实现层面对SolrCloud这个分布式搜索解决方案进行进一步的深入剖析。

posted @ 2012-02-12 22:00 lexus 阅读(25) 评论(0) 编辑

brasero

posted @ 2012-02-12 10:14 lexus 阅读(49) 评论(0) 编辑

Ubuntu 制作光盘镜像文件

出自Guoshuang Wiki

从光盘建立 iso 文件

sudo umount /dev/cdrom dd if=/dev/cdrom of=file.iso bs=1024

从目录建立 iso 文件

mkisofs -r -o file.iso /location_of_folder/

做 md5 验证

md5sum file.iso > file.iso.md5
posted @ 2012-02-12 10:06 lexus 阅读(60) 评论(0) 编辑

Mybatis:代码生成器(Maven版)&集成Spri

 

http://tywo45.iteye.com/blog/1207581

ng

posted @ 2012-02-12 01:01 lexus 阅读(92) 评论(0) 编辑

。。。。

posted @ 2012-02-12 00:52 lexus 阅读(28) 评论(0) 编辑