1.ORM定义
这里就不介绍关于ORM的一些官方的术语了,简单来说,对象关系映射(ORM)就是实现对象到关系数据库的映射,在平常的业务开发中,如果我们能实现这种映射,我们在完成某项数据库操作时,就不用去书写复杂的sql语句,大大便利了我们编程。
常见的ORM框架有:Hibernate、TopLink、Castor JDO、Apache OJB等
2. ORM的具体实现
实现对象与数据库的关系映射有两种方式:XML文件或者注解,我们使用注解的方式。
大致的实现逻辑:
- 给model类写上三个注解,类注解的内容为表的名字,属性注解写上属性相对的字段名,最后一个注解代表主键,写在主键对应的属性上
- 通过解析对应类的注解,我们可以得到表名,字段名,主键名,我们将这些信息封装到ClassTable类中,最终存入到ClassFactory类的Map中
- 这样我们就可以在内存中得到表名,字段名,主键名,这些都是构成SQL语句你的元素,
这样就可以根据功能,自动化的生成sql语句。
2.1 确定映射关系
如果我们需要完成数据库与对象的映射,我们就需要完成三种映射
1.对象和表的映射
2.对象成员与表中的记录的映射
3.对象中的某一个成员与表的主键的映射
要完成这三种映射,需要三个注解
- 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();
}
- 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 "";
}
- 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);
}
}