java - 业务逻辑写在数据库还是自身应用程序?
高洛峰
高洛峰 2017-04-17 13:23:09
0
3
224

SQL应该负责怎么样的CURD,分组、排序、可能根据业务逻辑只是选择性查个别字段、使用SQL函数等等让不让数据库做?还是自己用编程语言(比如java、c++)写的应用程序里处理数据?

实例:统计2015-03-22 ~ 2015-03-24期间全国每个城市/省份每天的访问ip量。
假设查询涉及的表的数据量为S。考虑以下三种方式。
做法一:
在一个以天为步进单位长度来遍历2015-03-22 ~ 2015-03-24日期范围以及全国每个城市的循环里,执行countIp(visitDay, cityCode)统计某个城市或省份某天的ip量。核心SQL:

SELECT COUNT(DISTINCT user_ip) FROM pv_access  WHERE visit_date_time BETWEEN {某天最早时间点} AND {某天最晚时间点} AND city_code = {某个城市的编码}

SELECT COUNT(DISTINCT user_ip) FROM pv_access  WHERE visit_date_time BETWEEN {某天最早时间点} AND {某天最晚时间点} AND city_code LIKE {模糊匹配某个省的所有城市}

做法二:通过以下SQL获取数据,然后在应用程序中做分组统计。

SELECT visit_date_time, city_code, user_ip  FROM pv_access  WHERE visit_date_time BETWEEN '2015-03-22 00:00:00' AND '2015-03-24 23:59:59' AND city_code in ({所有城市的编码})

如果没有统计省份的需求,有第三种做法,直接执行SQL按【天+城市】分组统计:

SELECT DATE_FORMAT(visit_date_time,"%Y-%m-%d") as day, city_code, ipCount FROM pv_access  WHERE visit_date_time BETWEEN '2015-03-22 00:00:00' AND '2015-03-24 23:59:59' AND city_code in ({所有城市的编码}) GROUP BY DATE_FORMAT(visit_date_time,"%Y-%m-%d"), city_code;

我自己的分析:

  1. 涉及循环n次访问数据库,每次取一个分组的统计结果,时间复杂度为(nS)。优点应该是易于维护。
  2. 数据库负责简单的查出记录集,不负责统计,一次性取出统计所需的所有数据,然后让应用程序做分组统计等处理。但是这样不就增加了传输量吗?因为可能我们需要的最终结果只是一个统计值(比如这个例子),但为了将统计工作转移到应用程序,就必须传输更多的数据。传输量为(S)。
  3. 一条SQL语句获取最终结果则只需一次请求,时间复杂度为(S)。但压力大部分会转移到数据库?

    如果涉及分组统计,而分组不是互斥的(上面的例子【天+地区】分组不是互斥,既有城市又有省份),那么应该无法使用直接用SQL实现分组统计得到最终结果,是吧?这个时候只能通过自身应用程序实现分组统计?

我想我上面的问题的本质问题是:
两个可互相通讯并对外提供服务的程序各自应该负担什么工作,业务逻辑放在哪,放多少?
希望各位有经验有见解的童鞋给我指点迷津。

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

모든 응답(3)
洪涛

首先我们需要分清楚数据和状态。

状态是对数据的抽象
数据多半不能直接被用户看到(比如你不能直接返回一个timestamp给用户),而状态则更贴近业务;
数据需要是原子的(数据库第一、二范式),而状态一般涉及一条以上的数据;
数据稳定性高,状态变数多:需求变化了,不应该去操作全量数据,而是修改状态控制;
数据适合放在有持久化的地方,而状态根据数据动态算出,适合放在内存中(当然,系统大到出现集群的概念以后,状态也可能需要持久化)。

大部分时候,我们需要的都不是裸数据,而是根据数据获得的状态。由数据转化为状态的逻辑总得放在一个端,要么是数据库,要么是后端,在非常少见的情形里,是前端/客户端。

读操作的逻辑放在哪里不那么非黑即白,需要根据具体业务分析。

对数据本身的约束可以放在数据库中:

  • unique

  • unsigned

  • primary

对状态的约束一般在控制在数据的写操作

  • “每天只允许注册 100 个用户”这个需求就创建了“是否今天注册了超过100个用户”的状态

如果对状态的约束全需要放在业务逻辑里,业务逻辑写在哪里呢?
不得不说,业务逻辑使用存储过程/触发器实现有很多很多缺点:

  • 存储过程/触发器异常处理很麻烦,程序流程处理复杂了不说,也难以对异常情形生成友好的错误提示

  • 存储过程/触发器难以断点调试

  • 存储过程/触发器基于关系型数据库,做更加复杂(树状结构等)/ 更加简单(连循环计算都需要一个临时表)的逻辑都有很大损耗

  • 存储过程/触发器杂糅了逻辑在数据库中,业务变大以后难以合理分层

  • 存储过程/触发器使用描述性语言,相对难以优化

因此,几乎没有人把对状态的写操作的相关业务逻辑写在存储过程/触发器里。

최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!