前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第34次文章:SORM框架(四)

第34次文章:SORM框架(四)

作者头像
鹏-程-万-里
发布2019-09-27 17:25:46
6320
发布2019-09-27 17:25:46
举报

本周我们在上周SORMv1.0框架的基础上对其进行升级,加入了一些设计模式,连接池等改造,大大的提高了整个框架运行的效率,得到现在的SORMv1.8版本。

SORMv1.8的完全版本的获取链接为:

链接:https://pan.baidu.com/s/1r9aCf3IUg4uH_Lj9OZIO6g 提取码:a4r8

与此同时,我们结束了第一阶段的java学习,开始进入数据库的学习阶段。


一、对SORM进行升级改造

1.对query进行简化操作

我们在编写SORMv1.0时,构建了一个MySqlQuery类,实现了Query接口。但是经过分析之后,MySqlQuery类中的每个方法的实现并不仅限于MySql数据库的操作,对于其他数据库也是可以使用这些方法进行操作的。所以我们将Query接口改变为一个抽象类,将之前所有MySqlQuery类中实现的方法全部搬移到Query抽象类中直接进行实现。同时,由于每种不同的数据库会具有不同的分页查询方法,所以我们在Query类中,增加一个分页查询抽象方法。提供给每个不同的数据库方法进行单独实现。

代码语言:javascript
复制
  /**
   * 分页查询
   * @param pageNum 第几页数据
   * @param size 每页显示多少记录
   * @return
   */
  public abstract Object queryPagenate(int pageNum,int size);

由于当前的SORM数据库框架并没有涉及到分页部分,所以我们现在仅仅是为以后预留出此接口,并不进行实现。

2.使用模板方法简化Query

当我们分析一下Query类中的queryRows和queryValue方法时,我们会发现两者的前半部分都是相同的,均为先获取与数据库的连接,然后传入sql语句,给sql语句设置参数,不同的地方在于两者的查询方式。所以我们使用模板方法模式,新建一个模板方法excueteQueryTemplate,将相同的部分一起进行实现,不同的部分,我们使用回调的方式,在各自的方法中进行实现。具体的实现如下:

代码语言:javascript
复制
  /**
   * 采用模板方法模式将JDBC操作封装成模板,便于重用
   * @param sql sql语句
   * @param params sql的参数
   * @param clazz 记录要封装到的java类
   * @param back CallBack的实现类,实现回调
   * @return
   */
  public Object excueteQueryTemplate(String sql,Object[] params,Class clazz,CallBack back) {

    Connection conn = DBManager.getConn();
    List list = null;    //存储查询结果的容器
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
      ps = (PreparedStatement) conn.prepareStatement(sql);
      //给sql设置参数
      JDBCUtils.handleParams(ps, params);
      System.out.println(ps);
      rs = ps.executeQuery();
      
      return back.doExecute(conn, ps, rs);
    
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    } finally {
      DBManager.close(ps, conn);
    }  
  }

为了实现回调,我们新建一个CallBack接口,然后增加一个doExcute方法,提供给后续的每个方法进行自主实现。

代码语言:javascript
复制
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public interface CallBack {
  public Object doExecute(Connection conn,PreparedStatement ps,ResultSet rs);
}

经过模板方法模式的改造之后,我们可以看到queryRows和queryValue方法的代码如下:

代码语言:javascript
复制
  /**
   * 查询返回多行记录,并将每行记录封装到clazz指定的类的对象中
   * @param sql 查询语句
   * @param clazz 封装数据的javabean类的class对象
   * @param params sql的参数
   * @return 查询到的结果
   */
  public List queryRows(final String sql,final Class clazz,final Object[] params) {
    return (List)excueteQueryTemplate(sql, params, clazz, new CallBack() {

      @Override
      public Object doExecute(Connection conn, java.sql.PreparedStatement ps, ResultSet rs) {
        List list = null;
        try {
          ResultSetMetaData metaData = rs.getMetaData();
          //多行
          while(rs.next()) {
            if(list==null) {
              list = new ArrayList();
            }
            
            Object rowObj = clazz.newInstance();  //调用Javabean的无参构造器

            //多列 select username,pwd,age from user where id>? and age>18
            for(int i=0;i<metaData.getColumnCount();i++) {
              String columnName = metaData.getColumnLabel(i+1);
              Object columnValue = rs.getObject(i+1);

              //调用rowObject对象的setUsername方法,将ColumnValue的值设置进去
              ReflectUtils.invokeSet(rowObj, columnName, columnValue);
            }
            list.add(rowObj);
          }
        }catch(Exception e) {
          e.printStackTrace();
        }
        return list;
      }
    
    });
  }

  /**
   * 查询返回一个值(一行一列),并将该值返回
   * @param sql 查询语句
   * @param params sql的参数
   * @return 查询到的结果
   */
  public Object queryValue(String sql,Object[] params) {

    return excueteQueryTemplate(sql, params, null, new CallBack() {

      @Override
      public Object doExecute(Connection conn, java.sql.PreparedStatement ps, ResultSet rs) {
        Object value = null;
        try {
          while(rs.next()) {
            value = rs.getObject(1);
          }
        } catch (SQLException e) {
          e.printStackTrace();
        }
        return value;
      }
    });
  }

tips:使用模板方法模式之后,可以避免我们在两个方法中写重复性代码。我们都是通过调用回调函数CallBack对两个方法进行具体实现。在回调函数中,我们使用匿名内部类,直接对CallBack接口中的doExcute方法进行实现。大大简化了代码,使得代码具有更强的阅读性。

3.增加连接池(Connection Pool)

在我们学习连接的时候就已经知道,获取connection对象的底层实现是利用Socket套接字对象,是十分耗时的一项操作。所以在实际的使用中,我们对于connection的使用应该尽可能的节省。对connection对象进行重复操作,可以大大提高整个系统的效率。所以我们建立连接池对象的基本思想如下:

(1)将Connection对象放入List中,反复重用。

(2)在连接池的初始化的时候,事先放入多个连接池对象。当我们从连接池中取连接对象时,如果池中有可用连接,则将池中最后一个返回,同时,将该连接从池中remove,表示正在使用。如果池中无可用连接,则创建一个新的。

(3)在关闭连接时,不是真正关闭连接,而是将用完的连接放入池中。

所以根据上面我们对连接池实现思路,创建一个连接池类,具体实现如下:

代码语言:javascript
复制
package com.peng.sorm.pool;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import com.peng.sorm.core.DBManager;

/**
 * 连接池的类
 */
public class DBConnPool {
  
  /**
   * 连接池对象
   */
  private static List<Connection> pool;
  /**
   * 最大连接数
   */
  private static final int POOL_MAX_SIZE=DBManager.getConf().getPoolMaxSize();
  /**
   * 最小连接数
   */
  private static final int POOL_MIN_SIZE=DBManager.getConf().getPoolMinSize();

  /**
   * 初始化连接池,使池中连接数达到最小值
   */
  public void initPool() {
    if(pool == null) {
      pool = new ArrayList<Connection>();
    }
    while(pool.size()< POOL_MIN_SIZE) {
      pool.add(DBManager.createConn());
      System.out.println("初始化池,池中连接数:"+pool.size());
    }
  }
  
  /**
   * 从池中取出一个连接
   * @return
   */
  public synchronized Connection getConnection() {
    int last_index = pool.size()-1;
    Connection conn = pool.get(last_index);
    pool.remove(last_index);
    return conn;
  }

  /**
   * 所谓的关闭连接并不是真的连接,只是将此连接放回到连接池中
   * @param conn
   */
  public synchronized void close(Connection conn) {
    if(pool.size()>=POOL_MAX_SIZE) {
      try {
        conn.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }else {
      pool.add(conn);
    }
  }
  
  public DBConnPool() {
    initPool();
  }
}

tips:由于每个客户的用途有所差异,所以对连接池的大小需求也有所不同。为了避免用户重新修改我们的代码。我们可以在配置文件中增设连接池的最大最小值选项,然后我们在代码中就可以直接通过配置文件来获取我们需要的值。从而避免了客户修改代码的风险。

测试连接池效率:

代码语言:javascript
复制
import java.util.List;

import com.peng.sorm.core.Query;
import com.peng.sorm.core.QueryFactory;
import com.peng.vo.EmpVO;

/**
 * 测试连接池的效率
 *
 */
public class Test2 {
  public static void test() {
    Query q = QueryFactory.createQuery();
    //复杂查询,将两个表进行关联查询
    String sql2 = "select e.id,e.empname,salary+bonus 'xinshui',age,d.dname 'deptName',d.address 'deptAddr' from emp e "
    +"join dept d on e.deptId=d.id ";
    List<EmpVO> list2 = q.queryRows(sql2,EmpVO.class, null);
    for(EmpVO e:list2) {
      System.out.println(e.getEmpname()+" "+e.getAge()+" "+e.getId()+" "+e.getXinshui()+" "+e.getDeptName()+" "+e.getDeptAddr());
      System.out.println("******************");
    }
  }
  
  public static void main(String[] args) {
    long a = System.currentTimeMillis();
    for(int i=0;i<3000;i++) {
      test();      
    }
    long b = System.currentTimeMillis();
    System.out.println(b-a);//不加连接池:14187毫秒. 增加连接池之后:1957
  }
}

在使用连接池和不使用连接池时,最后的耗时结果如下

不使用连接池:

使用连接池:

tips:经过两者的对比之后就可以发现,提高的效率不是一点点,而是接近10倍。未使用的时候,耗时14187ms,使用连接池的时候,耗时1957ms,由此可见使用连接池对象时的优越性。


以上就是关于JAVA的SORM基础啦!下面我们进入数据库的正式学习!


二、数据库

1.相关概念

DB:数据库(datebase)存储数据的“仓库”。它保存了一系列有组织的数据。

DBMS:数据库管理系统(Datebase Management System)。数据库是通过DBMS创建和操作的容器

SQL:结构化查询语言(Structure Query Language):专门用来与数据库通信的语言

SQL的优点

(1)不是某个特定数据库供应商专用的语言,几乎所有DBMS都支持SQL

(2)简单易学

(3)虽然简单,但实际上是一种强有力的语言,灵活使用其语言元素,可以进行非常复杂和高级的数据库操作。

2.数据库的特点

(1)将数据放到表中,表再放到库中

(2)一个数据库中可以有多个表,每个表都有一个名字,用来标识自己。表名具有唯一性

(3)表具有一些特性,这些特定定义了数据在表中如何存储,类似于java中“类”的设计

(4)表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似java中的”属性“。

(5)表中的数据是按行存储的,每一行类似于java中的“对象”。

3.MySQL服务的启动和停止

方式一:计算机-右击管理-服务

方式二:通过管理员身份运行cmd窗口

net statrt 服务名(启动服务)

net stop 服务名(停止服务)

4.MySQL服务的登录和退出

方式一:通过mysql自带的客户端 只限于root用户

方式二:通过Windows自带的客户端

登录:mysql -h主机名 -P端口号 -u用户名 -p密码

退出:exit 或 ctrl+c

5.MySQL的常见命令

(1)查看当前所有的数据库

show databases;

(2)打开指定的库

use 库名;

(3)查看当前库中所有的表

show tables;

(4)查看其他库中的表

show tables from 库名;

(5)创建表

create table 表名(

列名 列类型,

列名 列类型,

.........

);

(6)查看表结构

desc 表名;

(7)查看服务器的版本

方式一:登录到mysql服务器

select version();

方式二:没有登录到mysql服务端

mysql --version 或 mysql --V

6.MySQL的语法规范

(1)不区分大小写,但是建议关键字大写,表名、列名小写

(2)每条命令最好用分号结尾

(3)每条命令根据需要,可以进行缩进 或换行

(4)注释

单行注释:#注释文字

单行注释:-- 注释文字(注意在两个单横线之后有一个空格)

多行注释:/* 注释文字 */


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java小白成长之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、对SORM进行升级改造
  • 二、数据库
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档