开发者学堂课程【DAO 开发实战业务分析:OR-Mapping 设计改进(主键查询改进)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/399/detail/5181
OR-Mapping 设计改进(主键查询改进)
内容介绍:
一、简述
二、具体内容
一、简述
在整个 JDBC 的开发之中对于数据的取出实际上是有一个严重的性能问题的,理论上不需要的数据不应该取出,如果要想达到这样的目的,就必须针对于整体操作进行一些规划,如果需要设置要查询的列,则这个设置过程应该交由用户处理,也就是说用户要负责生成 SQL 语句。
二、具体内容
1、在 AbstractDAO 类里面追加一个处理的方法。找到 findById,返回的一定是位型,跟上public
<
T> T
find
B
yId
S
upport(S
tring sql,String Value
,Class<
T> cls
) throws
E
xception
{},
要求能接收 sql 与value,Class 是一定要有的,否则值不能返回。
首先要改的部分在于return
super.
findByIdSupport
(sql,id,Member.
class);
。
再在上方写出注释,而在将查询结果自动转为VO类流程的过程中的关键因素为查询全部的操作也要经过这种转换。
如下:
/**
* 对数据的查询进行控制
* @param sql
要执行的根据I
D
查询的S
QL
语句
* @param value
要查询的id数据
*
@param
cls
要处理的V
O
类型
* @
return
查询到数据则将Result
S
et的内容自动转换为V
O
对象返回
* @
throws
E
xception
*/
public
<
T
,V
> T
find
B
yId
S
upport(S
tring sql,V
value,Class<
T> cls
) throws
E
xception
{
return
null
;
}
2、在子类里面需要负责好要使用的 SQL 语句。
Iterator<?> iter = ids. iterator() ;
int foot = 1 ;
while (iter.hasNext()) {
buf.append(“?,”) ;
this.valueMap.put(foot ++,iter.next()) ;
}
buf.delete(buf.length() - 1, buf.length()) ;
buf. append(“(“) ;
return buf.toString() ;
}
}
3、在 AbstractDAO 父类里面实际上对于 SQL 不再需要自动生成了,而后只需要考虑设置内容即可,而且主键的类型往往是 String 或者是 Integer(Int)。
在 FindSupport 中,在追加处理方法的部分中,并不知道主键的类型,但是可以通过 Class 资源文件找到主键的列与属性,再通过属性找到属性的类型。
而在这个地方并不能跟String而是跟泛型,即改为 public <T,V> T findByIdSupport(String sql,V value,Class<T> cls) throws Exception {,而有了 T 和 value 则不需要通过反射去寻找,而能够直接找到位型。
通过 System.
out.println(value.getClass().getSimpleName());
来进行验证是可以找到位型的。
然后将值给 FIndSupport 来执行,如下:
p
ackage
cn.
mldn.util.dao.support;
import
java.
sql.PreparedStatement ;
p
ublic class FindSupport {
public
<
V> void setPreparedStatement(PreparedStatement pstmt,V value) {
String type = value.getClass().getSimpleName() ;
if (“String”.equals(type)) {
pstmt.setString(1,value.toString()) ;
}else if (“Int”.equals(type) || “Integer”.equals(type))
pstmt.setInt(2,parseInt(value.toString())) ;
}
}
}
4、但是现在不是一个查询可以解决的问题,整个过程之中需要将 ResultSet 的数据变为 VO 数据保存,所以此处就需要一个 ResultToVO 的工具类。
知道元数据的目的是为了得到列名称,有了列名称就可以找到属性名称。而数据取出要通过对象来进行实例化控制,
如下:
p
ackage
cn.
mldn.util.dao
;
public
class
Result
S
et
T
o
VOU
til
{
private
Result
S
et
T
o
VOU
til(
) {}
/**
* 将Result
S
et中的内容进行一个转换处理
* @param pstmt
包含有元数据以及可以执行查询的处理对象
*
@param
cls
要转换的
VO
对象
* @
return
*/
public
static
<T> T
convert
S
ingle(
PreparedStatement pstmt,Class<T> cls) {
R
esult
S
et
M
eta
D
ata
rsmd
=
pstmt.
getMetaData ;
R
esult
S
et
rs = pstmt.executeQuery() ; //
发出查询命令
T
t
=
cls
.newInstance() ;
if(rs
.
next())
{
/
/
有数据
for (int x = 1; x < rsmd.getColumnCount() ; x ++) {
F
ield
field
=
cls.
getDeclaredField(rsmd.getColumnLabel
(x).
toLowerCase());
String type = field.fetType().getSimpleName() ;
if(“String”.equals(type)) {
BeanValueUtils.setValue(t,rsmd.getColumnLabel(x).toLowerCase(),rs.getString(rsmd.getColumnLabel(x)));
}
else
if(“int“.
equals(type) ||
“in
teger
“.
equals(type))
{
BeanValueUtils.setValue(t,rsmd.getColumnLabel(x).toLowerCase(),rs.getInt(rsmd.getColumnLabel(x)));
}
else
if(“
double
“.
equals(type) ||
“
Double
“.
equals(type))
{
BeanValueUtils.setValue(t,rsmd.getColumnLabel(x).toLowerCase(),rs.getDouble(rsmd.getColumnLabel(x)));
}
else
if(“
Date
“.
equals(type) ||
“in
teger
“.
equals(type))
{
BeanValueUtils.setValue(t,rsmd.getColumnLabel(x).toLowerCase(),rs.getDate(rsmd.getColumnLabel(x)));
}
return null ;
}
}
}
测试操作后,显示索引丢失,跟上F
ind
S
upport
support
=
new
F
ind
S
upport();
,再跟上
support.
setPreparedStatement(this.pstmt,value);
后再次执行,没有出错但没有值,再跟上 system.out.println(obj);,执行成功。
5、需要在 BeanValueUtils 类中追加一个根据对象使用相应的setter方法的调用操作。通过 setValue ,即 public
static
void
set
V
alue(Object
obj,String
attribute
N
ame)
{来专门设置内容,知道属性名称就可以知道参数位型。
再找到
Fieldfield
=
obj
.getClass().getDeclaredField(attributeName);,
然后就可以知道属性位型,再找到field.getype()进行完善。此外需要完善内容的设置,跟上Object value,
再找到
set
M
ethod.
invoke(obj,value);,
就可以实现setter调用操作,如下:
public
static
void
set
V
alue(Object
obj,String
attribute
N
ame)
{
try {
Field
field
=
obj
.getClass().getDeclaredField(attributeName);
Method setMethod = obj.getClass().getMethod(“set” + StringUtils.initcao(attributeName())) ;
set
M
ethod.
invoke(obj,value);
} catch (Exception e) {
e.print
S
tack
T
race() ;
}
}
6、实现方法的整合调用:
/**
* 对数据的查询进行控制
* @param sql
要执行的根据I
D
查询的S
QL
语句
* @param value
要查询的id数据
*
@param
cls
要处理的V
O
类型
* @
return
查询到数据则将Result
S
et的内容自动转换为V
O对象返回
* @
throws
E
xception
*/
public
<
T
,V
> T
find
B
yId
S
upport(S
tring sql,V
value,Class<
T> cls
) throws
E
xception
{
F
ind
S
upport
support
=
new
F
ind
S
upport();\
this.pstmt = this.conn.preparedStatement(
sql);
support.
setPreparedStatement(this.pstmt,value);
return
R
esult
S
et
T
oVOUtil.
convertSingle(this.pstmt,cls);
}
要想实现一些自动化的控制,必须依靠元数据,而且使用反射最大的亮点在于不受到具体类型的限制。