自己手动实现对象关系映射(Object Relational Mapping,简称ORM)

1.ORM定义

这里就不介绍关于ORM的一些官方的术语了,简单来说,对象关系映射(ORM)就是实现对象到关系数据库的映射,在平常的业务开发中,如果我们能实现这种映射,我们在完成某项数据库操作时,就不用去书写复杂的sql语句,大大便利了我们编程。
常见的ORM框架有:Hibernate、TopLink、Castor JDO、Apache OJB等

2. ORM的具体实现

实现对象与数据库的关系映射有两种方式:XML文件或者注解,我们使用注解的方式。
大致的实现逻辑:

  1. 给model类写上三个注解,类注解的内容为表的名字,属性注解写上属性相对的字段名,最后一个注解代表主键,写在主键对应的属性上
  2. 通过解析对应类的注解,我们可以得到表名,字段名,主键名,我们将这些信息封装到ClassTable类中,最终存入到ClassFactory类的Map中
  3. 这样我们就可以在内存中得到表名,字段名,主键名,这些都是构成SQL语句你的元素,
    这样就可以根据功能,自动化的生成sql语句。

2.1 确定映射关系

如果我们需要完成数据库与对象的映射,我们就需要完成三种映射
1.对象和表的映射
2.对象成员与表中的记录的映射
3.对象中的某一个成员与表的主键的映射

要完成这三种映射,需要三个注解

  1. ClassAnnotation注解完成类与表的映射关系
package com.mec.Annotation;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(TYPE)
public @interface ClassAnnotation {
	String table();
}

  1. PropertyAnnotation注解完成类成员与数据库表属性名的映射关系
package com.mec.Annotation;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(FIELD)
public @interface PropertyAnnotation {
	String column()  default "";
}

  1. Id注解指定类中的哪一个成员对应表中的主键。
package com.mec.Annotation;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(FIELD)
public @interface Id {
}

使用完注解大致是这个样子
在这里插入图片描述

2.2 完成注解的解析与信息的存储

Property类,用来存储表中的属性名,和该属性名对应的成员。

package com.mec.DataBase;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Property {
	String column;//数据库属性名
	Field name;//类的成员
	
	
	public String getColumn() {
		return column;
	}
	
	public void setColumn(String column) {
		this.column = column;
	}
	
	public Field getName() {
		return name;
	}
	
	public void setName(Field name) {
		this.name = name;
	}
	//resultSet是执行完sql语句得到的结果集,object是被写了注解的对象
	public void SetField(ResultSet resultSet, Object object) {
		try {//从结果集中通过属性名得到对应属性名的值
			Object value = resultSet.getObject(column);
			//将这个值赋值给这个成员
			name.setAccessible(true);
			name.set(object, value);
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		
	}
}

ClassTable类

package com.mec.DataBase;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;


public class ClassTable {
	
	public ClassTable() {
		propertyList = new ArrayList<Property>();
	}
	//表对应的类
	private Class<?> klass;
	//类对应的表名
	private String table;
	//不论是类还是表,都有多个属性或者成员
	private List<Property> propertyList;
	//主键的成员属性映射关系
	private Property id;
	
	
	public Class<?> getKlass() {
		return klass;
	}
	public Property getId() {
		return id;
	}
	public void setId(Property id) {
		this.id = id;
	}
	public void setKlass(Class<?> klass) {
		this.klass = klass;
	
	}
	public String getTable() {
		return table;
	}
	public void setTable(String table) {
		this.table = table;
	}
	public List<Property> getPropertyList() {
		return propertyList;
	}
	public void setPropertyList(List<Property> propertyList) {
		this.propertyList = propertyList;
	}
	
	//以SQL语句的形式得到所有的字段名,用于自动生成sql语句
	public String getColumn() {
		StringBuffer columnString = new StringBuffer();
		boolean isFirst = true;
		for (Property pro : propertyList) {
			columnString.append(isFirst ? " " : ",")
			.append(table).append('.')
			.append(pro.getColumn());
			
			isFirst = false;
		}
		
		return columnString.toString();
	}
	
	//给类的成员赋上从数据库中读出来的值
	public void setFields (ResultSet resultSet, Object object) {
		for (Property pro : propertyList) {
			pro.SetField(resultSet, object);
		}
	}
	
}

ClassFactory类,用于存储ClassTable对象,以及注解的解析

package com.mec.DataBase;


import java.lang.reflect.Field;
import java.util.HashMap;

import java.util.Map;

import org.w3c.dom.Element;

import com.mec.Annotation.ClassAnnotation;
import com.mec.Annotation.Id;
import com.mec.Annotation.PropertyAnnotation;
import com.mec.util.XMLParser;

public class ClassFactory {
	//存储ClassTable对象,键为类的名字
	private static final Map<String, ClassTable> map;
	static {
		//单例模式初始话
		map = new HashMap<String, ClassTable>(); 
	}
	
	public ClassFactory() {
	}
	public static void makeClassTableForAnnotation(Class<?> klass) {
		boolean isVisit = false;
		ClassTable classTable = new ClassTable();
		if (!klass.isAnnotationPresent(ClassAnnotation.class)) {
			return;
		}
		//解析注解
		ClassAnnotation ca = klass.getAnnotation(ClassAnnotation.class);
		//读出注解储存的值
		classTable.setTable(ca.table());
		classTable.setKlass(klass);
		
		
		Field[] fields = klass.getDeclaredFields();
		
		for (Field field : fields) {
			//解析成员注解得到对应的表中的属性名
			if (!field.isAnnotationPresent(PropertyAnnotation.class)) {
				continue;
			}
			Property pro = new Property();
			PropertyAnnotation pa = field.getAnnotation(PropertyAnnotation.class);
			pro.setName(field);
			
			String column = pa.column();
			if (column.length() == 0 ) {
				pro.setColumn(field.getName());
			}else {
				pro.setColumn(column);
			}
			classTable.getPropertyList().add(pro);
			if (!isVisit && field.isAnnotationPresent(Id.class)) {
				classTable.setId(pro);
				isVisit = true;
			}
		}
		map.put(klass.getName(), classTable);
	}
	
	public static ClassTable getClassTable(String klass) {
		return map.get(klass);
	}
	
	public static ClassTable getClassTable(Class<?> klass) {
		return map.get(klass.getName());
	}
}

DataBase类

该类是自动生成SQL语句并执行的过程,并没有详细注释

package com.mec.DataBase;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import java.util.List;

import com.mec.Annotation.Id;
import com.mec.util.PropertiesParser;



public class DataBase {

	private static  volatile Connection connection;
	
	public DataBase() { 

	}
	//解析Properti文件,得到连接数据库所需的信息
	public static void loadDatabaseConfig(String path) {
		PropertiesParser.load(path);
	}
	//连接数据库
	public  Connection getConnection() {
		if (connection == null) {
			synchronized (DataBase.class) {
		
				if (connection == null) {
					
					try {
						//连接数据库得到Connection
						Class.forName(PropertiesParser.getMessage("driver"));
						connection = DriverManager.getConnection(
								PropertiesParser.getMessage("url"), 
								PropertiesParser.getMessage("user"), 
								PropertiesParser.getMessage("password"));
					} catch (ClassNotFoundException e) {
						e.printStackTrace();
					} catch (SQLException e) {
					}
				}
			}
		}
		return connection;
	}
	//执行SQL语句,一般INSERT、UPDATE、DELETE使用此方法,返回值代表更新的记录数
	public int executeUpdate(String SQLString) {
		Connection connection = getConnection();
		try {
			PreparedStatement state = connection.prepareStatement(SQLString);
			return state.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return -1;
	}
	
	//执行sql语句,一般从数据库中读取记录时,使用此方法
	public ResultSet executeQuery(String SQLString) {
		ResultSet rs = null;
		Connection connection = getConnection();
		try {
			PreparedStatement state = connection.prepareStatement(SQLString);
			return state.executeQuery();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return rs;
	}
	
	@SuppressWarnings("unchecked")
	public  <T> List<T> list(Class<?> klass) {
		//得到存有表名、字段明,主键名的ClassTable类对象
		ClassTable ct = ClassFactory.getClassTable(klass);
		if (ct == null) {
			ClassFactory.makeClassTableForAnnotation(klass);
			ct = ClassFactory.getClassTable(klass);
			if (ct == null) {
				return null;
			}		
		}
		String SQLString = "SELECT" + ct.getColumn() + " FROM " + ct.getTable();
		connection = getConnection();
		
		List<T> result = new ArrayList<T>();
		ResultSet rs = executeQuery(SQLString);
		try {
			while (rs.next()) {
				try {
					Object object = klass.newInstance();
					ct.setFields(rs, object);
					result.add((T) object);
				} catch (Exception e) {
					e.printStackTrace();
				}
				
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return result;
		
	}
	
	public  <T> int save(T one) {
		Class<?> klass = one.getClass();
		boolean isfirst = true;
		connection = getConnection();
		
		ClassTable ct = ClassFactory.getClassTable(klass.getName());
		if (ct == null) {
			ClassFactory.makeClassTableForAnnotation(klass);
			ct = ClassFactory.getClassTable(klass.getName());
			if (ct == null) {
				return 0;
			}
		}
		
		Field[] fields = klass.getDeclaredFields();
		StringBuffer sb = new StringBuffer();
		
		for (int i = 0 ; i < ct.getPropertyList().size() ; i++) {
			sb.append(isfirst ? "" : ",").append("?");
			isfirst = false;
		}
		try {
			String sqlString ="INSERT INTO " + ct.getTable() + "(" + ct.getColumn() +")" + "VALUES" 
					+ "("  + sb +")";
			PreparedStatement state = connection.prepareStatement(sqlString);
			
			int i = 1;
			for (Field field : fields) {
				field.setAccessible(true);
				Object object = field.get((Object)one);
				state.setObject(i++, object);
			}
//			System.out.println(sqlString);
			return state.executeUpdate();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return 0;
	}
	
	public  <T> int modify(T one) {
		Class<?> klass = one.getClass();
		connection = getConnection();
		boolean isFirst = true;
		ClassTable ct = ClassFactory.getClassTable(klass.getName());
		if (ct == null) {
			ClassFactory.makeClassTableForAnnotation(klass);
			ct = ClassFactory.getClassTable(klass.getName());
			if (ct == null) {
				return 0;
			}
		}
		String key = ct.getId().getColumn();

		Field[] fields = klass.getDeclaredFields();
		
		StringBuffer sb = new StringBuffer();
		for (int i = 0 ; i < ct.getPropertyList().size() ; i++) {
			if (ct.getPropertyList().get(i).getColumn().equals(ct.getId().getColumn())) {
				continue;
			}
			sb.append(isFirst ? "" : ",").append(ct.getTable()).append(".");
			sb.append(ct.getPropertyList().get(i).getColumn()).append("=").append("?");
			
			isFirst = false;
		}
		 
		String SQLString = "UPDATE " + ct.getTable() + " SET " 
				+ sb + " WHERE " +ct.getTable()  + "."+ key + "= ?";
		try {
			PreparedStatement state = connection.prepareStatement(SQLString);
			int i = 1;
			for (Field field : fields) {
				field.setAccessible(true);
				if(field.isAnnotationPresent(Id.class)) {
					Object object = field.get((Object)one);
					state.setObject(fields.length, object);
					continue;
				}
				if (i == fields.length) {
					break;
				}
				state.setObject(i++, field.get(one));
			}
			return state.executeUpdate();
			
		} catch (SQLException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

		return 0;
	}
	
	public <T> int remove(T one) {
		return modify(one);
		
	}
}

                                                                                                      
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值