现在最如日中天的是Hibernate,但老朽学了一下,然后就没有再学下去,原因简单,因为设计思路不同。以前做的系统全是在设计完成后,数据库先行,并且有大量的主从表以及存储过程,触发器以及函数等内容,这是由于需要充分利用DBMS本身的优化设计以提高性能和使用的便利,这点Hibernate是无法体会得到的。
另外,这种设计思想对于熟悉SQL的人来讲并感觉不到太大的方便之处,除了不用再在编写增修删等的工作上进行重复劳动,而HQL更是有点过分的感觉。
当然,老朽对Hibernate了解不多,所以可能其没非如此弱也不一定,但已经不想再花时间来更深入的了解一下了,这个时间可以设计一个新的ORM,差不多吧?差多了,呵呵。
其优点在于:
1. 由面向表格转为面向对象,其实这样说有偏颇之处,表格如果是按基本的设计方式来的话,大部分是实体的数据表现,其本身就是对象,虽然是基于关系数据库的表现。
2. 隐藏了SQL,就是将对数据库系统的直接操作隐藏了起来,好处是使不谙数据库的开发人员可以不用再学,而直接使用某语言的方式就可以做,坏处是,这样使得数据库本身只是成为了数据存储器,而其本身的好处再也体现不出来了。
好象上面说的不是优点,不过第一句话是优点的,确实是,但其后面却有几个概念和应用上的误解,目前对很多初入门的同学影响很大,唉,计算器应用的技术又岂是一语可盖之的,因为应用是世界一种在基础层面之上一个层面的表现方式,故亦如世界本身一样,包罗万象也。
好久以前,大约一年多了吧,知道有个ibatis这样一个东西,却一直没有看一下,只是由朋友和一些简要的文档那里知道一些特性,就是它是由自己定义SQL来的,没有完全封装,所以提供了更大的自由度和扩展性,于是,也就不如Hibernate来的彻底和方便。
应用学习者,由实例入门也,此方为正途,省时又易上手。
于是编一个小小的例子,只对一个单表进行基本操作,感觉还行,例程写法,后面再一步步的来列出来,兼之批评一下,有一些文章对例程往往语焉不详,特别在当前配置文件大行其道的时候,对配置文件的位置竟然不讲,而且一文中,文件名始与终不统一,颇有些始乱终弃的感觉,嘿嘿,此词用得可能不好,却是最好的写照,此类文章是浪费时间的最好去处,读到最后,按例程走的结果是失败,真是赔了时间又走错路。
好了,在做完该小例后,开始乱想,主要有几个方面:
1. 主从表的处理
2. 存储过程的处理
3. 不规则查询的处理
4. 编写工具程序的实现
最近可能是由于更多倾向于IDE的设计,所以对第四条想得比较多些,对于主从表的处理,老朽一直没有想到一个比较好的处理方法,特别对于数据新增和修改的准确性上面,很是有点头痛。
主从表的问题,主要是体现在对主从表同时新增和修改的情况,从表数据的准确性验证比较复杂。事务在这里并不是万能的,所以这里应该更多的考虑在数据库之前的验证准确性应该是解决问题的核心所在吧。
编写工具程序,想了一下,对ibatis如果要进行编写并不是一个简单的事情,因为里面客制化的内容比较多,想了一下,就决定不想了。
最近更在考虑一个元对象的问题,就是将类的属性本身实际上也是一个对象,那么这个类别的类的设计,其实也就是一种元数据了,这样可以对类的属性进行统一,从而可以在应用层处理上提供更大的方便,比如输入界面,可以通过程序直接动态拉出来等等吧。
参考文档:
1. iBATIS Database Layer开发指南
Clinton Begin 着刘涛译www.ibatis.com
------------------------------------------------------------------------
附:ibatis例程(注:该例来自于参考文档,改正了其中的部分错误)
1. 构造环境
1.1. 建立PRoject目录结构,这一部分很简单,老朽用eclipse,目录结构如下:
1.2. 将相关的类库包文件复制至ibatis目录下面,并加入到该工程的build path,就是加入classpath:
如此,工程的基本环境构建完成。
2. 建立数据表并设置数据源(注:在这里,为了方便,使用了桥接方式)
2.1. 建立数据表,SQL如下,老朽用的是SQLServer,无他,只因机器上有。
CREATE TABLE PERSON (
PER_ID numeric(5, 0) NOT NULL ,
PER_FIRST_NAME varchar (40) NOT NULL ,
PER_LAST_NAME varchar (40) NOT NULL ,
PER_BIRTH_DATE datetime NULL ,
PER_WEIGHT_KG numeric(4, 2) NOT NULL ,
PER_HEIGHT_M numeric(4, 2) NOT NULL ,
PRIMARY KEY (PER_ID)
)
2.2. 建立数据源,并指向Person表所在的数据库
3. 编写例程代码,在这里,只是建立对Person表的基本操作代码,如新增,修改和删除而已。
3.1. Person.java 这是基本类,该类就是提供一个基本结构
package examples.domain;
import java.util.Date;
public class Person{
private int id; // PER_ID
private String firstName; // PER_FIRST_NAME
private String lastName; // PER_LAST_NAME
private Date birthDate; // PER_BIRTH_DATE
private double weightInKilograms; // PER_WEIGHT_KG
private double heightInMeters; // PER_HEIGHT_M
public Person(){}
public String toString(){
return "[" + id + "" + firstName + "" +
lastName + "" + birthDate + "" + weightInKilograms +
"" + heightInMeters + "]";
}
public Date getBirthDate(){ return birthDate; }
public void setBirthDate(Date birthDate){ this.birthDate = birthDate; }
public String getFirstName(){ return firstName; }
public void setFirstName(String firstName){ this.firstName = firstName; }
public double getHeightInMeters(){ return heightInMeters; }
public void setHeightInMeters(double heightInMeters){
this.heightInMeters = heightInMeters;
}
public int getId(){ return id; }
public void setId(int id){ this.id = id; }
public String getLastName(){ return lastName; }
public void setLastName(String lastName){ this.lastName = lastName; }
public double getWeightInKilograms(){ return weightInKilograms; }
public void setWeightInKilograms(double weightInKilograms){
this.weightInKilograms = weightInKilograms;
}
}
3.2. Person.xml SQL映射文件,这个就是将SQL语句与ibatis的数据操作方法相映像的文件
"http://www.ibatis.com/dtd/sql-map.dtd">
SELECT PER_ID as id,
PER_FIRST_NAME as firstName,
PER_LAST_NAME as lastName,
PER_BIRTH_DATE as birthDate,
PER_WEIGHT_KG as weightInKilograms,
PER_HEIGHT_M as heightInMeters
FROM PERSON
WHERE PER_ID = #value#
]]>
INSERT INTO PERSON(
PER_ID,
PER_FIRST_NAME,
PER_LAST_NAME,
PER_BIRTH_DATE,
PER_WEIGHT_KG,
PER_HEIGHT_M)
VALUES (
#id#,
#firstName#,
#lastName#,
#birthDate#,
#weightInKilograms#,
#heightInMeters#
)
]]>
UPDATE PERSON SET
PER_FIRST_NAME = #firstName#,
PER_LAST_NAME = #lastName#,
PER_BIRTH_DATE = #birthDate#,
PER_WEIGHT_KG = #weightInKilograms#,
PER_HEIGHT_M = #heightInMeters#
WHERE PER_ID = #id#
]]>
DELETE PERSON WHERE PER_ID = #id#
3.3. SqlMapConfigExample.properties 数据库连接属性文件
driver=sun.jdbc.odbc.JdbcOdbcDriver
url=jdbc:odbc:test
username=sa
passWord=123456
3.4. SqlMapConfigExample.xml ibatis基本配置文件,核心配置文件
"http://www.ibatis.com/dtd/sql-map-config.dtd">
resource="examples/sqlmap/maps/SqlMapConfigExample.properties" />
maxTransactions="10" statementCacheSize="75" useGlobalTransactions="false" />
factory-class="com.ibatis.db.sqlmap.datasource.DbcpDataSourceFactory">
3.5. MyAppSqlConfig.java 调用及测试程序
package example.application;
import java.io.Reader;
import java.util.Date;
import com.ibatis.common.resources.Resources;
import com.ibatis.db.sqlmap.SqlMap;
import com.ibatis.db.sqlmap.XmlSqlMapBuilder;
import examples.domain.Person;
public class MyAppSqlConfig{
private static final SqlMap sqlMap;
static{
try{
String resource = "SqlMapConfigExample.xml";
Reader reader = Resources.getResourceAsReader(resource);
sqlMap = XmlSqlMapBuilder.buildSqlMap(reader);
}catch(Exception e){
e.printStackTrace();
throw new RuntimeException("Error initializing: " + e);
}
}
public static SqlMap getSqlMapInstance(){ return sqlMap; }
public static void main(String[] args){
SqlMap sqlMap = MyAppSqlConfig.getSqlMapInstance();
Integer id = new Integer(2);
try{
// Select
Person person =
(Person)sqlMap.executeQueryForObject("getPerson", id);
System.out.println("....person=" + person);
// Update
person.setId(3);
person.setFirstName("Deny");
person.setLastName("Liu");
person.setBirthDate(new Date());
person.setHeightInMeters(1.83);
person.setWeightInKilograms(86.36);
System.out.println("....update=" +
sqlMap.executeUpdate("updatePerson", person));
// Delete
person.setId(1);
System.out.println("....delete=" +
sqlMap.executeUpdate("deletePerson", person));
// Create
Person newPerson = new Person();
newPerson.setId(1);
newPerson.setFirstName("Clinton");
newPerson.setLastName("Begin");
newPerson.setBirthDate(new Date());
newPerson.setHeightInMeters(1.83);
newPerson.setWeightInKilograms(86.36);
System.out.println("....insert=" +
sqlMap.executeUpdate ("insertPerson", newPerson));
}catch(Exception e){
e.printStackTrace();
}
}
}
在这个简单的例程中,数据库连接池使用了DBCP,是apache的东东,具体也没有研究过,呵呵,虽然现在的数据库连接池种类繁多,但大多都走得太远了,在一个连接池的包里面恨不得将整个SQL的操作全包进来,弄得不伦不类,又大又不方便,而且还用不起来,唉
好啦,没用的不说了,全部完成后的工程样子长得像下面这样:
运行MyAppSqlConfig.java的结果嘛,哦,还要先在Person表里面加三笔测试数据,然后再运行,否则会出异常,然后就可以看得到通过ibatis对数据表的操作结果了,就是下个SQL看一下嘛,嘿嘿,人老啦,总是会忘事儿
(出处:http://www.knowsky.com)