怎么创建数据表的实体类和业务类_类加载与反射 3

2251d02a83c3208465ef91b5660d9b17.png

java零基础入门-高级特性篇(十六) 类加载与反射 3

如果你认为反射只有前面介绍的那些作用,那么就太小看这个功能了。本章再来介绍反射中更加强大的用法,反射功能可以在设计层面更好的处理一些难题,甚至改变编程的方式。

面向切面编程AOP

AOP - Aspect Oriented Programming的缩写,java不是面向对象编程么,怎么又整了个面向切面编程出来了?其实面向切面这种思想是对面向对象思想(OOP-Object Oriented Programming)的一种补充和扩展,让程序在设计上更加灵活,使代码编写的难度降低,功能之间的耦合度降低。普通的业务逻辑都是串行的,一个逻辑接着一个逻辑,从上往下顺序执行,有时需要新增功能时,不得不对每一个功能都进行修改,而AOP提供了另一种解决方案,它可以通过预编译方式和运行期动态代理的方式, 实现在不修改源代码的情况下给程序统一加上新功能。

d6ff3c2fb9ab07e8bfc6b5b25f26e671.png
功能改造

假设现在有一个系统有登录,购物,付款,退出这几个功能。然后有一天,突然有用户说我为什么没登录就可以付钱?我东西寄哪去了?我明明付了钱为啥说我没付钱?这时候怎么办?如果没有一套完善的日志系统,我们无从查起,不是知道具体哪个环节出了问题,所以需要对用户的每一步的操作都记录日志,这样出了问题就可以精确的追踪到出问题的地方。这要怎么改造系统?那还不简单~加班呗,每个具体功能前后全加上日志,一旦用户有操作就给记录日志。说的很轻松,但是要知道上图只是一个简单的例子,真正的系统可是十分庞大的,几十个模块都算少的,比如物流,仓库,财务,会员等等,一旦用户付了钱买了东西,一大片业务都需要同时改变,更新物流信息,库存减少,财务入账,银行扣款,会员积分增加,等等等,你确定你要全公司一起日以继夜的加班新增功能么?

面向切面AOP告诉你,不需要!只需要一个程序员敲几行代码即可。是不是觉得有点不可思议?这么多模块都需要加日志,几行代码怎么可能做得完?其实如果使用AOP的思想来考虑这个问题,这个问题会简单很多,下面看看AOP如何解决。

105a80d511a2df5de3f333a9d9c74c1a.png
切面

无需改动原有代码,新增切面即可,将记录日志的功能切入到所有需要记录日志的功能模块中,这样只需要在一个地方维护日志模块功能即可,不需要在每一个功能中都加上记录日志的功能。有了切面,如果后面还有这种需要在部分功能上都加上同样功能的需求的时候,只需要增加切面即可。比如在购物的时候不需要验证登录,付款的时候验证登录就可以了,这时候就只有部分功能加入权限验证切面就可以了。

7b126dcdc4b5e9120bc41a8dd1b51470.png
切面

在讲具体代码之前,除了AOP,还有一个知识需要了解一下,那就是代理,AOP就是代理模式的一种具体实现。那么代理模式又是个什么?代理不懂,代理律师总听过吧?打官司,自己不懂法,需要找一个专业的律师帮忙打官司,自己付钱等结果就行了。这种不直接由自己出面解决问题,而使用中介的方式让中介来完成本该由自己完成工作的模式,就是代理模式。代理模式提供了一个代理对象,并由代理对象控制对原对象的引用,最后由代理对象完成任务。

2bd78af19531e2c4d07309c604fd3f2e.png
代理

原告和被告都不懂法,官司没法打,所以都请个代理律师,让律师来完成申诉和辩护的任务。原告就相当于系统原有代码,当系统需要统一增加功能的时候,请个代理律师来完成新的功能就行了,原告和被告是不需要做任何改变的,毕竟为了打个官司,总不能让原告和被告先去学一遍法律知识吧。

2e66417cd306fd3b57a6f97d503f25fa.png
原功能

1.首先是登录功能的接口,用来为登录模块创建模板。2.User实体类,用来传递用户信息。3.具体的登录功能实现,如果需要新增日志功能的话,需要在每个方法上面都加上日志记录的代码。4.没有日志记录功能的代码,所以打印出来的只有用户具体的状态。具体的功能都在实现类里面,要增加功能也是在实现类中添加,所以这个实现类就是需要被代理的类。下面就来看看如何设计一个代理类,来为这个实现类服务。

a0026262f2a82199f52d94d6287a1347.png
切面

这个类LoginInvocationHandler需要实现InvocationHandler类,然后重写invoke方法。在构造器中需要传入被代理的对象,可以通过反射获取被代理对象的信息,invoke方法替代了原来需要被调用的被代理对象的方法,这样就可以在被代理对象的方法中添加新的功能而无需改动原有的代码。

f8e456f09d75ee907986f3545249f819.png
使用代理调用方法

在调用方法的时候,不要再直接调用原对象的方法,而需要根据切面设置代理,通过反射根据接口创建新的代理对象,此时生成的对象在运行时具备了代理对象新增的功能,最后使用代理对象调用方法即可。在结果中也看到了,新的功能已经生效,在用户的登录和退出之前和之后,都已经加上了日志记录。这个例子很好的体现了反射功能的强大,用反射实现了代理最终实现了面向切面的功能添加。

注解

在上面切面制作的类中,实现InvocationHandler接口的时候,有一个奇怪的东西。在实现接口的方法的时候,会有一个@Override在方法上面。这是个什么玩意?这种代码叫做注解Annotation,它可以在不改变原有代码逻辑的情况下,对代码进行一些补充或功能的添加。注解的功能十分强大,java的jdk有部分注解用于对代码进行修饰,而他的功能强大之处主要体现在它的自定义功能。由于可以自定注解,在各大框架中有大量的封装好的注解供我们使用,极大的方便了我们的开发和提高开发效率。

常用java自带注解

@Override:限定重写父类方法。抽象类中有抽象方法,也可以有实现好的方法,如果继承了抽象类,那么已实现的方法可以重写也可以不重写,而抽象方法必须被重写,接口也是一样,接口中都是抽象方法,在实现接口的时候必须重写接口的抽象方法。而这个注解就是标识出必须被子类重写的父类方法或实现接口的方法,它可以帮助我们避免忘记,或写错需要重写方法带来的问题。其实IDE工具一般都有自动完成重写方法的功能,在自动完成的过程中也会自动加上这个注解,表示已重写该方法。

bc646d07b2b2ce3335b5baea4dafa064.png
@Override注解

@Deprecated:标识已过时的类或方法。在使用java的早期版本类或方法的时候会发现有一些类或方法是带有一个删除线的,因为他们已经被打上了@Deprecated注解。这些类或方法表示java已经不再推荐使用,在以后的版本有可能会将这种过时的类删除,所以在写代码的过程中要尽量避免使用这种类或方法。

a162c84a5b8fbb463b9ea09d63cac09e.png
@Deprecated注解

@SuppressWarnings:取消编译警告。这个注解可以在类上,方法上也可以在变量上,当出现编译警告的时候,通过这个注解就可以告诉编译器别给我警告了,我知道了。此注解会作用到标记位置的所有作用范围,如果在类上,整个类都被取消警告,在方法上,整个方法取消警告。这个注解最常见的时候就是当我们声明一个集合并且不指定泛型,这个时候就会出现警告,如果确实不想指定泛型最好加上此注解。在程序出现多条警告的时候,还可以同时取消多个编译警告,在注解上传入一个字符串数组即可。

59535bc0f20f76043afb152c08035e66.png
@SuppressWarnings注解

自定义注解

java自身的自定义注解功能有限,结合一些框架以后会有更加强大的功能。但是有些简单的功能,依靠java自身也是可以完成的,下面来看看如何一个自定义的注解。

自定义注解肯定会用到元注解,元注解就是用来修饰注解的注解。也就是说定义一个注解的时候需要依赖别的注解,这些被依赖的注解就是元注解。常用的元注解有下面四种。

@Documented – 如果一个类型添加了Documented注解,那么它的注解会成为元素API的一部分。可以被工具文档化,在生成文档的时候会将信息自动生成到API中。

@Target – 指定该注解可以使用在什么地方,比如是在方法上的注解还是类上的注解。如果不指定此元注解,标识该注解可以用在任何元素上。下面是可以指定的位置。

TYPE:类,接口或者枚举 FIELD:域,包含枚举常量 METHOD:方法

PARAMETER:参数 CONSTRUCTOR:构造方法 PACKAGE:包

LOCAL_VARIABLE:局部变量 ANNOTATION_TYPE:注解类型

@Inherited – 子类继承父类中的注解。

@Retention – 表示注解的声明周期。有三种方式,SOURCE:编译完就失效。CLASS:编译级别保留,在jvm运行时失效,默认值。RUNTIME: 运行级别保留,编译后的class文件中存在,在jvm运行时保留,可以被反射调用。

下面来定义一个注解,来帮助我们检查字段的赋值是否满足要求。通常在web项目中,会有大量的数据从前端传递给后端,数据校验就是一个十分重要的环节。比如在用户进行注册的时候,就必须进行数据校验,比如用户名的长度,密码复杂度等等,都需要满足要求才能够发送到后端,而后端也必须再一次对这些数据进行校验。

但是,通常对这些数据进行校验会写在业务中,造成业务代码中充斥了大量的if,else的判断,这样不仅在业务中写了大量与业务无关的代码,还会有大量重复的代码。比如注册的时候校验密码,需要在注册功能中校验一遍,再修改密码的时候,又要在修改密码的功能中再次校验,如果能够将校验规则提取出来,不仅使得代码更加专注于业务,还能大幅提高编码效率。如果将校验规则封装进方法,也会有参数传递,方法调用等逻辑,如果在对对象进行赋值的时候,就进行校验,这样会更加的优雅,没有任何的校验逻辑在代码中。如何做到?使用注解。

2e17a6a72b26fca68c90f80962126c85.png
数据校验

在对象赋值的时候,将校验逻辑封装进注解,在属性上注解后,在对属性进行赋值的时候就会进行数据校验,对实体类的封装性没有任何的破坏,也不会破坏单一职责原则,因为实体类本身里面是没有任何校验逻辑的。

1.首先定义自定义注解。@Target指定此注解用在字段上,@Retention指定为RUNTIME,运行时可以使用反射来调用。注解中指定可以在注解上使用的参数,参数类型只能是基本类型,boolean是基本类型可以使用。isNotNull()是属性名,default false表示如果注解上不使用此属性,则默认为false。这样一个自定义注解就定义好了。

9e1428870922fa876d73fa03b163639e.png
自定义注解

2.校验器,封装注解中具体的校验逻辑。

d5ba9bb28250ba59385ae707aea8edd0.png
注解逻辑

3.使用自定义注解。在需要验证的字段上加上注解,并且对注解属性进行赋值。如果没有声明注解属性,则使用定义注解时的属性默认值。

62b67c0914d8ddb9aed3d012595d5b66.png
使用自定义注解

4.校验赋值。在对象赋值的后,使用校验器对对象进行校验。

c9d703aef5fdc04a87fd2d5ce979e3a1.png
校验

其实在参数校验方面,已经有很成熟的标准框架可以直接使用,比如JSR303 ,就是一套JavaBean参数校验的标准。除了JSR303内置了大量现成的注解之外,还可以非常灵活的对校验注解进行扩展,定义自己需要的验证注解。这一套注解的使用方法跟上例中我们自定义的注解使用方法类型,但是用法更方便,无需使用验证器传入对象进行校验,在注解中就可以定义需要抛出的异常信息等等。JSR303已有注解如下

@Null 被注释的元素必须为 null

@NotNull 被注释的元素必须不为 null

@AssertTrue 被注释的元素必须为 true

@AssertFalse 被注释的元素必须为 false

@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@Size(max, min) 被注释的元素的大小必须在指定的范围内

@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内

@Past 被注释的元素必须是一个过去的日期

@Future 被注释的元素必须是一个将来的日期

@Pattern(value) 被注释的元素必须符合指定的正则表达式

各位只需要了解即可,在项目中需要进行参数校验的时候再来查阅即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码生成器,ORMap,支持Oracle/SqlServer/MSAccess,性能大大优于iBatisNet,终身免费,随意使用。<br>===========<br>软件说明: <br>1.1 引言<br>约有90%的企业信息化管理系统基于数据库实现,这系统中又有超过30%的代码集中在数据访问层负责业务数据存取。除了实现数据的增删改查,数据访问层还要提供一些与业务无关功能,例如面向对象的持久化与访问机制、本地事务与分布式事务支持、多数据库支持,这些机制或功能形成相对独立的逻辑领域,其主要目的有:<br><br>1、 提供简单易用的数据库访问方法,提高开发效率;<br><br>2、 提供面向对象的方式来简化对数据库访问与操作,也就是ORMap方式;<br><br>3、 屏蔽数据库差异,使开发出的产品容易在不同数据库产品上移植。<br><br>为了适应软件快速开发的需要,软件企业应该借助组件产品或开源软件项目来搭建这些基础设施。在.Net平台上,目前比较成功和应用较广的开源项目有NHibernate和IBatisNet等,它们在ORMap方面的表现尤为突出。依赖这些平台,软件开发效率和产品质量都得到了极大提高,ORMap机制渐渐成为大势所趋。<br><br>本公司致力于软件组件开发,提供的AppFramework数据库访问组件具有高效的ORMap机制,调用接口简单灵活,支持各种主流的数据库平台,是个非常优秀的数据访问组件。本文详尽描述了AppFramework数据库访问组件使用的方法和技巧,有助于开发者最大程度发挥出AppFramework的优势。<br><br>1.2 各种优秀ORMap工具比较<br>NHibernate和IBatisNet等虽然都实现了ORMap,但它们的设计侧重点有所不同,有着各自的优势和缺陷,适合于特定的项目。NHibernate实现了纯对象化的ORMap,在屏蔽数据库差异、面向对象方面做的非常好,但在访问与操作海量数据时其性能表现较差,也不易实现复杂的查询统计功能。NHibernate适合那些数据量不大、性能要求不高、复杂度不高的场合。<br><br>IBatisNet是一个轻量级ORMap工具,它把所有的SQL脚本以模板的方式集中到若干个XML配置文件里,用反射的方式向把C#实体对象属性与SQL模板的参数绑定,动态生成参数化的SQL语句发送给数据库执行,查询的结果集也用反射的方式构造为对象集合返回给程序。由于提供了灵活的SQL模板机制,在海量数据的访问与操作方面其性能比NHibernate要高得多,也很容易实现各种复杂的数据查询统计功能。但是IBatisNet也存在许多几个不足之处,有些还是先天因素造成的:<br><br>第一,数据库可移植性差。IBatisNet获得高性能与灵活性也是付出代价的,它牺牲了数据库可移植性:由于编写SQL模板不得不用到数据库产品的一些语法差异,例如ORACLE的TO_DATE、Length()、SYSDATE等,为了把产品移植到其它数据库,开发人员不得不对大量的SQL模板进行翻译。<br><br>第二,无法方便地向数据库中插入NULL值。因为IBatisNet是直接把C#的基本型(如int/DateTime)插入到数据库中字段的。对于一些C#值型,例如int,并没有NULL状态。于是不得不采用一些特殊的值来表示NULL,例如int.MinValue。IBatisNet数据映射器会自动把int.MinValue转换为NULL插入到数据库,而从数据库中获得NULL时,也会转化为C#的int.MinValue。这样,程序就要对int.MinVaue这个值进行特殊处理,例如不能把int.MinValue直接显示在DataGrid里或界面上。有一种规避的方法,就是避免向数据库插入NULL,即要求所有业务数据入库的值都不为空。但这样作实际上是限制了程序的行为能力,例如无法实现单据草稿的保存。<br><br>第三,在插入数据时无法方便的使用字段默认值。最明显的就是似于LAST_UPDATE_TIME了,通常为了保证这个字段的一致性,通常在插入新记录时采用当前数据库时间作为字段值。但IBatisNet接收的实体类对象属性都是普通C#型,并不具备传入表达式的能力。如果采用动态SQL,则会导致SQL模板和参数实体类过于复杂,将极大降低性能。<br><br>第四,在查询返回大量对象时,用反射的方式构造实体的方式性能损失是相当大的。实体类属性数目越多、返回记录数越多,用到反射的次数也越多,查询性能降低就越明显。<br><br>第五,不能方便地限定查询语句返回的字段。ADO.Net执行查询时,select语句里设置了几个字段就返回几个字段到DataTable。而IBatisNet若要返回不同的字段就要定义多套ResultMap,否则就定义一套所有字段的ResultMap,任何查询都返回所有字段。这样无疑浪费了数据库服务器与应用服务器之间的网络带宽,在进行海量数据访问时性能将严重降低。<br><br>第六,返回的结果IList不能够方便地进行二次查询。相比之下,ADO.Net返回的DataTable虽然性能差一些,但可以实现在应用程序内存中灵活和高性能的二次查询。<br><br>第七,无法直接利用数据库的特殊语法支持海量数据的分页查询功能。众所周知Oracle提供了ROWNUM实现数据数据库内分页功能,若要利用这一特性,就要在SQL模板里直接硬编码这些特殊语法,这必然导致大量的移植工作。<br><br>第八、缺少代码生成和检查工具。程序里的变量名与Sql模板里的变量经常会出现不一致,而这些错误无法在编译时发现,靠人工检查很容易造成错误泄漏。也没提供工具直接生成SQL模板和映射配置文件。<br><br>第九,IBatisNet的SqlMap文件里的SQL语句以明文存放,容易被修改造成重大安全隐患,尤其不适合开发C/S应用程序。<br><br>第十,由于Sql模板采用动态加载的方式,如果写错了SQL,程序里难以跟踪调试,这对初学者来说无疑是对耐心和信心的极大考验。<br><br>总之,IBatisNet虽然提灵活、高性能的ORMap机制,但却损失了数据库可移植性的,在使用方便性和局部性能方面也都有很大提高的余地。<br><br>1.3 AppFramework数据访问组件的组成和优势<br>AppFramework数据访问组件由下列文件组成:<br><br>1、 AppFramework.DBAccess.dll<br><br>提供多数据库统一的访问接口,提供DAO管理器、数据库会话管理器。<br><br>2、 AppFramework.Data.dll<br><br>提供核心的数据结构和基础。<br><br>3、 AppFramework.Tools.CodeGenPlugin.msi<br><br>提供集成于Visual Studio 2005的C#代码生成器插件,用于生成DAO/Model/各种接口。<br><br>4、 DBAccess.config<br><br>配置数据库连接串。<br><br>5、 CodeGenPlogin.config<br><br>配置代码生成器参数。<br><br>6、 *.DaoGen文件<br><br>配置DAO生成信息,并由CodeGenPlugin解析生成代码。<br><br><br><br>AppFramework数据库访问组件针对IBatisNet的种种缺陷提出相应的解决方案,相比之下有如下优势:<br><br>1、 从扩展基础数据型入手,解决了空值问题和默认值问题;<br><br>2、 提供了内置的数据库内分页访问机制,极大地提高了海量查询的响应速度;<br><br>3、 增加ObjectTable<T>泛型来承载查询返回的对象集,不但比IList更加强型化,还提供了二分查找功能,使得对象结果集可以在应用程序内存中进行重排序和快速查找;<br><br>4、 提供了强大的QueryFilter构造查询条件,使得实现数据查询不再需要编写复杂的SQL语句;<br><br>5、 提供似IBatisNet的Sql模板功能,为复杂的查询统计提供较直观的开发模式;<br><br>6、 提供代码生成工具,生成的代码的同时可以之间的继承关系和接口实现关系,所有DAO方法均以接口作为参数,使得代码更加具有可扩展性和灵活性。<br><br>7、 Sql模板和ORMap直接生成.cs原代码,编译为可执行代码,各种ORMap映射文件无需再随主程序集一起部署,提高了代码的安全性,提高了代码的可调试性,也提高了ORMap的性能。<br><br><br><br>下面三张表格罗列的测试数据,可以明显看出AppFramework数据库访问组件的性能全面超越了IBatisNet: <br><br><br><br>表I –10并发20循环(数据库和测试机分开)<br><br>对比项目<br>iBatis2.0<br><br>(毫秒)<br>AppFramework<br><br>(毫秒)<br>后者前者性能对比<br><br>(倍)<br><br>根据主键获取实体<br><br>(20次单条select)<br>19.8<br>16.1<br><br>QueryFilter:18.0<br>1.23<br><br>1.10<br><br>每秒插入实体<br><br>(20次insert)<br>41<br>21<br>1.95<br><br>更新实体<br><br>(20次单条update)<br>27<br>19<br><br>SqlMap:24<br>1.42<br><br>1.13<br><br>查询结果集(平均101行)<br><br>(2循环200次select)<br>1100<br>690<br><br>不定字段:720<br>1.59<br><br>1.53<br><br><br><br><br>表II –50并发4循环(数据库和测试机分开)<br><br>对比项目<br>iBatis2.0<br><br>(毫秒)<br>AppFramework<br><br>(毫秒)<br>后者前者性能对比<br><br>(倍)<br><br>根据主键获取实体<br><br>(20次单条select)<br>17.5<br>13.3<br><br>QueryFilter:14.5<br>1.32<br><br>1.21<br><br>插入实体<br><br>(20次insert)<br>36.1<br>17.4<br>2.07<br><br>更新实体<br><br>(20次单条update)<br>23.5<br>15.9<br><br>SqlMap:20.3<br>1.48<br><br>1.16<br><br>查询结果集(平均101行)<br><br>(1循环200次select)<br>1055.1<br>666.8<br><br>不定字段:710.1<br>1.58<br><br>1.50<br><br><br><br><br>表III –50并发10循环(数据库和测试机同机)<br><br>对比项目<br>iBatis2.0<br><br>(毫秒)<br>AppFramework<br><br>(毫秒)<br>后者前者性能对比<br><br>(倍)<br><br>根据主键获取实体<br><br>(20次单条select)<br>6.1<br>5.3<br><br>QueryFilter: 5.75<br>1.15<br><br>1.06<br><br>插入实体<br><br>(20次insert)<br>15.1<br>10.8<br>1.40<br><br>更新实体<br><br>(20次单条update)<br>10.4<br>7.5<br><br>SqlMap:9.3<br>1.38<br><br>1.12<br><br>查询结果集(平均101行)<br><br>(1循环200次select)<br>560<br>360<br><br>不定字段:380<br>1.56<br><br>1.47<br><br><br><br><br>总之,AppFramework数据库访问组件是一个高性能、接口简单、可移植性强、高灵活性的综合数据访问解决方案。使用AppFramework数据库访问组件,可以降低企业的开发人员培训成本,提高产品的开发速度,提高产品稳定可靠性,提高产品的可伸缩性和可移植性。下文将分入门、精通、高级三个篇章,详细讲述如何使用AppFramework数据库访问组件来搭建应用程序。
1.1 引言<br>约有90%的企业信息化管理系统基于数据库实现,这系统中又有超过30%的代码集中在数据访问层负责业务数据存取。除了实现数据的增删改查,数据访问层还要提供一些与业务无关功能,例如面向对象的持久化与访问机制、本地事务与分布式事务支持、多数据库支持,这些机制或功能形成相对独立的逻辑领域,其主要目的有:<br><br>1、 提供简单易用的数据库访问方法,提高开发效率;<br><br>2、 提供面向对象的方式来简化对数据库访问与操作,也就是ORMap方式;<br><br>3、 屏蔽数据库差异,使开发出的产品容易在不同数据库产品上移植。<br><br>为了适应软件快速开发的需要,软件企业应该借助组件产品或开源软件项目来搭建这些基础设施。在.Net平台上,目前比较成功和应用较广的开源项目有NHibernate和IBatisNet等,它们在ORMap方面的表现尤为突出。依赖这些平台,软件开发效率和产品质量都得到了极大提高,ORMap机制渐渐成为大势所趋。<br><br>本公司致力于软件组件开发,提供的AppFramework数据库访问组件具有高效的ORMap机制,调用接口简单灵活,支持各种主流的数据库平台,是个非常优秀的数据访问组件。本文详尽描述了AppFramework数据库访问组件使用的方法和技巧,有助于开发者最大程度发挥出AppFramework的优势。<br><br>1.2 各种优秀ORMap工具比较<br>NHibernate和IBatisNet等虽然都实现了ORMap,但它们的设计侧重点有所不同,有着各自的优势和缺陷,适合于特定的项目。NHibernate实现了纯对象化的ORMap,在屏蔽数据库差异、面向对象方面做的非常好,但在访问与操作海量数据时其性能表现较差,也不易实现复杂的查询统计功能。NHibernate适合那些数据量不大、性能要求不高、复杂度不高的场合。<br><br>IBatisNet是一个轻量级ORMap工具,它把所有的SQL脚本以模板的方式集中到若干个XML配置文件里,用反射的方式向把C#实体对象属性与SQL模板的参数绑定,动态生成参数化的SQL语句发送给数据库执行,查询的结果集也用反射的方式构造为对象集合返回给程序。由于提供了灵活的SQL模板机制,在海量数据的访问与操作方面其性能比NHibernate要高得多,也很容易实现各种复杂的数据查询统计功能。但是IBatisNet也存在许多几个不足之处,有些还是先天因素造成的:<br><br>第一,数据库可移植性差。IBatisNet获得高性能与灵活性也是付出代价的,它牺牲了数据库可移植性:由于编写SQL模板不得不用到数据库产品的一些语法差异,例如ORACLE的TO_DATE、Length()、SYSDATE等,为了把产品移植到其它数据库,开发人员不得不对大量的SQL模板进行翻译。<br><br>第二,无法方便地向数据库中插入NULL值。因为IBatisNet是直接把C#的基本型(如int/DateTime)插入到数据库中字段的。对于一些C#值型,例如int,并没有NULL状态。于是不得不采用一些特殊的值来表示NULL,例如int.MinValue。IBatisNet数据映射器会自动把int.MinValue转换为NULL插入到数据库,而从数据库中获得NULL时,也会转化为C#的int.MinValue。这样,程序就要对int.MinVaue这个值进行特殊处理,例如不能把int.MinValue直接显示在DataGrid里或界面上。有一种规避的方法,就是避免向数据库插入NULL,即要求所有业务数据入库的值都不为空。但这样作实际上是限制了程序的行为能力,例如无法实现单据草稿的保存。<br><br>第三,在插入数据时无法方便的使用字段默认值。最明显的就是似于LAST_UPDATE_TIME了,通常为了保证这个字段的一致性,通常在插入新记录时采用当前数据库时间作为字段值。但IBatisNet接收的实体类对象属性都是普通C#型,并不具备传入表达式的能力。如果采用动态SQL,则会导致SQL模板和参数实体类过于复杂,将极大降低性能。<br><br>第四,在查询返回大量对象时,用反射的方式构造实体的方式性能损失是相当大的。实体类属性数目越多、返回记录数越多,用到反射的次数也越多,查询性能降低就越明显。<br><br>第五,不能方便地限定查询语句返回的字段。ADO.Net执行查询时,select语句里设置了几个字段就返回几个字段到DataTable。而IBatisNet若要返回不同的字段就要定义多套ResultMap,否则就定义一套所有字段的ResultMap,任何查询都返回所有字段。这样无疑浪费了数据库服务器与应用服务器之间的网络带宽,在进行海量数据访问时性能将严重降低。<br><br>第六,返回的结果IList不能够方便地进行二次查询。相比之下,ADO.Net返回的DataTable虽然性能差一些,但可以实现在应用程序内存中灵活和高性能的二次查询。<br><br>第七,无法直接利用数据库的特殊语法支持海量数据的分页查询功能。众所周知Oracle提供了ROWNUM实现数据数据库内分页功能,若要利用这一特性,就要在SQL模板里直接硬编码这些特殊语法,这必然导致大量的移植工作。<br><br>第八、缺少代码生成和检查工具。程序里的变量名与Sql模板里的变量经常会出现不一致,而这些错误无法在编译时发现,靠人工检查很容易造成错误泄漏。也没提供工具直接生成SQL模板和映射配置文件。<br><br>第九,IBatisNet的SqlMap文件里的SQL语句以明文存放,容易被修改造成重大安全隐患,尤其不适合开发C/S应用程序。<br><br>第十,由于Sql模板采用动态加载的方式,如果写错了SQL,程序里难以跟踪调试,这对初学者来说无疑是对耐心和信心的极大考验。<br><br>总之,IBatisNet虽然提灵活、高性能的ORMap机制,但却损失了数据库可移植性的,在使用方便性和局部性能方面也都有很大提高的余地。<br><br>1.3 AppFramework数据访问组件的组成和优势<br>AppFramework数据访问组件由下列文件组成:<br><br>1、 AppFramework.DBAccess.dll<br><br>提供多数据库统一的访问接口,提供DAO管理器、数据库会话管理器。<br><br>2、 AppFramework.Data.dll<br><br>提供核心的数据结构和基础。<br><br>3、 AppFramework.Tools.CodeGenPlugin.msi<br><br>提供集成于Visual Studio 2005的C#代码生成器插件,用于生成DAO/Model/各种接口。<br><br>4、 DBAccess.config<br><br>配置数据库连接串。<br><br>5、 CodeGenPlogin.config<br><br>配置代码生成器参数。<br><br>6、 *.DaoGen文件<br><br>配置DAO生成信息,并由CodeGenPlugin解析生成代码。<br><br> <br><br>AppFramework数据库访问组件针对IBatisNet的种种缺陷提出相应的解决方案,相比之下有如下优势:<br><br>1、 从扩展基础数据型入手,解决了空值问题和默认值问题;<br><br>2、 提供了内置的数据库内分页访问机制,极大地提高了海量查询的响应速度;<br><br>3、 增加ObjectTable<T>泛型来承载查询返回的对象集,不但比IList更加强型化,还提供了二分查找功能,使得对象结果集可以在应用程序内存中进行重排序和快速查找;<br><br>4、 提供了强大的QueryFilter构造查询条件,使得实现数据查询不再需要编写复杂的SQL语句;<br><br>5、 提供似IBatisNet的Sql模板功能,为复杂的查询统计提供较直观的开发模式;<br><br>6、 提供代码生成工具,生成的代码的同时可以之间的继承关系和接口实现关系,所有DAO方法均以接口作为参数,使得代码更加具有可扩展性和灵活性。<br><br>7、 Sql模板和ORMap直接生成.cs原代码,编译为可执行代码,各种ORMap映射文件无需再随主程序集一起部署,提高了代码的安全性,提高了代码的可调试性,也提高了ORMap的性能。<br><br> <br><br>下面三张表格罗列的测试数据,可以明显看出AppFramework数据库访问组件的性能全面超越了IBatisNet: <br><br> <br><br>表I –10并发20循环(数据库和测试机分开)<br><br>对比项目<br> iBatis2.0<br><br>(毫秒)<br> AppFramework<br><br>(毫秒)<br> 后者前者性能对比<br><br>(倍)<br> <br>根据主键获取实体<br><br>(20次单条select)<br> 19.8<br> 16.1<br><br>QueryFilter:18.0<br> 1.23<br><br>1.10<br> <br>每秒插入实体<br><br>(20次insert)<br> 41<br> 21<br> 1.95<br> <br>更新实体<br><br>(20次单条update)<br> 27<br> 19<br><br>SqlMap:24<br> 1.42<br><br>1.13<br> <br>查询结果集(平均101行)<br><br>(2循环200次select)<br> 1100<br> 690<br><br>不定字段:720<br> 1.59<br><br>1.53<br> <br><br> <br><br>表II –50并发4循环(数据库和测试机分开)<br><br>对比项目<br> iBatis2.0<br><br>(毫秒)<br> AppFramework<br><br>(毫秒)<br> 后者前者性能对比<br><br>(倍)<br> <br>根据主键获取实体<br><br>(20次单条select)<br> 17.5<br> 13.3<br><br>QueryFilter:14.5<br> 1.32<br><br>1.21<br> <br>插入实体<br><br>(20次insert)<br> 36.1<br> 17.4<br> 2.07<br> <br>更新实体<br><br>(20次单条update)<br> 23.5<br> 15.9<br><br>SqlMap:20.3<br> 1.48<br><br>1.16<br> <br>查询结果集(平均101行)<br><br>(1循环200次select)<br> 1055.1<br> 666.8<br><br>不定字段:710.1<br> 1.58<br><br>1.50<br> <br><br> <br><br>表III –50并发10循环(数据库和测试机同机)<br><br>对比项目<br> iBatis2.0<br><br>(毫秒)<br> AppFramework<br><br>(毫秒)<br> 后者前者性能对比<br><br>(倍)<br> <br>根据主键获取实体<br><br>(20次单条select)<br> 6.1<br> 5.3<br><br>QueryFilter: 5.75<br> 1.15<br><br>1.06<br> <br>插入实体<br><br>(20次insert)<br> 15.1<br> 10.8<br> 1.40<br> <br>更新实体<br><br>(20次单条update)<br> 10.4<br> 7.5<br><br>SqlMap:9.3<br> 1.38<br><br>1.12<br> <br>查询结果集(平均101行)<br><br>(1循环200次select)<br> 560<br> 360<br><br>不定字段:380<br> 1.56<br><br>1.47<br> <br><br> <br><br>总之,AppFramework数据库访问组件是一个高性能、接口简单、可移植性强、高灵活性的综合数据访问解决方案。使用AppFramework数据库访问组件,可以降低企业的开发人员培训成本,提高产品的开发速度,提高产品稳定可靠性,提高产品的可伸缩性和可移植性。下文将分入门、精通、高级三个篇章,详细讲述如何使用AppFramework数据库访问组件来搭建应用程序。 <br>
V1.1比V1.0增强了IDBSession功能,可查询得到 IDataReader;修改了查询 in 操作符的bug。<br>内含代码生成器,支持Oracle/SqlServer/MSAccess,ORMap性能大大优于iBatisNet,终身免费无限制使用,绝无任何版权问题。<br>===========<br>软件说明: <br>1.1 引言<br>约有90%的企业信息化管理系统基于数据库实现,这系统中又有超过30%的代码集中在数据访问层负责业务数据存取。除了实现数据的增删改查,数据访问层还要提供一些与业务无关功能,例如面向对象的持久化与访问机制、本地事务与分布式事务支持、多数据库支持,这些机制或功能形成相对独立的逻辑领域,其主要目的有:<br><br>1、 提供简单易用的数据库访问方法,提高开发效率;<br><br>2、 提供面向对象的方式来简化对数据库访问与操作,也就是ORMap方式;<br><br>3、 屏蔽数据库差异,使开发出的产品容易在不同数据库产品上移植。<br><br>为了适应软件快速开发的需要,软件企业应该借助组件产品或开源软件项目来搭建这些基础设施。在.Net平台上,目前比较成功和应用较广的开源项目有NHibernate和IBatisNet等,它们在ORMap方面的表现尤为突出。依赖这些平台,软件开发效率和产品质量都得到了极大提高,ORMap机制渐渐成为大势所趋。<br><br>本公司致力于软件组件开发,提供的AppFramework数据库访问组件具有高效的ORMap机制,调用接口简单灵活,支持各种主流的数据库平台,是个非常优秀的数据访问组件。本文详尽描述了AppFramework数据库访问组件使用的方法和技巧,有助于开发者最大程度发挥出AppFramework的优势。<br><br>1.2 各种优秀ORMap工具比较<br>NHibernate和IBatisNet等虽然都实现了ORMap,但它们的设计侧重点有所不同,有着各自的优势和缺陷,适合于特定的项目。NHibernate实现了纯对象化的ORMap,在屏蔽数据库差异、面向对象方面做的非常好,但在访问与操作海量数据时其性能表现较差,也不易实现复杂的查询统计功能。NHibernate适合那些数据量不大、性能要求不高、复杂度不高的场合。<br><br>IBatisNet是一个轻量级ORMap工具,它把所有的SQL脚本以模板的方式集中到若干个XML配置文件里,用反射的方式向把C#实体对象属性与SQL模板的参数绑定,动态生成参数化的SQL语句发送给数据库执行,查询的结果集也用反射的方式构造为对象集合返回给程序。由于提供了灵活的SQL模板机制,在海量数据的访问与操作方面其性能比NHibernate要高得多,也很容易实现各种复杂的数据查询统计功能。但是IBatisNet也存在许多几个不足之处,有些还是先天因素造成的:<br><br>第一,数据库可移植性差。IBatisNet获得高性能与灵活性也是付出代价的,它牺牲了数据库可移植性:由于编写SQL模板不得不用到数据库产品的一些语法差异,例如ORACLE的TO_DATE、Length()、SYSDATE等,为了把产品移植到其它数据库,开发人员不得不对大量的SQL模板进行翻译。<br><br>第二,无法方便地向数据库中插入NULL值。因为IBatisNet是直接把C#的基本型(如int/DateTime)插入到数据库中字段的。对于一些C#值型,例如int,并没有NULL状态。于是不得不采用一些特殊的值来表示NULL,例如int.MinValue。IBatisNet数据映射器会自动把int.MinValue转换为NULL插入到数据库,而从数据库中获得NULL时,也会转化为C#的int.MinValue。这样,程序就要对int.MinVaue这个值进行特殊处理,例如不能把int.MinValue直接显示在DataGrid里或界面上。有一种规避的方法,就是避免向数据库插入NULL,即要求所有业务数据入库的值都不为空。但这样作实际上是限制了程序的行为能力,例如无法实现单据草稿的保存。<br><br>第三,在插入数据时无法方便的使用字段默认值。最明显的就是似于LAST_UPDATE_TIME了,通常为了保证这个字段的一致性,通常在插入新记录时采用当前数据库时间作为字段值。但IBatisNet接收的实体类对象属性都是普通C#型,并不具备传入表达式的能力。如果采用动态SQL,则会导致SQL模板和参数实体类过于复杂,将极大降低性能。<br><br>第四,在查询返回大量对象时,用反射的方式构造实体的方式性能损失是相当大的。实体类属性数目越多、返回记录数越多,用到反射的次数也越多,查询性能降低就越明显。<br><br>第五,不能方便地限定查询语句返回的字段。ADO.Net执行查询时,select语句里设置了几个字段就返回几个字段到DataTable。而IBatisNet若要返回不同的字段就要定义多套ResultMap,否则就定义一套所有字段的ResultMap,任何查询都返回所有字段。这样无疑浪费了数据库服务器与应用服务器之间的网络带宽,在进行海量数据访问时性能将严重降低。<br><br>第六,返回的结果IList不能够方便地进行二次查询。相比之下,ADO.Net返回的DataTable虽然性能差一些,但可以实现在应用程序内存中灵活和高性能的二次查询。<br><br>第七,无法直接利用数据库的特殊语法支持海量数据的分页查询功能。众所周知Oracle提供了ROWNUM实现数据数据库内分页功能,若要利用这一特性,就要在SQL模板里直接硬编码这些特殊语法,这必然导致大量的移植工作。<br><br>第八、缺少代码生成和检查工具。程序里的变量名与Sql模板里的变量经常会出现不一致,而这些错误无法在编译时发现,靠人工检查很容易造成错误泄漏。也没提供工具直接生成SQL模板和映射配置文件。<br><br>第九,IBatisNet的SqlMap文件里的SQL语句以明文存放,容易被修改造成重大安全隐患,尤其不适合开发C/S应用程序。<br><br>第十,由于Sql模板采用动态加载的方式,如果写错了SQL,程序里难以跟踪调试,这对初学者来说无疑是对耐心和信心的极大考验。<br><br>总之,IBatisNet虽然提灵活、高性能的ORMap机制,但却损失了数据库可移植性的,在使用方便性和局部性能方面也都有很大提高的余地。<br><br>1.3 AppFramework数据访问组件的组成和优势<br>AppFramework数据访问组件由下列文件组成:<br><br>1、 AppFramework.DBAccess.dll<br><br>提供多数据库统一的访问接口,提供DAO管理器、数据库会话管理器。<br><br>2、 AppFramework.Data.dll<br><br>提供核心的数据结构和基础。<br><br>3、 AppFramework.Tools.CodeGenPlugin.msi<br><br>提供集成于Visual Studio 2005的C#代码生成器插件,用于生成DAO/Model/各种接口。<br><br>4、 DBAccess.config<br><br>配置数据库连接串。<br><br>5、 CodeGenPlogin.config<br><br>配置代码生成器参数。<br><br>6、 *.DaoGen文件<br><br>配置DAO生成信息,并由CodeGenPlugin解析生成代码。<br><br><br><br>AppFramework数据库访问组件针对IBatisNet的种种缺陷提出相应的解决方案,相比之下有如下优势:<br><br>1、 从扩展基础数据型入手,解决了空值问题和默认值问题;<br><br>2、 提供了内置的数据库内分页访问机制,极大地提高了海量查询的响应速度;<br><br>3、 增加ObjectTable<T>泛型来承载查询返回的对象集,不但比IList更加强型化,还提供了二分查找功能,使得对象结果集可以在应用程序内存中进行重排序和快速查找;<br><br>4、 提供了强大的QueryFilter构造查询条件,使得实现数据查询不再需要编写复杂的SQL语句;<br><br>5、 提供似IBatisNet的Sql模板功能,为复杂的查询统计提供较直观的开发模式;<br><br>6、 提供代码生成工具,生成的代码的同时可以之间的继承关系和接口实现关系,所有DAO方法均以接口作为参数,使得代码更加具有可扩展性和灵活性。<br><br>7、 Sql模板和ORMap直接生成.cs原代码,编译为可执行代码,各种ORMap映射文件无需再随主程序集一起部署,提高了代码的安全性,提高了代码的可调试性,也提高了ORMap的性能。<br><br><br><br>下面三张表格罗列的测试数据,可以明显看出AppFramework数据库访问组件的性能全面超越了IBatisNet: <br><br><br><br>表I –10并发20循环(数据库和测试机分开)<br><br>对比项目<br>iBatis2.0<br><br>(毫秒)<br>AppFramework<br><br>(毫秒)<br>后者前者性能对比<br><br>(倍)<br><br>根据主键获取实体<br><br>(20次单条select)<br>19.8<br>16.1<br><br>QueryFilter:18.0<br>1.23<br><br>1.10<br><br>每秒插入实体<br><br>(20次insert)<br>41<br>21<br>1.95<br><br>更新实体<br><br>(20次单条update)<br>27<br>19<br><br>SqlMap:24<br>1.42<br><br>1.13<br><br>查询结果集(平均101行)<br><br>(2循环200次select)<br>1100<br>690<br><br>不定字段:720<br>1.59<br><br>1.53<br><br><br><br><br>表II –50并发4循环(数据库和测试机分开)<br><br>对比项目<br>iBatis2.0<br><br>(毫秒)<br>AppFramework<br><br>(毫秒)<br>后者前者性能对比<br><br>(倍)<br><br>根据主键获取实体<br><br>(20次单条select)<br>17.5<br>13.3<br><br>QueryFilter:14.5<br>1.32<br><br>1.21<br><br>插入实体<br><br>(20次insert)<br>36.1<br>17.4<br>2.07<br><br>更新实体<br><br>(20次单条update)<br>23.5<br>15.9<br><br>SqlMap:20.3<br>1.48<br><br>1.16<br><br>查询结果集(平均101行)<br><br>(1循环200次select)<br>1055.1<br>666.8<br><br>不定字段:710.1<br>1.58<br><br>1.50<br><br><br><br><br>表III –50并发10循环(数据库和测试机同机)<br><br>对比项目<br>iBatis2.0<br><br>(毫秒)<br>AppFramework<br><br>(毫秒)<br>后者前者性能对比<br><br>(倍)<br><br>根据主键获取实体<br><br>(20次单条select)<br>6.1<br>5.3<br><br>QueryFilter: 5.75<br>1.15<br><br>1.06<br><br>插入实体<br><br>(20次insert)<br>15.1<br>10.8<br>1.40<br><br>更新实体<br><br>(20次单条update)<br>10.4<br>7.5<br><br>SqlMap:9.3<br>1.38<br><br>1.12<br><br>查询结果集(平均101行)<br><br>(1循环200次select)<br>560<br>360<br><br>不定字段:380<br>1.56<br><br>1.47<br><br><br><br><br>总之,AppFramework数据库访问组件是一个高性能、接口简单、可移植性强、高灵活性的综合数据访问解决方案。使用AppFramework数据库访问组件,可以降低企业的开发人员培训成本,提高产品的开发速度,提高产品稳定可靠性,提高产品的可伸缩性和可移植性。下文将分入门、精通、高级三个篇章,详细讲述如何使用AppFramework数据库访问组件来搭建应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值