先来看一段常见的数据库操作代码:

```
protected User getDataFromDatabase(long id){
String sql = "select firstname from user where id=?";//1
Connection conn = DBConnectionFactory.getConnection();
PreparedStatement stat;
User user;//2
try {
stat = conn.prepareStatement(sql);
stat.setObject(1, id);
ResultSet rs = stat.executeQuery();
user.setFirstName(rs.getString("firstname"));//3
stat.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return user;
}
``` 在上面代码中存在三个可变部分,如果需要把数据库操作代码修改为任何对象都能使用的同一段代码,则需要提取出这三个可变部分。所以我们修改一下上面代码。
1、首先提取一下sql语句部分。如果我们可以动态生成该sql语句,数据库对象映射器应该就完成了一半。所以我们先来拆解sql语句,看看下面这段代码:
```
String selectList="firstname";
String whereClause="id=?";
String tableName = "user";
String sql = "select " + selectList +" from " + tableName +" where " + whereClause;
protected User getDataFromDatabase(String sql,long id){
//String sql = "select firstname from user where id=?";//1
Connection conn = DBConnectionFactory.getConnection();
PreparedStatement stat;
User user;//2
try {
stat = conn.prepareStatement(sql);
stat.setObject(1, id);
ResultSet rs = stat.executeQuery();
user.setFirstName(rs.getString("firstname"));//3
stat.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return user;
}
```
拆解了第一部分,现在看起来好像也感觉差别不大,仅仅是把sql当作参数传递进去。关于第二第三可变部分,我们再来看看下面这段代码: ```
String selectList="firstname";
String whereClause="id=?";
String tableName = "user";
String sql = "select " + selectList +" from " + tableName +" where " + whereClause;
Class klass = User.class;
String fieldName = "firstName";
String columnName = "firstname";
Field field = klass.getDeclaredField(fieldName);
protected Object getDataFromDatabase(String sql,Object id){
//String sql = "select id,firstname from user where id=?";//1
Connection conn = DBConnectionFactory.getConnection();
PreparedStatement stat;
Object user;//2
try {
stat = conn.prepareStatement(sql);
stat.setObject(1, id);
ResultSet rs = stat.executeQuery();
user = klass.newInstance();
field.set(user,rs.getObject(columnName));
//user.setFirstName(rs.getString("firstname"));//3
stat.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return user;
}
```
现在再重新看函数体内,与特定user对象的信息,好像没有了,当然这里为了简化问题,user对象只有一个firstname,后面会看到有多个变量时,仅仅是field.set()那里变成了一个for循环。然后我们再来优化一下代码,毕竟所有代码堆在一个地方乱七八糟,非常不容易理解。而且如果代码仅仅是这样的话,也没有任何的可重用性。我们先把函数体提取到BaseMapper.class。把其他可变的部分,提取到TableMap.class和OneToOneColumnMap.class。TableMap存储对象与数据库表映射信息,OneToOneColumnMap存储对象field与表列的映射信息。每一个对象都会有一个BaseMapper实例,存储各自的对象关系映射信息。代码如下:
```
class BassMapper{
protected TableMap<T> tableMap;
public Object getDataFromDatabase(String sql,Object... param){
Connection conn = DBConnectionFactory.getConnection();
PreparedStatement stat;
Object result = null;
try {
stat = conn.prepareStatement(sql);
for(int i = 0;i < param.length;i++){
stat.setObject(i + 1, param[i]);
}
ResultSet rs = stat.executeQuery();
if(rs.next()){
result = (T) tableMap.getKlass().newInstance();
for(Iterator<OneToOneColumnMap> it = tableMap.getOneToOneColumns();it.hasNext();){
OneToOneColumnMap columnMap = it.next();
Object columnValue = rs.getObject(columnMap.getColumnName());
columnMap.setField(result, columnValue);
}
}
stat.close();
} catch (SQLException | InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
}
}
``` ```
class OneToOneColumnMap{
private String columnName;
private String fieldName;
protected Field field;
private TableMap dataMap; public OneToOneColumnMap(String columnName,String fieldName,TableMap dataMap){
this.columnName = columnName;
this.fieldName = fieldName;
this.dataMap = dataMap;
initField();
} public String getColumnName(){
return this.columnName;
} public String getFieldName(){
return this.fieldName;
} public Object getValue(Object subject){
try {
return field.get(subject);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
} public void setField(Object result,Object columnValue){
try {
field.set(result, columnValue);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} protected void initField(){
try {
this.field = dataMap.getKlass().getDeclaredField(getFieldName());
field.setAccessible(true);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
``` ```
class TableMap{
private Class<T> domainClass;
private String tableName;
private OneToOneColumnMap primaryKeyColumn;
private List<OneToOneColumnMap> oneToOneColumnMaps = new ArrayList<OneToOneColumnMap>(); public TableMap(String tableName,Class<T> domainClass){
this.domainClass = domainClass;
this.tableName = tableName;
}
public void addOneToOneColumn(String columnName,String fieldName){
OneToOneColumnMap columnMap = new OneToOneColumnMap(columnName,fieldName,this);
if(!oneToOneColumnMaps.contains(columnMap)){
if(primaryKeyColumn == null){
primaryKeyColumn = columnMap;
}
oneToOneColumnMaps.add(columnMap);
}
} public void setPrimaryKeyColumn(String columnName, String fieldName){
this.primaryKeyColumn = new OneToOneColumnMap(columnName,fieldName,this);
if(!oneToOneColumnMaps.contains(primaryKeyColumn)){
oneToOneColumnMaps.add(primaryKeyColumn);
}
} public String primaryKeyWhereClause(){
return primaryKeyColumn.getColumnName() + " = ? ";
} public Object primaryKeyColumnName(){
return primaryKeyColumn.getColumnName();
} public Object primaryKeyValue(Object domainObject){
return primaryKeyColumn.getValue(domainObject);
} public String getTableName(){
return this.tableName;
} public String insertList(){
StringBuffer result = new StringBuffer("?");
for(int i = 0;i < oneToOneColumnMaps.size() - 1;i++){
result.append(",");
result.append("?");
}
return result.toString();
} public String columnList(){
StringBuffer result = new StringBuffer(" ");
for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
OneToOneColumnMap columnMap = it.next();
result.append(columnMap.getColumnName());
result.append(",");
}
result.setLength(result.length() - 1);
return result.toString();
} public String updateList(){
StringBuffer result = new StringBuffer(" SET ");
for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
OneToOneColumnMap column = it.next();
result.append(column.getColumnName());
result.append("=?,");
}
result.setLength(result.length() - 1);
return result.toString();
} public String getColumnForField(String fieldName){
for(Iterator<OneToOneColumnMap> it = getOneToOneColumns();it.hasNext();){
OneToOneColumnMap columnMap = it.next();
if(columnMap.getFieldName().equals(fieldName)){
return columnMap.getColumnName();
}
}
return null;
}
}
```
BaseMapper通过一个TableMap来初始化,依赖关系如下:
![这里写图片描述](http://img.blog.csdn.net/20170211104536444?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvaHV4dWVtaW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
项目代码:https://github.com/hu-xuemin/xBlog.git

一个基于注解的orm简单实现(二):实现思路的更多相关文章

  1. 基于注解的SpringMVC简单介绍

    SpringMVC是一个基于DispatcherServlet的MVC框架,每一个请求最先访问的都是DispatcherServlet,DispatcherServlet负责转发每一个Request请 ...

  2. 【转】基于注解的SpirngMVC简单介绍

    转载地址:http://haohaoxuexi.iteye.com/blog/1343761 SpringMVC是一个基于DispatcherServlet的MVC框架,每一个请求最先访问的都是 Di ...

  3. SpringMVC学习总结(四)——基于注解的SpringMVC简单介绍

    SpringMVC是一个基于DispatcherServlet的MVC框架,每一个请求最先访问的都是 DispatcherServlet,DispatcherServlet负责转发每一个Request ...

  4. 【转载】基于注解的SpringMVC简单介绍

    SpringMVC是一个基于DispatcherServlet的MVC框架,每一个请求最先访问的都是DispatcherServlet,DispatcherServlet负责转发每一个Request请 ...

  5. 实现一个基于tcc/tlink的简单的编译链接工具

    一.基础研究 在这里我们需要提供一套新的c语言开发工具cc,它支持的c程序不是从main开始运行而是从CMain开始运行. 书上已经对该工具程序进行了需求分析:(1)要在屏幕中间显示彩色的字符串:(2 ...

  6. LineCalc,一个基于Lex&Yacc的简单行计算工具

    LineCalc是基于Lex&Yacc的一个简单的行计算工具,支持常见的运算符和部分POSIX中定义于math.h中的数学函数:同时,LineCalc还提供了一个简单的错误处理模块,能检测公式 ...

  7. 一个基于EntityFramework Core的简单数据库访问层,适用于轻量级数据库业务

    这个访问层的代码实际上是园子里某个前辈的,本人只是觉得好使,记录了下来. 本访问层需要通过Nuget安装EntityFramework Core,不过个人认为EF 6同样可以使用. 搭配数据库,最好是 ...

  8. 一个基于tcp的socket简单对话小例子

    首先我们需要写连个py文件,一个server,一个client. import socket sk = socket.socket() # sk.bind(('ip',port)) sk.bind(( ...

  9. Mario是一个基于.NETCore的简单快速开发框架

    Mario .NET Core简单快速开发框架 Mario是一个基于.NET Core的简单快速开发框架 GitHub:https://github.com/deeround/Mario 技术特点 基 ...

随机推荐

  1. 【推荐】PHP中格式化时间函数date与gmdate的区别 | 修改PHP的默认时区

    PHP中的时间有2个格式化函数:date()和gmdate(),在官方的文档中的描述为: date -- 格式化一个本地时间/日期 gmdate -- 格式化一个 GMT/UTC 日期/时间,返回的是 ...

  2. java系列--I/O流

    java.io类 一.I/O流 1.流的概念 二. InputStream --此抽象类是表示字节输入流的所有类的超类. 1.public int read(byte[] b) throws IOEx ...

  3. 微信上传图片接口实现 JS

    //2.微信上传图片接口实现 <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></scri ...

  4. mysql常用博客论坛

    大神博客: starive的博客:http://blog.itpub.net/26435490/viewspace-1133659/ 北在南方的博客:http://blog.itpub.net/226 ...

  5. YII 1.0 隐藏单入口index.php 设置路由与伪静态

    隐藏 index.php 保证apache配置文件httpd.conf里的LoadModulerewrite_module modules/mod_rewrite.so开启(去掉#)将相对应目录的Al ...

  6. PHP的一些 有用但不常用的函数记录

    1. microtime() 当前 Unix 时间戳以及微秒数. <?php $mem = new Memcache; $mem->connect("127.0.0.1" ...

  7. eclipse开发velocity实例(初学)

    开发环境         Eclipse Java EE IDE for Web Developers.(Version: Helios Service Release 1) jdk1.6.0_07 ...

  8. Ubuntu 14.04下搭建Node.js的开发环境

    最近想找一个轻量级且支持快速开发的服务开发平台,选来选去选择了Node.js,当时有几种选择: Python + Django(用过Django,虽然开发快速,但是感觉性能并不太好). Ruby + ...

  9. HMX-Server C++ 分步式服务器大版本更新了(有源码)

    原文地址:http://www.cnblogs.com/hellohuang/p/6294763.html # HMX-ServerHMX-Server分步式服务器框架,主要分为网关.登录.世界.场景 ...

  10. arcpy.mapping实战-专题图制图自动化

    arcpy.mapping实战-专题图制图自动化 by 李远祥 最初对arcpy.mapping感兴趣是因为一次大规模的专题地图调整的需要,由于某某单位利用ArcEngine编写的专题图出图系统,出现 ...