上文已经谈到对象关系库需要对操作中间产生的数据进行缓存以提升性能
我们需要对通过反射获取的属性进行缓存
我们需要对属性拼装成的SQL语句进行缓存
综上,我们可以设计出SQLClass作为Class的缓存类保存反射的结果,SQLField作为Field的缓存类保存反射的结果
对于Person类有一个
SQLClass<Person> sqlClass=new SQLClass(Person.class)
作为其缓存类,缓存类中包含Person所有数据库相关的属性值
public class SQLField{
private Field field;
private Column column;
//省略getter
//返回SQLField对应的数据库列名称
public String getName(){
//如果Column额外设置了名字,则返回设置的名字,否则返回field变量的名字
if(column.name().length()>0)return column.name();
return field.getName();
}
//遍历类所有的SQLField
public static void mapSQLField(Class clazz,SQLConsumer<SQLField> consumer){
if (!clazz.getSuperclass().equals(Object.class)) {
mapSQLField(clazz.getSuperclass(), mapper);//先访问父类的属性
}
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if (field.isAnnotationPresent(Column.class)) {
Column column = field.getAnnotation(Column.class);
mapper.accept(new SQLField<T>(field, column));
}
}
}
}
public class SQLClass<T>{
private Class<T> clazz;
private List<SQLField> fields=new LinkedList<>();//保存此类所有Field缓存
private SQLField primaryKey;
private String tableName;
private SQLClass(Class<T> clazz){this.clazz=clazz;}
public static <T> SQLClass<T> build(Clazz<T> clazz)throws SQLException{
SQLClass<T> sqlClass=new SQLClass(clazz);
sqlClass.init();
return sqlClass();
}
//初始化缓存类
private void init() throws SQLException{
//获取数据库表名
if(!clazz.isAnnotationPresent(Table.class))
throw new SQLException(clazz+"类没有配置表名");
Table table=clazz.getAnnotation(Table.class);
this.tableName=table.value();
//获取数据库对应的所有属性值字段
SQLField.mapSQLField(clazz,sqlField->{
fields.add(sqlField);
if(sqlField.getColumn().isPrimaryKey()){
primaryKey=sqlField;
}
});
if(primaryKey==null)throw new SQLException(clazz+"类没有配置主键");
}
private String selectSQL;//查询SQL语句的缓存
private Object selectLock=new Object();
//返回查询的SQL语句
public String selectSQL(){
if(selectSQL==null)
synchronized(selectLock){
if(selectSQL==null){
selectSQL=initSelectSQL();
}
}
}
return selectSQL;
}
//初始化查询的SQL语句
private String initSelectSQL(){
//将每个字段的名字拼接到一起
StringJoiner joiner=new StringJoiner(",");
for(SQLField sqlField:fields){
joiner.add(sqlField.getName());
}
StringBuilder builder=new StringBuilder();
builder.append("SELECT ")
.append(joiner.toString())
.append(" FROM ")
.append(tableName)
.append(";");
return builder.toString();
}
//上面我已经演示了如何获取查询的SQL语句,后面的增加,删除,更改的SQL语句限于篇幅已经省略
//把一行ResultSet转化成一个对象实例
public void toBean(ResultSet rs){
T t=t.newInstance();
for(SQLField sqlField:fields){
sqlField.set(t,rs.get(sqlField.getName());
}
return t;
}
}
现在我们已经知道了如何构建SQLClass作为反射结果和SQL语句的缓存,现在我们还需要一个类作为SQLClass的缓存
public class SQLCache{
//用来缓存SQLClass的容器
private ConcurrentHashMap<Class, SQLClass> map = new ConcurrentHashMap<>();
//获取clazz对应的SQLClass
public <T> SQLClass<T> getSQLClass(Class<T> clazz) throws SQLException {
SQLClass<T> sqlClass = map.get(clazz);
if (sqlClass == null) {
SQLClass<T> tempSqlClass = SQLClass.build(clazz);
map.putIfAbsent(clazz, tempSqlClass);
sqlClass = map.get(clazz);
}
return sqlClass;
}
}
既然我们已经了缓存类,我们的简单对象关系库已经实现了大半部分。
接下来我们考虑的如何使用这些缓存类实现对象关系库