拿起笔来做刀枪 · 之六 再造一个hibernate
2014-07-28 15:00
465 查看
hibernate有两个比较有趣的地方:
一个是它的core feature : ORM。
还有一个是它的HQL 与多种sql语法体系的映射。
第二个部分其实我们很少用到,而且相对比较复杂,涉及到词法分析、语法树构建等一系列编译原理的天坑。
我们还是从最直观的入手:ORM。
先从我们第一直观印象,构建我们的需求接口:
以上代码,提供了直观的需求:不用写sql语句,就能通过对象,和数据库直观的联系起来。
当然还涉及到我们自定义的两个类:
这个接口没有特殊含义,仅仅是一个分类或者描述功用的标志,就跟
在就是 Document
好了,现在我们的工作就是让main方法执行起来不出错就OK了。
继续简化一下思路,insert和update操作,orm做的操作中心在:将Object class 转成对应的sql语句。
我们假设表名和类名一致,字段名和类成员变量名一致,那么,对于Document类,对应的db table为:
因此,我们采取java的reflect机制完成这个工作:
输出结果符合预期。
注意:简便起见,代码里面我们只判断了两种数据类型:int 和 string。
我们只是完成了sql语句的组织,由于我们并没有决定使用什么数据库,所以当前给出的方法:
仅仅只是抛出异常:
同理,我们搞定insert方法:
对应的语句是:
最后是load方法,现在我们要换一个角度,load所做的事情,是把根据sql查询出来的结果进行bean的实例化和赋值。
这里我们同样先定义一个待底层实现的sql查询方法:
Last ROUND!!!!
现在,让我们基于sqlite来做一个实现:)
RUN一下试试:
可以看到,我们成功的创建了表,然后插入了6项数据,然后根据ID 1.。。。6 逐一查询打印了出来。
一个是它的core feature : ORM。
还有一个是它的HQL 与多种sql语法体系的映射。
第二个部分其实我们很少用到,而且相对比较复杂,涉及到词法分析、语法树构建等一系列编译原理的天坑。
我们还是从最直观的入手:ORM。
先从我们第一直观印象,构建我们的需求接口:
package net.csdn.blog.deltatang.hibernate4me; public abstract class SqlEngine { public abstract void createTable(Class<? extends DbValObj> clazz); public abstract void insert(DbValObj valObj); public abstract DbValObj load(int id, Class<? extends DbValObj> clazz); public void test() { createTable(Document.class); Document doc1 = new Document(1, "解放区的天是明朗的天", "Document 1 的正文内容"); Document doc2 = new Document(2, "从来就没有什么救世主,也没有神仙皇帝", "Document 2 的正文内容"); Document doc3 = new Document(3, "中国人民从此站立起来了", "Document 3 的正文内容"); Document doc4 = new Document(4, "东风吹,战鼓擂,如今世上谁怕谁", "Document 4 的正文内容"); Document doc5 = new Document(5, "不是东风压倒西风,就是西风压倒东风", "Document 5 的正文内容"); Document doc6 = new Document(6, "人民万岁,人民万岁", "Document 6 的正文内容"); insert(doc1); insert(doc2); insert(doc3); insert(doc4); insert(doc5); insert(doc6); for(int i = 1; i < 7; i++) { Document doc = (Document) load(i, Document.class); System.out.println(doc); } } }
以上代码,提供了直观的需求:不用写sql语句,就能通过对象,和数据库直观的联系起来。
当然还涉及到我们自定义的两个类:
package net.csdn.blog.deltatang.hibernate4me; public interface DbValObj { }
这个接口没有特殊含义,仅仅是一个分类或者描述功用的标志,就跟
java.io.Serializable是一样的作用,好像叫做什么模式来着? java 的模式太特么泛滥了,俺实在想不起来了:)
在就是 Document
package net.csdn.blog.deltatang.hibernate4me; public class Document implements DbValObj { private int id; private String title; private String content; public Document() { super(); } public Document(int id, String title, String content) { super(); this.id = id; this.title = title; this.content = content; } public int getId() { return id; } public String getTitle() { return title; } public String getContent() { return content; } @Override public String toString() { return "Document [id=" + id + ", title=" + title + ", content=" + content + "]"; } }这个前文有提到,检索的内容资源。
好了,现在我们的工作就是让main方法执行起来不出错就OK了。
继续简化一下思路,insert和update操作,orm做的操作中心在:将Object class 转成对应的sql语句。
我们假设表名和类名一致,字段名和类成员变量名一致,那么,对于Document类,对应的db table为:
create table Document (id integer, title text, content text )
因此,我们采取java的reflect机制完成这个工作:
@Override public void createTable(Class<? extends DbValObj> clazz) { StringBuffer sql = new StringBuffer(); sql.append("create table "); String tabname = clazz.getSimpleName(); sql.append(tabname); sql.append(" ("); Field[] fs = clazz.getDeclaredFields(); for(Field f : fs) { String fname = f.getName(); sql.append(fname).append(" "); Class fc = f.getType(); if(fc == Integer.class) { sql.append(fname).append("integer, "); } else { sql.append(fname).append("text, "); } } sql.deleteCharAt(sql.lastIndexOf(",")); sql.append(")"); System.out.println(sql); try { update(sql.toString()); } catch (Exception e) { e.printStackTrace(); } }
输出结果符合预期。
注意:简便起见,代码里面我们只判断了两种数据类型:int 和 string。
我们只是完成了sql语句的组织,由于我们并没有决定使用什么数据库,所以当前给出的方法:
update(sql.toString());
仅仅只是抛出异常:
private void update(String sql) throws Exception { throw new RuntimeException("func update(String sql) is not implemented."); }
同理,我们搞定insert方法:
对应的语句是:
insert into Document (id, title, content) values (1, 'aaa', 'bbbbb')
@Override public void insert(DbValObj valObj) { Class clazz = valObj.getClass(); StringBuffer sql = new StringBuffer(); sql.append("insert into "); String tabname = clazz.getSimpleName(); sql.append(tabname); sql.append(" ("); List<Object> values = new ArrayList<Object>(); Field[] fs = clazz.getDeclaredFields(); for(Field f : fs) { f.setAccessible(true); String fname = f.getName(); sql.append(fname).append(", "); Object value = ""; try { value = f.get(valObj); } catch (Exception e) { e.printStackTrace(); } values.add(value); } sql.deleteCharAt(sql.lastIndexOf(",")); sql.append(")"); sql.append(" values ("); for(Object val : values) { if(val instanceof Integer) { sql.append("").append(val).append(", "); } else { sql.append("'").append(val).append("', "); } } sql.deleteCharAt(sql.lastIndexOf(",")); sql.append(")"); System.out.println(sql); try { update(sql.toString()); } catch (Exception e) { e.printStackTrace(); } }
最后是load方法,现在我们要换一个角度,load所做的事情,是把根据sql查询出来的结果进行bean的实例化和赋值。
这里我们同样先定义一个待底层实现的sql查询方法:
private Map<String, String> select(String sql) throws Exception { throw new RuntimeException("func select(String sql) is not implemented."); }这个方法,跟spring jdbctemplate 的 getMap 方法异曲同工:)然后是,实例赋值部分:
@Override public DbValObj load(int id, Class<? extends DbValObj> clazz) { String tabname = clazz.getSimpleName(); String sql = "select * from " + tabname + " where id=" + id; Map<String, String> row = null; try { row = select(sql); } catch (Exception e) { e.printStackTrace(); return null; } DbValObj obj = null; try { obj = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); return null; } Field[] fs = clazz.getDeclaredFields(); for(Field f : fs) { f.setAccessible(true); String key = f.getName(); String val = row.get(key); try { if(f.getType().getSimpleName() == "int") { f.set(obj, Integer.parseInt(val)); } else { f.set(obj, val); } } catch (Exception e) { e.printStackTrace(); } } return obj; }
Last ROUND!!!!
现在,让我们基于sqlite来做一个实现:)
package net.csdn.blog.deltatang.hibernate4me; import java.io.File; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import SQLite.Callback; import SQLite.Database; public class SqliteDB extends SqlEngine { private Database database; public SqliteDB(String dbpath) { super(); File dbf = new File(dbpath); dbf.delete(); try { this.database = new Database(); database.open(dbpath, 0755); database.set_encoding("utf-8"); } catch (Exception e) { } } private Map<String, String> select(String sql) throws Exception { final List<String> cols = new ArrayList<String>(); final List<String> vals = new ArrayList<String>(); database.exec(sql, new Callback() { @Override public void types(String[] arg0) { } @Override public boolean newrow(String[] arg0) { for(String val : arg0) { vals.add(val); } return false; } @Override public void columns(String[] arg0) { for(String val : arg0) { cols.add(val); } } }); Map<String, String> res = new HashMap<String, String>(cols.size()); for(int i = 0; i < cols.size(); i++) { res.put(cols.get(i), vals.get(i)); } return res; } private void update(String sql) throws Exception { database.exec(sql, new Callback() { @Override public void types(String[] arg0) { } @Override public boolean newrow(String[] arg0) { return false; } @Override public void columns(String[] arg0) { } }); } @Override public void createTable(Class<? extends DbValObj> clazz) { //............................ <pre name="code" class="java">//............................}@Overridepublic void insert(DbValObj valObj) {
//............................}@Overridepublic DbValObj load(int id, Class<? extends DbValObj> clazz) {
//............................}public static void main(String[] args) throws Exception {SqlEngine sdb = new SqliteDB("d:/docs.db");sdb.test();}}
RUN一下试试:
create table Document (id idtext, title titletext, content contenttext ) insert into Document (id, title, content ) values (1, '解放区的天是明朗的天', 'Document 1 的正文内容' ) ....................... insert into Document (id, title, content ) values (6, '人民万岁,人民万岁', 'Document 6 的正文内容' ) Document [id=1, title=解放区的天是明朗的天, content=Document 1 的正文内容] ....................... Document [id=6, title=人民万岁,人民万岁, content=Document 6 的正文内容]
可以看到,我们成功的创建了表,然后插入了6项数据,然后根据ID 1.。。。6 逐一查询打印了出来。
相关文章推荐
- 拿起笔来做刀枪 · 之四 再造一个struts
- 拿起笔来做刀枪 · 之三 再造一个jsp(java sign pages)
- 拿起笔来做刀枪 · 之二 再造一个spring
- 拿起笔来做刀枪 · 之五 再造一个lucene
- 拿起笔来做刀枪 · 之一 再造一个dom4j
- 拿起笔来做刀枪 · 之七 最终幻想 Final Fantasy
- 拿起笔来做刀枪 · 序言
- 苹果史蒂夫·乔布斯辞世 一个传奇时代的终结
- 写一个sql中视图和存储过程的简单创建和调用方法!!!自我备忘用····
- 又是一个新的‘站点·
- 怎么样从一个疯狂下载者成为一个学习者!!!值得反省下的问题·~~
- 刷 百度排名,百度(google)搜索提示下拉关联词的一个简易思路··
- 「ONE · 一个 」优雅PC客户端
- Hibernate ORM(1):创建一个Maven & Hibernate & MySQL应用
- 切·格瓦拉 ———— 一个英雄的一生!
- 《编程导论(Java)·例程》tips.Print的一个bug
- 从零开始C++ 第二课 CC++初体验,编写一个简单的程序·hello C++ 课程一天第二课
- 汉斯·乌尔里希·鲁德尔-唯一一个钻石金双剑金橡叶骑士勋章获得者
- 微软二十五年(比尔·盖茨) --- 我们都在同一个游泳池里游泳
- javascript入门·脚本执行的时间的四种类型(赠送一个转换的小例题)