【ORM】怎样自己写一个ORM框架-1

最近一直在看一些Spring JDBC 的一些东西,觉得吧手动的方式真的不太习惯,而MyBatis需要配置Mapping,虽然更加灵活了,也不简单,hibernate 基本上可以实现单表Nosql但是比较重量级。纠结了这么长时间,还是现在用的的ORM框架比较好用。

我们一般的默认都是 约定优于配置 也就是说我们的规范更加重要,比如说为什么我们的JAVA类命名规则是驼峰,接口或者实现类加上I或者Impl,这些不加没有任何问题,如果开心的话随便怎么起都可以,但是有一些是我们的标准也就是规章制度,是要严格按照遵守执行的。

PowerDesigner

可能有部分人用过这个工具,也是比较有年头的工具了,我们主要是用这个工具进行数据建模,做一个关系映射(RM),表的数据结构等与我们的一些元数据信息做匹配,既然都说是元数据了,那么存的内容是我们最基本的一些元信息,比如表的字段长度,字段类型,是否可为空,是否参与计算,是否是动态属性等等,记录着表的最基础的信息

现在该说我们的规范是什么?

  • 首先我们一定要有pojo而且与数据库存的字段是一摸一样的,这点上和hibernate类似
  • 主表和子表都是单表结构所以在生成的pojo时需要继承其顶层类SinglePojo
  • 主子表通过单独的一个AggPojo来实现主子表的关联,AggPojo里面的child和parent方法分别指向主子pojo

这个时候,entry已经出来了,实体类出来以后,我们就要想该如何设计ORM框架

使用原生JDBC 少不了以下几步

  1. 加载驱动类
  2. 获得连接
  3. 开启事务
  4. 执行sql
  5. 关闭事务和连接

我们需要做的事是屏蔽掉1、2、3、5 封装第四部,使之通过类和参数的方式实现Nosql。

DataSourceCenter

首先我们需要一个类来记录我们数据库的一些信息,这些需要我们单独有一个界面来配置,保存为一个properties文件,在启动服务的时候加载到类里面去,就能获取到对应的一些数据库的基本信息,
也就是DataSourceCenter记录着一些元信息,在这里面会加载第一次与数据库的连接,具体的实现不在本类

CrossDBConnection

这个类里边,先检查我们现在运行的数据库是什么厂商的什么版本,
支持
ORACLE 、MSSQL、DB2 、HSQL、SYBASE、INFORMIX OSCAR、POSTGRESQL、ALCEDO、GBASE等一些厂商的数据库产品,

// JDBC驱动写好方便直接调用
public final static String JDBC_ODBC = "sun.jdbc.odbc.JdbcOdbcDriver";
public final static String JDBC_DB2_NET = "COM.ibm.db2.jdbc.net.DB2Driver";
public final static String JDBC_DB2_APP = "COM.ibm.db2.jdbc.app.DB2Driver";
public final static String JDBC_ORACLE = "oracle.jdbc.driver.OracleDriver";
public final static String JDBC_SYBASE = "com.sybase.jdbc.SybDriver";
public final static String JDBC_GBASE = "com.gbase.jdbc.Driver";
public final static String JDBC_OSCAR = "com.oscar.Driver";

JdbcPersistenceManager
这个里面的初始化方法中第一次与数据库做一个连接
init
在调用时第一次与数据库做连接获取到conn逐级返回

我们在CrossDBConnection 上增加一个数据库连接工厂,封装数据库连接的构造过程,简化客户端的调用ConnectionFactory用静态方法直接获得conn

对于事务的处理

使用 UAPTransaction可以对事务进行特殊的处理操作,我们继承了Transaction接口实现了Commit,RollBack等方法

一般来说我们把一次远程调用当成一次事务,当然也可以自由配置,任何RPC框架都会有自己的一个注册中心,实际上就是xml配置,用友将配置信息注册到upm文件当中,服务器启动时会扫描注册模块中的所有upm文件,保存到ConcurrentHahsMap中去,在upm中我们有一个属性叫做TX可以取两个值.

  1. 一个是默认值CMT默认requestneeded,也就是我们说的事务传播机制中的REQUIRED:如果当前方法有事务则加入事务,没有则创建一个事务。
  2. 如果需要使用 REQUIREDS_NEW 的传播机制,也就是:新建一个事务并在这个事务中运行,如果当前存在事务就把当前事务挂起。新建的的提交与回滚一挂起事务没有联系,不会影响挂起事务的操作,需要方法名以_RequestNew结尾来实现。
  3. 另一个值为BMT,使用程序来控制事务

如果支持这么多类型的数据库,而每个数据库支持的sql都有不同,那么,我们需要屏蔽掉这些差异
我们在预编译的时候就要消除这些差异

SQLParameter

/**
 * 加入一个Null参数类型
 * 
 * @param type
 *            参数的类型参考java.sql.Types
 */
public void addNullParam(int type) {
    paramList.add(SQLTypeFactory.getNullType(type));
}

/**
 * 加入一个Blob参数类型
 * 
 * @param blob
 *            对象参数
 */
public void addBlobParam(Object blob) {
    if (blob == null)
        addNullParam(Types.BLOB);
    else
        paramList.add(SQLTypeFactory.getBlobType(blob));
}

/**
 * 加入一个Blob参数类型
 * 
 * @param blob
 *            字节数组参数
 */
public void addBlobParam(byte[] bytes) {
    if (bytes == null)
        addNullParam(Types.BLOB);
    else
        paramList.add(SQLTypeFactory.getBlobType(bytes));
}

/**
 * 加入一个Blob参数类型
 * 
 * @param stream
 *            字节流
 * @param length
 *            长度
 */
public void addBlobParam(InputStream stream, int length) {
    if (stream == null)
        addNullParam(Types.BLOB);
    else
        paramList.add(SQLTypeFactory.getBlobType(stream, length));
}

/**
 * 加入一个Clob参数类型
 * 
 * @param clob
 */
public void addClobParam(String clob) {
    if (clob == null)
        addNullParam(Types.CLOB);
    else
        paramList.add(SQLTypeFactory.getClobType(clob));
}

/**
 * 加入一个Clob参数类型
 * 
 * @param reader
 *            字符流
 * @param length
 *            长度
 */
public void addClobParam(Reader reader, int length) {
    if (reader == null)
        addNullParam(Types.CLOB);
    else
        paramList.add(SQLTypeFactory.getClobType(reader, length));
}

/**
 * 加入一个任意对象参数,注意该参数不能为空
 * 
 * @param param
 *            对象参数
 */
public void addParam(Object param) {
    if (param == null)
        throw new IllegalArgumentException("SQL Parameter object cannot be null, which can be replaced by NullType Object!!");
    paramList.add(param);

} 

在连接数据库的时候,连接数量太多,也就是并发处理的数据比较多的时候对数据库和主机的性能都是一个考验,这个时候就需要用到我们平时所说的连接池,不能无限制的增加连接,会导致机器运行很不稳定。所以连接池的大小就成为了一个重点,那么是我们设置连接池的参数越大,效率就会越高吗?当然不是,一般情况下,我们设置的 连接数 = ((核心数 * 2) + 有效磁盘数),所以我们在初始化DBConnectionPool的时候初始conMax值设置为20,conMin设置为2(当然1就没有线程池的意义了)

这个时候,我们对于数据库的连接,事务,屏蔽差异透明化已经基本完成。

接下来就是讲一下我们获取到了连接,如何NoSql方式执行

平时使用最多的就是CURD,实际工作中R用的更多,而且处理也更加繁琐,那么我们只深入解析一下retrieve。
既然我们要实现通过类名和参数就能执行查询,我们必定要封装一个查询的wrapper,我们只讲通过聚合pojo实现查询,SinglePojo在聚合pojo里面有体现,不单独讲。

页面篇幅限制下一篇继续来讲解。

猜你喜欢

转载自blog.csdn.net/qq_34370153/article/details/80929722