JAVA & 数据库编程 & ORM工具(上)

  • 1、从普通数据库连接到ORM的遐想
  • 2、配置文件
  • 3、完成类与表的映射关系

1、从普通数据库连接到ORM的遐想

如何通过jdbc让java语言和数据“联通”起来,想必是不难的。

try {
			//1
			Class.forName("com.mysql.jdbc.Driver");
			
			Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/school?"
					+ "useSSL=false", "root", "个人密码(例如123123)");
			//2
			String sqlStr = "SELECT id, name, age FROM student";
			
			PreparedStatement statement = connection.prepareStatement(sqlStr);
			ResultSet rSet = statement.executeQuery();
			//3
			while(rSet.next()) {
				String stuID = rSet.getString("id");
				String stuName = rSet.getString("name");
				String stuAge = rSet.getString("age");
				System.out.println(stuID +" "+ stuName +" " + stuAge);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}

不难看出,以上程序有三大步骤。

  1. 链接数据库
  2. 构造并执行失去了语句
  3. 处理从数据库中得到的结果

对于每次对数据库的获取而言,步骤二和三是不可缺少的,但是对于链接数据库这一操作,是可以不用每使用一次就必须重新建立连接的。

当然,如果只是发现这一点,是不会想到ORM的。那么仔细研究数据表的模式和我们对数据库表的操作。

1、数据库是由:表、记录组成;
	SELECT查找的是由多条记录组成的“表”;
	INSERT INTO 插入的是一条相对完整的记录;
	UPDATE 是对一条,或多条复合要求的记录进行修改;
	DELETE 删除的是复合条件的记录……
2、Java的面向对象编程思想:
	类;
	对象。
将上述两种不同的操作,按照数据对等性,可以这样看:
表 <=> 类
	表是由多个字段描述而成的;
	类是由多个成员描述而成的;
记录 <=> 对象
	记录是那些字段的某一次取值的集合;
	对象是那些成员的某一次取值的集合。

在研究我们对于数据的增删改查

这些操作的统一SQL语句可以描述为:
查找指定的一条记录:
	SELECT 字段表 
		FROM 表名称 
		WHERE 关键字段=value;
查找所有记录:
	SELECT 字段表 
		FROM 表名称;
插入一条记录:
	INSERT INTO 表名称
		(字段表)
		VALUES (字段值表);
		……
上述SQL语句的创建,可不可以“自动化”?如果能自动化,那么,这些
SQL语句的执行更容易自动化……
上述想法能得以实现的关键不确定点是:
	字段表;
	字段名称;
	字段的值;
	从结果集中取得的记录存储方式……
如果上述问题能够得以解决,那么,有关数据库表访问,完全可以
自动化.

最终引出我们的ORM:Object Relation Mapping

Object就是Java的对象;

Relation就是关系型数据库;

Mapping就是“映射关系”。

同时,让我们看看最后完成工具的时候,使用数据库如何轻松。

java text文档做数据库_字段

其中实现的PreparedStatement,一定程度上防止了sql注入

2、配置文件

第一个配置文件,是从个人连接数据库的必要数据中提取出来的。

java text文档做数据库_java_02

固定的驱动类名,固定的个人数据库位置(自定义),用户名(使用者自行配置),密码(使用者自行配置)。

java text文档做数据库_java_03

property文件。

第二个配置文件,也是实现ORM的基础。就是表与类之间的关系映射。

举个例子:

java text文档做数据库_字段_04


上述是一张学生信息的表(虽然数据很少)。表名是 student ,位于school数据库下。表有三个属性,分别是id, name, age。其中id为主键。

那么用一个类来如何描述呢?

java text文档做数据库_java text文档做数据库_05


我们建立一个模板类。就叫做学生信息。

public class StudentInfo {
	private String stuId;
	private String stuName;
	private String stuAge;
	
	public StudentInfo() {
	}

	public String getStuId() {
		return stuId;
	}

	public void setStuId(String stuId) {
		this.stuId = stuId;
	}
	//省略些,get,set方法

	@Override
	public String toString() {
		return "StudentInfo [stuId=" + stuId + ", stuName=" + stuName + ", stuAge=" + stuAge + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((stuId == null) ? 0 : stuId.hashCode());
		return result;
	}
	//stuId作为两个实例是否不同的筛选因子。对于表中的主键。
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		StudentInfo other = (StudentInfo) obj;
		if (stuId == null) {
			if (other.stuId != null)
				return false;
		} else if (!stuId.equals(other.stuId))
			return false;
		return true;
	}
}

看完表,再看完类,是否找到了映射关系?xml文件配置自然来。

<?xml version="1.0" encoding="UTF-8"?>
<mappings>
	<mapping class = "com.mec.about_orm.model.StudentInfo" table = "student">//类和表一对一
		<field name = "stuId" cloumn = "id"></field>//cloumn 列,属性,对应着类的成员名
		<field name = "stuName" cloumn = "name"></field>
		<field name = "stuAge" cloumn = "age"></field>
		<key name = "id"></key>
	</mapping>
</mappings>

3、完成类与表的映射关系

此时我们在仔细看看我们拥有什么

  • 一张xml文件
  • 一个java存储数据的模板类
  • 一个数据库中一张完整的表
    那么关键,自然是在xml文件上。
    我们需要做的工作就是,扫描xml文件形成,将一个表的映射类给完整描述出来。
    先看类成员与表的属性对应

    定义一个类 FieldCloumnDefinition:
public class FieldCloumnDefinition {
	private Field field;//成员
	private String cloumn;
	
	public FieldCloumnDefinition() {
	}
	//成员的get, set方法略
	@Override
	public String toString() {
		return field.getName() +"<=>" + cloumn;
	}
}

接着再看类与表的映射

java text文档做数据库_java_06


定义一个表和类映射关系的类:

java text文档做数据库_java text文档做数据库_07

元数据,实例都是为反射使用做准备。

接下来,开始扫描xml文件。(如果不清楚我扫描xml文件的方式,可以看这篇文章JAVA & 自建工具类 & xml文件解析工具)第一步:扫描表和类的映射关系

java text文档做数据库_数据库_08

扫描成功后获得表名,与类的具体地址。这时可以将类地址作为键值,将映射关系类作为值。形成映射池。其中给模板类的元数据复制的是setkClass方法,如下:

void setkClass(String className) {
		try {
			this.modelClass = Class.forName(className);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

给表名赋值就不说了。至此,映射关系类,成员已有二,差三。
第二步:扫描内部的成员和列映射
这里其实有两个标签扫描

new XMLParse() {
					
					@Override
					public boolean dealElement(Element element, int index) {
						String fieldName = element.getAttribute("name");
						String cloumnName = element.getAttribute("cloumn");
						ctd.setTrueCloumnName(fieldName, cloumnName);
						return true;
					}
				}.parseElement(element, "field");

第一个是对“field”标签扫描。

void setTrueCloumnName(String fieldName, String cloumnName) {

		Field[] fields = this.modelClass.getDeclaredFields();//利用反射获得所有成员
		if (fields.length <= 0) {
			return;
		}
		for (Field field : fields) {
			if (fieldName.equals(field.getName())) {//匹配成员名,将映射的成员与列类完成
				FieldCloumnDefinition fcd = new FieldCloumnDefinition();
				fcd.setCloumn(cloumnName);
				fcd.setField(field);
				this.fDefinitions.add(fcd);
			}
		}
	}

至此,又多了个成员完成,且获得了完整的FieldCloumnDefinition类。

new XMLParse() {
					
					@Override
					public boolean dealElement(Element element, int index) {
						String keyName = element.getAttribute("name");
						
						ctd.setKeyCloumn(keyName);
						return false;
					}
				}.parseElement(element, "key");

第二个是对“key”扫描

void setKeyCloumn(String keyName) {
		if (this.fDefinitions.size() == 0) {
			return;
		}
		for (FieldCloumnDefinition fd : this.fDefinitions) {
			if(keyName.equals(fd.getCloumn())) {//主键名和已形成的成员列映射类的列名相同
				this.primaryKey = fd;
			}
		}
	}

到此,除了object成员,其他成员都已经有了。而object只有get,set方法。

那么,前三个类都已经完成了。分别是类与表的映射,成员与列名映射,扫描xml文件形成映射池

java text文档做数据库_java_09


只剩下最后的ORM类。

点击链接,继续ORM构造吧。