最后一点需要注意的是Schema这个单词,它在SQL环境下的含义与其在数据建模领域中的含义是完全不同的。在SQL环境下,Schema是一组相关的数据库对象的集合,Schema的名字为该组对象定义了一个命名空间,而在数据建模领域,Schema(模式)表示的是用形式语言描述的数据库的结构;简单来说,可以这样理解,数据建模所讲的Schema<也就是元数据>保存在SQL环境下相应Catalog中一个Schema<名叫DEFINITION_SCHEMA>下的表中,同时可以通过查询该Catalog中的另一个Schema<名叫INFORMATION_SCHEMA>下的视图而获取,具体细节不再赘述。
按照包容关系,从大到小的顺序为database、table、column。因而在介绍的时候我们将从最小的开始,也就是从Column开始,而后是Table,最后是database的顺序进行。
//列名
private String name;
* 类型,具体的数字代表的类型可以参考java.sql.Types中一系列的静态常量
* 如 public final static int BIT = -7;
* public final static int INTEGER = 4;
* public final static int DOUBLE = 8;
private int type;
这个类中的函数都是一些常用的基本函数,没有什么特殊的地方,也相当的简单明了,有兴趣的读者可以直接看源代码。个人觉得equals函数的实现挺有意思,在此做下说明,与大家分享:
* 有必要提下 “==”和equals的区别和联系
* “==” 比较的是两个变量在内存中的是否指向同一个地方,即内存地址是否相同
* “equals” 比较的是两个对象的内容是不是相同
* 因而 “==”的true的两个变量“equals”一定为true,但反之则不然.有兴趣的同学可以执行下下面几行代码:
* String a = new String("22");
String b = new String("22");
String csString = a;
System.out.println(a==b?"====":"!===");
System.out.println(a.equals(b)?"equals":"!equals");
System.out.println(a==csString?"====":"!===");
public
boolean
equals(Object o) {
//
比较这两个变量的内存地址,如果指向同一块内存,则必然相等
if
(
this
== o)
return
true
;
//
如果两个对象的类型都不一样,内容肯定也不一样,要不然也无需定义两个不同的类了
if
(o ==
null
|| getClass() != o.getClass())
return
false
;
final
Column column =
(Column) o;
//
比较类型,如果类型不同则必然是两个不同的列
if
(type != column.type)
return
false
;
//
请看下面这条语句,写的相当巧妙,一行语句针对两种请看做了处理,比if else要好
//
如果这个变量的name不为空,则判断这两个变量的类型名称是不是相同(用equals,而不是==);如果为空,则判断另一个变量的name是不是为空
if
(name !=
null
? !name.equals(column.name) : column.name !=
null
)
return
false
;
//
当然,也可以先比较名称然后再比较名称,
return
true
;
1 自反性 :对任意引用值X,x.equals(x)的返回值一定为true.
2 对称性: 对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;
3 传递性:如果x.equals(y)=true, y.equals(z)=true,则x.equals(z)=true
4 一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变
5 非空性:任何非空的引用值X,x.equals(null)的返回值一定为false
2.Table
接下来我们来看Table这个类,数据库中的表通常有这么几个属性:表名、一些列、主键、索引、表的注释、表的引擎类型、表的编码格式等。在mybatis中Table类的属性有如下几个:
private final String name;//表名
private String catalog;//表的catalog,具体哪些数据库支持该属性请见第一节
private String schema;//表的schema,对于mysql而言,就是库名
//包含的列,key的列的名称,value是列的具体信息
private final Map<String, Column> columns = new HashMap<String, Column>();
//主键,看这个定义不支持联合主键
private Column primaryKey;
这个类中的函数没有什么特殊之处,都是常见见的,在此不再进行说明。
3.Database
接下来我们来看Database这个类,在mybatis中Database类的属性有如下几个:
private final String catalog;//库的catalog,具体哪些数据库支持该属性请见第一节
private final String schema;//可以看做库名
//该数据库包含的表
private final Map<String, Table> tables = new HashMap<String, Table>();
这个类中的函数没有什么特殊之处,都是常见见的,在此不再进行说明。
三、DatabaseFactory
前面介绍了mybatis用来描述列、表、数据库的三个类,那如何获得一个数据库中的这些信息呢?这就要用到这一小节中的DatabaseFactory类了。这个类只有两个函数,一个是私有的不带参数的构造函数,另一个是返回Database对象的一个静态函数。对于私有的不带参数的构造函数我们无需进行介绍,它的作用就是不让其他的类去实例化该类,我们着重了解下这个静态函数。建议读者亲自创建一个数据库、表去执行下这个函数看看返回的结果,这样会对这个函数有更深刻的理解,在这个过程中彻底的理解他人的思想,转化为自己的能力。 在这里贴出newDatabase函数的主要内容:
// 先初始化一个database对象
Database database = new Database(catalogFilter, schemaFilter);
ResultSet rs = null;
try {
// 获取数据库连接的元数据
// ResultSet类也有getMetaData()函数,但返回的结果为ResultSetMetaData
DatabaseMetaData dbmd = conn.getMetaData();
try {
// 获取这个链接对应的数据库的列信息
* getColumns前两个参数说明,来自于该类的源代码
* @param catalog
* a catalog name; must match the catalog name as it
* is stored in the database; "" retrieves those
* without a catalog; <code>null</code> means that
* the catalog name should not be used to narrow the
* search
* 如果参数值是空字符串,返回没有catalog的数据库;如果参数为null,在查询时不用这个catalog做为查询条件
* ;如果为其他值,则按照输入值进行查询。 schema的查询条件类似
* @param schemaPattern
* a schema name pattern; must match the schema name
* as it is stored in the database; "" retrieves
* those without a schema; <code>null</code> means
* that the schema name should not be used to narrow
* the search
rs = dbmd.getColumns(catalogFilter, schemaFilter, null, null);
while (rs.next()) {
//获取数据
String catalogName = rs.getString("TABLE_CAT");
String schemaName = rs.getString("TABLE_SCHEM");
String tableName = rs.getString("TABLE_NAME");
String columnName = rs.getString("COLUMN_NAME");
int dataType = Integer.parseInt(rs.getString("DATA_TYPE"));
//从database根据表名获取table对象,如果没有这个表,则初始化
Table table = database.getTable(tableName);
if (table == null) {
table = new Table(tableName);
table.setCatalog(catalogName);
table.setSchema(schemaName);
database.addTable(table);
//将列添加到表对象中
table.addColumn(new Column(columnName, dataType));
数据库服务器:mysql
数据库名:test
CREATE TABLE `mybatis` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) DEFAULT '',
`password` varchar(32) DEFAULT '',
`sex` tinyint(1) DEFAULT '1' COMMENT '1表示男,2表示女;默认值为1',
`email` varchar(30) DEFAULT '',
`role` tinyint(4) DEFAULT '0' COMMENT '角色,默认值为0,表示还没有赋予角色',
`status` tinyint(1) DEFAULT '1' COMMENT '1表示有效,0表示无效;默认值为1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
执行的关键代码:
String catalogName = resultSet.getString("TABLE_CAT");
String schemaName = resultSet.getString("TABLE_SCHEM");
String tableName = resultSet.getString("TABLE_NAME");
String columnName = resultSet.getString("COLUMN_NAME");
int dataType = Integer.parseInt(resultSet.getString("DATA_TYPE"));
String commentString = resultSet.getString("REMARKS");
if (logger.isDebugEnabled()) {
logger.debug(null);
logger.debug("catalogName:" + catalogName
+ "; schemaName:" + schemaName + "; tableName:"
+ tableName + "; columnName:" + columnName
+ "; comment:" + commentString);
为方便查看,去掉了log4j打印的标准前缀执行结果:
catalogName:test; schemaName:null; tableName:mybatis; columnName:id; comment:
catalogName:test; schemaName:null; tableName:mybatis; columnName:username; comment:
catalogName:test; schemaName:null; tableName:mybatis; columnName:password; comment:
catalogName:test; schemaName:null; tableName:mybatis; columnName:sex; comment:1表示男,2表示女;默认值为1
catalogName:test; schemaName:null; tableName:mybatis; columnName:email; comment:
catalogName:test; schemaName:null; tableName:mybatis; columnName:role; comment:角色,默认值为0,表示还没有赋予角色
catalogName:test; schemaName:null; tableName:mybatis; columnName:status; comment:1表示有效,0表示无效;默认值为1
请注意:输出结果中的数据 catalogName为test,而 schemaName为null。和第一小节中提到的内容不符合,也和mysql官网中的说明不符合(http://dev.mysql.com/doc/refman/5.1/zh/information-schema.html)。
有哪位高手了解原因还请告知!