Spring数据访问之自定义ORM框架
1.目标
理解什么是ORM框架,并简单自定义一个ORM。
2.定义
什么是ORM框架?
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。
我们接触过的各大框架都实现了ORM,我们拿3个框架做个比较:
Hibernate 全自动挡的汽车 新手全自动,门槛低,性能低
MyBatis 手自一体的汽车(半自动) 适中,轻量级
SpringJdbc 全手动挡的汽车 高手全手动,门槛高,性能高
3.源码实现
3.1 mysql表
DROP TABLE IF EXISTS `t_member`;
CREATE TABLE `t_member` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
`age` int(11) NULL DEFAULT NULL,
`addr` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_unicode_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
3.2 定义实体类
@Entity
@Table(name="t_member")
@Data
public class Member implements Serializable {
@Id private Long id;
private String name;
private String addr;
private Integer age;
@Override
public String toString() {
return "Member{" +
"id=" + id +
", name='" + name + '\'' +
", addr='" + addr + '\'' +
", age=" + age +
'}';
}
}
3.3 简单实现ORM
public class JdbcTest {
public static void main(String[] args) {
//这就是OO编程,ORM
Member condition = new Member();
condition.setName("TomCat");
condition.setAge(2);
//"select * from t_member where name = 'Tom' and age = 19"
List<?> result = select(condition);
System.out.println(Arrays.toString(result.toArray()));
}
public static List<?> select(Object condition) {
List<Object> result = new ArrayList<>();
Class<?> entityClass = condition.getClass();
Connection con = null; //连接对象
PreparedStatement pstm = null; //语句集
ResultSet rs = null; //结果集
try {
//1、加载驱动类,千万不要忘记了
Class.forName("com.mysql.jdbc.Driver");
//2、建立连接
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo","root","123456");
Map<String,String> getFieldNameByColumn = new HashMap<String,String>();
Map<String,String> getColumnByFieldName = new HashMap<String,String>();
Field[] fields = entityClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String fieldName = field.getName();
if(field.isAnnotationPresent(Column.class)){
Column column = field.getAnnotation(Column.class);
String columnName = column.name();
getFieldNameByColumn.put(columnName,fieldName);
getColumnByFieldName.put(fieldName,columnName);
}else{
//默认属性名就是列名
getFieldNameByColumn.put(fieldName,fieldName);
getColumnByFieldName.put(fieldName,fieldName);
}
}
StringBuffer sql = new StringBuffer();
//3、创建语句集
Table table = entityClass.getAnnotation(Table.class);
sql.append("select * from " + table.name() + " where 1=1 ");
for (Field field : fields) {
Object value = field.get(condition);
if(null != value){
if(String.class == field.getType()){
sql.append(" and " + getColumnByFieldName.get(field.getName()) + " = '" + value + "'");
}else{
sql.append(" and " + getColumnByFieldName.get(field.getName()) + " = " + value);
}
//其他依次类推
}
}
pstm = con.prepareStatement(sql.toString());
//4、执行,获取结果集
rs = pstm.executeQuery();
int columnCounts = rs.getMetaData().getColumnCount();
while (rs.next()){
Object instance = entityClass.newInstance();
for (int i = 1; i <= columnCounts; i++) {
String columnName = rs.getMetaData().getColumnName(i);
Field field = entityClass.getDeclaredField(getFieldNameByColumn.get(columnName));
field.setAccessible(true);
field.set(instance,rs.getObject(columnName));
}
result.add(instance);
}
}catch (Exception e){
e.printStackTrace();
}
//6、关闭结果集、关闭语句集、关闭连接
finally {
try {
rs.close();
pstm.close();
con.close();
}catch (Exception e){
e.printStackTrace();
}
}
return result;
}
}
4. 总结
通过这些代码可以看出,Spring提供了一个未完成的模板Template,我们可以根据业务需要,使用这个Template来实现任何自定义的对象映射。同时,这个思想也同样适用于其他数据库如:Redis、MongoDB、HBase、ElasticSearch等。