oracle入门(8)——实战:支持可变参数、多种条件、多个参数排序、分页的存储过程查询组件

【本文介绍】

  学了好几天,由于项目需要,忙活了两天,写出了个小组件,不过现在还只能支持单表操作。也没考虑算法上的优化,查询速度要比hibernate只快了一点点,可能是不涉及多表查询的缘故吧,多表的情况下才更快。

  经非专业的测试,在有分页的情况下,在300万条数据里面查询的时间保持在0.1秒内。相同查询条件+分页的情况下,hibernate 用时0.3秒内。

  不分页的条件下,查出来的数据越多,时间越长,时间长的话,跟hibernate相相比就没什么优势了。

【思路】

  我的思路是从java传来”字段名,值,排序字段,升降序,分页“等 几个参数,都是字符串。然后在存储过程中 根据 标识符 切割字符串,最后拼接成一个SQL语句。

但也有不少值得改进的地方:

(1)PL/SQL语法的字符串最多只能传4000个字符,所以多于4000个字符的字符串可能会导致查询失败。

(2)日期的排序只能靠的是字符串的排序,所以数据库的日期 要 varchar类型。这样会引起不通用的问题。

(3)比较的符号要约定好,比如查询条件为包含什么什么,即contains,就要发送instr到数据库去拼接SQL语句,因为PL/SQL语言的instr 就相当于contians。这个问题有待改成常量的形式。具体约定如下:

大于:>

小于:<

大于等于:>=

小于等于:<=

不等于:!=

包含:instr

以什么开始:startWith

以什么结尾:endWith

是否为空:isNull

是否不为空:isNotNull

【第一步:在数据库中建立分割函数】

  oracle没有自带的”根据某标识“切割字符串的函数,所以我们要自己建立。

/**
用pipe函数实现字符串分割
**/
CREATE OR REPLACE TYPE ty_str_split IS TABLE OF VARCHAR2 (4000);
/
CREATE OR REPLACE FUNCTION fn_split (p_str IN VARCHAR2, p_delimiter IN VARCHAR2)
RETURN ty_str_split PIPELINED
IS
    j INT := 0;
    i INT := 1;
    len INT := 0;
    len1 INT := 0;
    str VARCHAR2 (4000);
BEGIN
    len := LENGTH (p_str);
    len1 := LENGTH (p_delimiter);

    WHILE j < len LOOP
       j := INSTR (p_str, p_delimiter, i);

       IF j = 0 THEN
           j := len;
          str := SUBSTR (p_str, i);
          PIPE ROW (str);
          IF i >= len THEN
              EXIT;
          END IF;
       ELSE
          str := SUBSTR (p_str, i, j - i);
          i := j + len1;
          PIPE ROW (str);
       END IF;
    END LOOP;

    RETURN;
END fn_split;
/

【第二步:建立存储过程】

CREATE OR REPLACE
procedure testc
(
p_cursor out testpackage.Test_CURSOR, --游标,返回列表
paraReturn out VARCHAR2,                          --返回的结果
paraTableName in VARCHAR2,                        --数据库名称
paraKey in VARCHAR2,                                  --key,字段名
paraCondition in VARCHAR2,                        --condition,条件
paraValue in VARCHAR2,                                --value,值
paraAndOr in VARCHAR2,                                --where连接附,and 还是or
paraOrderKey in VARCHAR2,                         --排序的key
paraOrderSort   in VARCHAR2,                       --排序的顺序
paraPagesize in NUMBER,                               --页数
paraPageNow in NUMBER                                --第几页
)
is
sqlStr VARCHAR2(1000) := ‘test‘; --拼接的sql语句
paraFiledCount NUMBER := 0;              --记录字段数
paraCount NUMBER := 1;                       --循环计数
paraOrderCount NUMBER := 0;              --排序字段计数
paraKeySplit ty_str_split;             --切割后的 key
paraConditionSplit ty_str_split;   --切割后的 condition
paraValueSplit ty_str_split;           --切割后的value
pareAndOrSplit ty_str_split;           --切割后的连接符
paraOrderKeySplit ty_str_split;        --切割后的排序KEY
paraOrderSortSplit ty_str_split;   --切割后的排序顺序
paraBegin NUMBER:= (paraPageNow-1)*paraPagesize;
paraEnd NUMBER:= paraPageNow*paraPagesize;

begin
    -- 查询的基本结构
    --sqlStr := ‘select * from (select tt.*,ROWNUM rowno from (select t.* from ‘ || paraTableName || ‘ t ‘;
    --sqlStr := ‘select * from (select t1.*, ROWNUM rn from (select * from ‘ || paraTableName ;
    sqlStr := ‘select * from ‘ || paraTableName ;

    -- 分割
    select fn_split (paraKey,‘^‘) into paraKeySplit from dual;
    select fn_split (paraCondition,‘^‘) into paraConditionSplit from dual;
    select fn_split (paraValue,‘^‘) into paraValueSplit from dual;
    select fn_split (paraAndOr,‘^‘) into pareAndOrSplit from dual;
    select fn_split (paraOrderKey,‘^‘) into paraOrderKeySplit from dual;
    select fn_split (paraOrderSort,‘^‘) into paraOrderSortSplit from dual;

    IF paraKey != ‘null‘ THEN
        sqlStr := sqlStr || ‘ where ‘;
        --key 长度
        for I in paraKeySplit.first()..paraKeySplit.last() loop
            paraFiledCount := paraFiledCount + 1;
        end loop;
        -- 循环
        LOOP
            -- 退出循环的条件
            EXIT WHEN paraCount > paraFiledCount;

            -- 循环拼接
            -- 拼接 = ,< ,> , >= , <= ,!=
            if
                paraConditionSplit(paraCount) = ‘=‘ OR
                paraConditionSplit(paraCount) = ‘<‘ OR
                paraConditionSplit(paraCount) = ‘>‘    OR
                paraConditionSplit(paraCount) = ‘>=‘ OR
                paraConditionSplit(paraCount) = ‘<=‘ OR
                paraConditionSplit(paraCount) = ‘!=‘
            THEN
                sqlStr := sqlStr ||  paraTableName || ‘."‘ || paraKeySplit(paraCount) || ‘"‘ || paraConditionSplit(paraCount) || CHR(39) || paraValueSplit(paraCount) || CHR(39);
            end if;
            -- 拼接contians
            if
                paraConditionSplit(paraCount) = ‘instr‘ THEN
                sqlStr := sqlStr || ‘instr(‘ ||  paraTableName || ‘."‘ || paraKeySplit(paraCount) || ‘",‘ || CHR(39) || paraValueSplit(paraCount) || CHR(39) || ‘)>0‘;
            end if;
            -- 拼接 startWith
            if
                paraConditionSplit(paraCount) = ‘startWith‘ THEN
                sqlStr := sqlStr || ‘REGEXP_LIKE(‘ ||  paraTableName || ‘."‘ || paraKeySplit(paraCount) || ‘",‘ || CHR(39) || ‘^‘ || paraValueSplit(paraCount) || CHR(39) || ‘)‘;
            end if;
            -- 拼接 endWith
            if
                paraConditionSplit(paraCount) = ‘endWith‘ THEN
                sqlStr := sqlStr || ‘REGEXP_LIKE(‘ ||  paraTableName || ‘."‘ || paraKeySplit(paraCount) || ‘",‘ || CHR(39)  || paraValueSplit(paraCount) || ‘$‘ || CHR(39) || ‘)‘;
            end if;
            -- 拼接 is null
            if
                paraConditionSplit(paraCount) = ‘isNull‘ THEN
                sqlStr := sqlStr ||  paraTableName || ‘."‘ || paraKeySplit(paraCount) || ‘"‘ || ‘ is null‘;
            end if;
            -- 拼接is not NULL
            if
                paraConditionSplit(paraCount) = ‘isNotNull‘ THEN
                sqlStr := sqlStr ||  paraTableName || ‘."‘ || paraKeySplit(paraCount) || ‘"‘ || ‘ is not null‘;
            end if;
            -- 拼接and 或者 or
            IF paraCount != paraFiledCount THEN
                sqlStr := sqlStr || ‘ ‘ || pareAndOrSplit(paraCount+1) || ‘ ‘;
            end IF;
            -- 计数增长
            paraCount := paraCount + 1;

        end LOOP;
    end if;

    --排序
    IF paraOrderKey != ‘null‘ THEN
            -- 排序字段 长度
        for I in paraOrderKeySplit.first()..paraOrderKeySplit.last() loop
            paraOrderCount := paraOrderCount + 1;
        end loop;
        paraCount := 1;
        sqlStr := sqlStr || ‘ order by ‘;
        --循环
        LOOP
        -- 退出循环的条件
            EXIT WHEN paraCount > paraOrderCount;
            sqlStr := sqlStr || ‘ ‘ || paraOrderKeySplit(paraCount) || ‘ ‘ || paraOrderSortSplit(paraCount);
            IF paraCount != paraOrderCount THEN
                sqlStr := sqlStr || ‘ , ‘;
            END IF;
            paraCount := paraCount + 1;
        END LOOP;
    END IF;

    -- 分页
    --sqlStr := sqlStr || ‘)t1 where ROWNUM <=‘ || paraEnd || ‘)  table_alias where table_alias.rowno >=‘ || paraBegin;
    --sqlStr := sqlStr || ‘)t1 where ROWNUM <=‘ || paraEnd || ‘)  where rn >=‘ || paraBegin;
    sqlStr := ‘SELECT * FROM (SELECT a.*, ROWNUM rn FROM (‘||sqlStr||‘) a WHERE ROWNUM <= ‘ || paraEnd || ‘)  WHERE rn >= ‘ || paraBegin;

    -- 记录下sql语句,返回去,以便调试
    paraReturn := sqlStr;

    -- 查询
    open p_cursor for sqlStr;

    -- 异常
    EXCEPTION
    WHEN no_data_found THEN
        DBMS_OUTPUT.PUT_LINE(‘找不到数据‘);
        paraReturn := ‘找不到数据‘;
end  testc;

【java通用类的封装】

package com.topview.util;

import java.lang.reflect.Method;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

public class FindByProcedure {

    private static Connection conn = null;
    private static Statement stmt = null;
    private static ResultSet rs = null;
    private static CallableStatement proc = null;

    private static int pre;//    查询起始时间
    private static int post;//     查询结束时间

    private static String sql;    // 查询的sql语句

    public static String getSql() {
        return sql;
    }

    public static void setSql(String sql) {
        FindByProcedure.sql = sql;
    }

    public static Connection getConn() {
        return conn;
    }

    /**
     * 连接由调用者提供。
     * @param conn
     */
    public static void setConn(Connection conn) {
        FindByProcedure.conn = conn;
    }

    public void before() {
        try {
            stmt = conn.createStatement();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                throw new MyException("没有传conn进来。");
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }

    public void after() {
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (stmt != null) {
                stmt.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if(proc != null) {
                proc.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *
     * @param tableName         要查询的表名,假如数据库有一张myUser表,则 tableName = user
     * @param keyList            要查询的字段集合,如["name","address"]
     * @param conditionList        要查询的逻辑集合,如[">",">="]
     * @param valueList            要查询的值集合,如["小铭","广工"]
     * @param andOrList            两个查询中间的连接符,如["and","or"]
     * @param orderList            排序的字段集合,如["age","name"]
     * @param orderSortList        排序的顺序集合,如["asc","desc"]
     * @param pageSize            每页显示的数量,如 10
     * @param pageNumber        第几页, 如1
     * *@param clazz            实体类的Class
     * @return                    该实体类的list
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> findByPropertList(String tableName,List<String> keyList,List<String> conditionList,List<String> valueList,List<String> andOrList,List<String> orderList,List<String> orderSortList,Integer pageSize,Integer pageNumber,Class<T> clazz) {

        // 表名为空时抛异常。
        if(tableName == null || "".equals(tableName)) {
            try {
                throw new MyException("传进来的tableName为空!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 类型为空时抛异常
        if(tableName == null || "".equals(tableName)) {
            try {
                throw new MyException("传进来的tableName为空!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        before();

        pre = (int) System.currentTimeMillis();

        StringBuilder keyListBuilder = new StringBuilder();
        StringBuilder conditionListBuilder = new StringBuilder();
        StringBuilder valueListBuilder = new StringBuilder();
        StringBuilder andOrListBuilder = new StringBuilder();
        StringBuilder orderListBuilder = new StringBuilder();
        StringBuilder orderSortListBuilder = new StringBuilder();

        String keyListStr = "";
        String conditionListStr = "";
        String valueListStr = "";
        String andOrListStr = "";
        String orderSortListStr = "";
        String orderSortSortListStr = "";

        List<T> ObjectList = new ArrayList<T>();

        // 如果不排序
        if(orderList == null || "".equals(orderList) || orderList.isEmpty()) {

            if(orderList == null) {
                orderList = new ArrayList<String>();
            }
            if(orderSortList == null){
                orderSortList = new ArrayList<String>();
            }
            orderList.add("null");
            orderSortList.add("null");
        }
        else {
            for(int i = 0 ; i < orderList.size(); i++) {
                orderListBuilder.append(orderList.get(i)).append("^");
                orderSortListBuilder.append(orderSortList.get(i)).append("^");
            }
            orderSortListStr = orderListBuilder.substring(0, orderListBuilder.length()-1);
            orderSortSortListStr = orderSortListBuilder.substring(0, orderSortListBuilder.length()-1);
        }
        // 如果不分页
        if(pageSize == null){
            pageSize = new Integer(10);
        }
        // 如果没key
        if(keyList == null || "".equals(keyList) || keyList.isEmpty()) {
            keyList.add("null");
            conditionList.add("null");
            valueList.add("null");
            andOrList.add("null");
        }

        else {
            for(int i = 0 ; i < keyList.size() ; i ++) {
                keyListBuilder.append(keyList.get(i)).append("^");
                conditionListBuilder.append(conditionList.get(i)).append("^");
                valueListBuilder.append(valueList.get(i)).append("^");
                andOrListBuilder.append(andOrList.get(i)).append("^");

            }
            keyListStr = keyListBuilder.substring(0, keyListBuilder.length()-1);
            conditionListStr = conditionListBuilder.substring(0, conditionListBuilder.length()-1);
            valueListStr = valueListBuilder.substring(0, valueListBuilder.length()-1);
            andOrListStr = andOrListBuilder.substring(0, andOrListBuilder.length()-1);
        }

        // 和数据库连接
        try {
            proc = conn.prepareCall("{ call testc(?,?,?,?,?,?,?,?,?,?,?) }");

            proc.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
            proc.registerOutParameter(2, Types.VARCHAR);
            proc.setString(3,tableName);
            proc.setString(4, keyListStr);
            proc.setString(5,conditionListStr);
            proc.setString(6,valueListStr);
            proc.setString(7,andOrListStr);
            proc.setString(8,orderSortListStr);
            proc.setString(9,orderSortSortListStr);
            proc.setInt(10, pageSize);
            proc.setInt(11, pageNumber);

            proc.execute();
            String para1 = (String) proc.getString(2);
            sql = para1;
            ResultSet rs = (ResultSet) proc.getObject(1);

            // 反射
            Method[] methods = clazz.getMethods();
            List<String> fieldNameList = new ArrayList<String>();
            List<Method> setMethodList = new ArrayList<Method>();

            for(Method m : methods) {
                if(m.getName().toString().contains("set")) {
                    fieldNameList.add((m.getName().toString().substring(3,m.getName().toString().length())).toLowerCase());
                    setMethodList.add(m);
                }
            }

            // 取返回值
            while (rs.next()) {
                try {
                    Object o = clazz.newInstance();
                    for(int i = 0 ; i < setMethodList.size() ; i ++) {
                        // 通过反射创建对象
                        setMethodList.get(i).invoke(o, rs.getObject(fieldNameList.get(i)));
                    }
                    ObjectList.add((T) o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            proc.close();

        } catch (SQLException e) {
            e.printStackTrace();
            try {
                throw new MyException("连接存储过程错误。");
            } catch (MyException e1) {
                e1.printStackTrace();
            }
        }finally {
            after();
        }

        post = (int) System.currentTimeMillis();

        return ObjectList;
    }    

    /**
     * 得到查询用时
     * @return    查询所用时间
     */
    public Float getUseTime(){
        return (((float)(post - pre))/1000) ;
    }

    /**
     * 异常类
     * @author xbw
     *
     */
    public class MyException extends Exception {

        private static final long serialVersionUID = 1L;

         //定义无参构造方法
         public MyException(){
             super();
         }

         //定义有参数的构造方法
         public MyException(String msg){
             super("MyExcepyion_By_Zjm:"+msg);
         }
    }
}

【一个调用的test】

    public static void main(String[] args) {
        FindByProcedure f = new FindByProcedure();

        String tableName = "";
        List<String> keyList = new ArrayList<String>();
        List<String> conditionList =new ArrayList<String>();;
        List<String> valueList =new ArrayList<String>();
        List<String> andOrList =new ArrayList<String>();
        List<String> orderList =new ArrayList<String>();
        List<String> orderSortList =new ArrayList<String>();
        tableName = "T_AP_ZA_LYT_GNLK";

        // key
        keyList.add("ZA_LYT_LKBH");
        keyList.add("ZA_LYT_TH");
        keyList.add("ZA_LYT_XM");
        keyList.add("ZA_LYT_MZ");
        keyList.add("ZA_LYT_CSRQ");
        keyList.add("ZA_LYT_RKSJ");
        keyList.add("ZA_LYT_RKSJ");

        // 比较符号
        conditionList.add("<");
        conditionList.add(">=");
        conditionList.add("instr");
        conditionList.add("<=");
        conditionList.add("startWith");
        conditionList.add(">=");
        conditionList.add("<=");

        // value
        valueList.add("4500000000000000500049");
        valueList.add("4600000000000000203771");
        valueList.add("VA");
        valueList.add("10");
        valueList.add("F");
        valueList.add("2014-12-24-08-29-38");
        valueList.add("2014-12-24-21-37-22");

        // 连接符
        andOrList.add("and");
        andOrList.add("and");
        andOrList.add("and");
        andOrList.add("and");
        andOrList.add("and");
        andOrList.add("and");
        andOrList.add("and");

        // 排序字段
        orderList.add("ZA_LYT_XM");
        orderList.add("ZA_LYT_XMPY");

        // 排序顺序
        orderSortList.add("ASC");
        orderSortList.add("DESC");

        List<T_AP_ZA_LYT_GNLK> list = new ArrayList<T_AP_ZA_LYT_GNLK>();

        // 连接conn要从外部传进去
        f.setConn(DBManager.getConnection());

        // 开始调用
        list = f.findByPropertList(tableName, keyList, conditionList, valueList, andOrList,orderList,orderSortList,5,1,T_AP_ZA_LYT_GNLK.class);

        for(T_AP_ZA_LYT_GNLK o : list) {
            System.out.println(o.getZa_lyt_xm());
        }

        System.out.println("总共拿出数据量:"+list.size());
        System.out.println("sql语句:"+f.getSql());
        System.out.println("查询用时:"+f.getUseTime().toString()+"s");
    }

oracle入门(8)——实战:支持可变参数、多种条件、多个参数排序、分页的存储过程查询组件

时间: 2024-10-24 17:49:00

oracle入门(8)——实战:支持可变参数、多种条件、多个参数排序、分页的存储过程查询组件的相关文章

SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程(支持单表或多表结查集分页)

原文:SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程(支持单表或多表结查集分页) SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程,支持单表或多表结查集分页,存储过程如下: /******************/ --Author:梦在旅途(www.Zuowenjun.cn) --CreateDate:2015-06-02 --Function:分页获取数据 /******************/ crea

《Docker技术入门与实战》pdf

下载地址:网盘下载 内容简介  · · · · · · [编辑推荐] <Docker技术入门与实战>是中国首部docker著作,一线Docker先驱实战经验结晶,来自IBM和新浪等多位技术专家联袂推荐! <Docker技术入门与实战>结合企业生产环境,深入浅出地剖析 Docker 的核心概念.应用技巧.实现原理以及生态环境,为解决各类问题提供了有价值的参考. [内容简介] 在云计算时代,开发者将应用转移到云上已经解决了硬件管理的问题,然而软件配置和管理相关的问题依然存在.Docke

.NET分布式缓存Redis从入门到实战

一.课程介绍 今天阿笨给大家带来一堂NOSQL的课程,本期的主角是Redis.希望大家学完本次分享课程后对redis有一个基本的了解和认识,并且熟悉和掌握 Redis在.NET中的使用.本次分享课程包含以下知识点: 1.StackExchange.Redis (简称:SE)驱动在C#中Redis几种数据结构学习和使用. 2.ServiceStack.Redis ( 简称: SS) 驱动在C#中Redis几种数据结构学习和使用. 3.Redis主从集群服务器搭建和学习. 4.在ASP.NET中Re

《Docker技术入门与实战第3版2018版》高清中文PDF下载

<Docker技术入门与实战第3版2018版>高清中文PDF下载资料简介:本书从Docker基本原理开始,深入浅出地讲解Docker的构建与操作,内容系统全面,可帮助开发人员.运维人员快速部署Docker应用.本书分为四大部分:基础入门.实战案例.进阶技能.开源项目,*部分(第1-8章)介绍Docker与虚拟化技术的基本概念,包括安装.镜像.容器.仓库.数据卷.端口映射等:第二部分(第9-16章)通过案例介绍Docker的应用方法,包括与各种操作系统平台.SSH服务的镜像.Web服务器与应用.

oracle入门学习笔记

Oracle学习笔记 推荐书籍:<Oracle有用教程(从入门到精通)>.<深入浅出Oracle> 1. 当前主流数据库: |-微软:SQL Server.access |-瑞典:Mysql |-IBM: DB2 |-Sybase: Sybase |-Oracle:Oracle A. 小型数据库:access.foxbase. 负载量小,100人内,成本千元内,安全性要求不高. 比如留言板等. B. 中型数据库:Mysql.SQL Server.Informix.日訪问量5000-

oracle入门(3)——oracle服务解释

[本文介绍] oracle不像mysql,安装后之后一个服务,如果mysql连接不上,打开其服务就行.oracle是有多个服务,哪些服务要开,哪些服务没必要开,对新手来说未必不是一个难点.下面对oracle的服务做一下总结. 以下内容来源于百度,发表该随笔只为备忘,感谢最先发表者(追溯不到). [oracle服务介绍] (1)OracleServiceSID 数据库服务,这个服务会自动地启动和停止数搜索据库.如果安装了一个数据库,它的缺省启动类型为自动.服务进程为ORACLE.EXE,参数文件i

xgboost入门与实战(原理篇)

http://blog.csdn.net/sb19931201/article/details/52557382 xgboost入门与实战(原理篇) 前言: xgboost是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包,比常见的工具包快10倍以上.在数据科学方面,有大量kaggle选手选用它进行数据挖掘比赛,其中包括两个以上kaggle比赛的夺冠方案.在工业界规模方面,xgboost的分布式版本有广泛的可移植性,支持在YARN, MPI, Sun

10-Python3从入门到实战—基础之函数

Python从入门到实战系列--目录 函数的定义 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数的语法 def 函数名(参数列表): 函数体 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 (); 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数. 函数的第一行语句可以选择性地使用文档字符串-用于存放函数说明. 函数内容以冒号起始,并且缩进. return [表达式] 结束函数,选择性地返回一个值给调用方.不带表达式的return相当于返

Swoole入门到实战打造高性能赛事直播平台

韩天峰力荐 Swoole入门到实战打造高性能赛事直播平台 第1章 课程介绍 欢迎大家来到swoole的课程!本章主要是介绍了swoole的一些特性,以及使用场景,并且分享了swoole在其他公司的一些案例,最后重点讲解了swoole学习的一些准备工作. 第2章 PHP 7 源码安装 很多工作好几年的PHPer对源码编译安装并不是很了解,其实这种情况是非常可怕的.本章我会教大家如何通过源码安装PHP7,并且简化PHP执行命令.最后重点讲解了源码安装踩到的坑,让您在源码编译安装过程中少走很多弯路.