PACKAGE静态缓存数据带来的逻辑隐患

本文介绍了一个关于Oracle数据库中包的全局变量与参数表数据不同步的问题。在同一个会话中,包的初始化仅执行一次,导致全局变量未能更新。为解决此问题,建议将初始化过程封装为独立的存储过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一个项目中,有一张参数表保存了一些全局变量,比如当前会计周期等。
通过一个包(PACKAGE)来实现业务逻辑,在PACKAGE的初始化程序里,读取相关的全局参数,用于后续处理程序。
但是在调试过程中,发现对参数进行修改后,包的全局变量跟实际库里的值不一致,导致业务逻辑错误。这里重现一下当时的场景:

--参数表结构
CREATE TABLE T_PARA
(PARA_CODE  VARCHAR2(20)
,PARA_NAME  VARCHAR2(60)
,PARA_VALUE VARCHAR2(60)
);
--其中一个参数:当前会计期,值是201801
INSERT INTO T_PARA VALUES('ACCYEARMON','当前会计期','201801');
commit;
/*
--包头
--定义了当前会计期的全局变量
*/
create or replace package PKG_SESSIONDAT is
  --全局变量,当前会计期
  G_ACCYEARMON   VARCHAR2(6);
  --返回G_ACCYEARMON值
  function GET_ACCYEARMON return VARCHAR2;
  --设置参数值
  PROCEDURE SET_ACCYEARMON(V_ACCYEARMON VARCHAR2);

end PKG_SESSIONDAT;

--包体
create or replace package body PKG_SESSIONDAT is
  --函数,返回当前会计期
  function GET_ACCYEARMON return VARCHAR2 IS
    v_ret t_para.para_value%type;
  BEGIN
    v_ret:=G_ACCYEARMON;
    return v_ret;
  END GET_ACCYEARMON;
  --存储过程,设置当前会计期
  PROCEDURE SET_ACCYEARMON(V_ACCYEARMON VARCHAR2) IS
  BEGIN
    UPDATE T_PARA SET PARA_VALUE=V_ACCYEARMON WHERE PARA_CODE='ACCYEARMON';
    COMMIT;
  END SET_ACCYEARMON;

begin
  --包初始化部分,调用包程序就会执行
  SELECT PARA_VALUE INTO G_ACCYEARMON
    FROM T_PARA
    WHERE PARA_CODE='ACCYEARMON';
end PKG_SESSIONDAT;

接下来做个测试,先取出初始会计期的值,然后重新设置该值,再取出来。

SQL> declare
  2    v_true varchar2(6);
  3  begin
  4    dbms_output.put_line('G_ACCYEARMON初始值='||PKG_SESSIONDAT.G_ACCYEARMON);
  5    dbms_output.put_line('GET_ACCYEARMON返回='||PKG_SESSIONDAT.GET_ACCYEARMON);
  6    PKG_SESSIONDAT.SET_ACCYEARMON('201802');
  7    dbms_output.put_line('重置后G_ACCYEARMON='||PKG_SESSIONDAT.G_ACCYEARMON);
  8    dbms_output.put_line('重置后GET_ACCYEARMON返回='||PKG_SESSIONDAT.GET_ACCYEARMON);
  9    select PARA_VALUE into v_true
 10      from T_PARA WHERE PARA_CODE='ACCYEARMON';
 11    dbms_output.put_line('数据库内真实值='||v_true);
 12  end p_test;
 13  /
G_ACCYEARMON初始值=201801
GET_ACCYEARMON返回=201801
重置后G_ACCYEARMON=201801
重置后GET_ACCYEARMON返回=201801
数据库内真实值=201802
PL/SQL procedure successfully completed

可以发现,用包里的存储过程对数据库值进行重置后,再调用包函数,全局变量的值没有变化,尽管数据库的值已经被重写了。
合理的解释是包的初始化程序没有再次执行。
查阅资料后验证了这一点:

在同一个会话中,包的初始化只执行一次。

刚才的示例中,换一个session,得到的值是正确的:

SQL> declare
  2    v_true varchar2(6);
  3  begin
  4    select PARA_VALUE into v_true
  5      from T_PARA WHERE PARA_CODE='ACCYEARMON';
  6    dbms_output.put_line('数据库内真实值='||v_true);
  7    dbms_output.put_line('另一个会话G_ACCYEARMON值='||PKG_SESSIONDAT.G_ACCYEARMON);
  8    dbms_output.put_line('另一个会话GET_ACCYEARMON返回='||PKG_SESSIONDAT.GET_ACCYEARMON);
  9  end;
 10  /
数据库内真实值=201802
另一个会话G_ACCYEARMON值=201802
另一个会话GET_ACCYEARMON返回=201802
PL/SQL procedure successfully completed

Oracle这样做的目的是提高效率、节省资源。但一不留心会给开发人员带来副作用,如何避免这类情况的产生,建议是:
将初始化程序单独封装成存储过程,在适当的时候进行调用。
比如上述案例:

  PROCEDURE Initialization IS
  BEGIN
    SELECT PARA_VALUE INTO G_ACCYEARMON
      FROM T_PARA
      WHERE PARA_CODE='ACCYEARMON';
  END Initialization;
<think>首先,用户的问题是关于Vue领域的,但提问的是“.json文件和.js文件的区别是什么”。这与Vue相关,因为在Vue项目中,经常使用JSON和JS文件。例如,在配置(如package.json)、状态管理(如Vuex)或数据存储中都会用到。作为Vue专家,我应该将这个主题联系到Vue上下文中回答。回答需要详尽:给出解决方法和问题产生原因,或给出代码。用户要求提供代码,但只能提供Vue代码。所以,如果适用,可以提供涉及Vue代码的例子来解释区别。回答流程:1.**回答问题**:直接解释.json和.js文件的区别。2.**给出解释**:详细说明原因、用途和示例。3.**结尾提供相关问题**:在最后严格遵循格式:§§相关问题§§:然后列出4个相关问题(用数字点列)。结构:-先回答区别。-解释在Vue项目中的应用。-可能给出一个Vue代码示例来演示它们的用法。具体区别:-**.json文件**:JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。它基于文本,易于人读和机器解析。在Vue中,常用于配置(如package.json、vue.config.json)、API响应、状态持久化等。JSON文件是纯数据,不含代码逻辑。-**.js文件**:JavaScript文件含可执行的JavaScript代码。在Vue中,用于组件、工具函数、模块等。.js文件可以含函数、类、变量和逻辑。在Vue项目中:-JSON文件:用于静态数据或配置。-JS文件:用于动态逻辑。给出代码示例:-如果可能,提供一个简单的Vue组件代码,其中使用了JSON数据。-由于用户要求“只能提供Vue代码”,我应该提供Vue组件中的代码片段。-示例:一个Vue组件从JSON文件中导入数据。问题产生原因:-解释为什么要区分它们:JSON是不可执行的数据格式,适合跨平台传输;JS是脚本语言,用于添加功能。最后,相关问题:-必须列出4个相关问题。-格式严格:先§§相关问题§§:然后1....2....3....4....-相关问题应该与主题相关:Vue、JSON、JS文件的使用。头脑风暴相关问题:1.在Vue中如何导入和使用JSON文件?2.Vue组件中如何处理动态数据从JS文件导入?3.为什么在Vue项目中使用JSON文件而不是直接在JS中定义对象?4.Vue.js如何处理模块化导入的不同文件类型?-或者更具体:如何在Vue单文件组件中导入外部JSON数据?确保回答完整:-回答:.json和.js文件的主要区别。-解释:详细阐述。-代码:提供Vue相关代码。-结束:相关问题。最终回答结构:1.**回答问题**:直接定义区别。2.**解释**:给出背景、原因、Vue上下文。3.**代码示例**:给出一个Vue代码片段,展示使用。4.**相关问题**:列表。</think> ### .json文件和.js文件的区别是什么? 在Vue项目中,`.json`文件和`.js`文件是两种常见的文件类型,它们的主要区别在于**文件格式、用途和执行方式**。以下是详细解释: 1. **文件格式和结构**: - **.json文件**:这是一种纯文本数据格式,基于JavaScript对象表示法(JSON)。它只含键值对或数组结构的数据,如 `{ "name": "Vue App", "version": "1.0.0" }`。JSON文件不支持代码逻辑(如函数、循环或条件语句),所有内容必须是静态数据。 - **.js文件**:这是一种JavaScript文件,可以含可执行代码、函数、类、变量和逻辑语句。它支持ECMAScript语法,并在运行时被解释或编译执行。例如,一个`.js`文件可以定义一个Vue组件:`export default { data() { return { count: 0 }; } }`。 2. **用途和适用场景**: - **.json文件**:主要用于存储配置、静态数据或API响应。在Vue项目中,常用于: - `package.json`:管理项目依赖和脚本。 - 数据文件:如存储多语言字符串(i18n)或常量配置。 - API交互:作为模拟数据的来源(例如,使用`fetch`从JSON文件加载数据)。 - 原因:JSON格式简单、跨平台,易于被其他语言或工具解析(如Node.js、Web浏览器)。它只处理数据,不涉及逻辑,因此适合用于非代码场景。 - **.js文件**:用于实现业务逻辑、组件定义和动态功能。在Vue中,常见的用法括: - Vue组件:在`.vue`单文件组件中引入或直接作为脚本模块。 - 工具函数:如验证器、API请求封装。 - 状态管理:在Vuex存储中定义actions或getters。 - 原因:JS文件支持运行时执行,允许动态行为(如响应式数据更新),这在构建交互式应用时至关重要。 3. **执行方式**: - **.json文件**:是不可执行的。在Vue中,你需要通过`import`语句(在模块化系统中)或`fetch`API加载它。导入后会解析为JavaScript对象,但不能调用方法或运行代码。 - **.js文件**:是可执行的。当导入时,浏览器或Node.js会解释其中的代码,运行函数或初始化变量。Vue框架依赖JS文件来创建组件实例和响应式系统。 在Vue项目中,为什么需要区分它们?主要原因是**性能、可维护性和安全性**: - JSON文件更适合静态数据,减少内存占用和加载时间(因为它不逻辑)。 - 直接在JS文件中定义大型数据对象可能导致代码臃肿和维护困难(例如,在热重载时JS文件会被重新执行,而JSON数据如果不变,可以缓存)。 - JSON文件作为纯数据源,减少了注入攻击风险(如XSS),而JS文件如果处理不当可能有安全隐患。 #### Vue代码示例 以下是一个简单的Vue组件示例,展示如何在Vue中导入和使用`.json`文件,并与`.js`文件对比。我将使用一个Vue单文件组件(.vue),其中: - 从JSON文件导入静态数据。 - 从JS文件导入工具函数。 **项目结构**: ``` /src /components DataDisplay.vue # Vue组件文件 /data config.json # JSON数据文件 /utils helper.js # JS工具文件 ``` **1. config.json文件内容(纯数据)**: ```json { "appName": "Vue Demo", "features": ["Reactivity", "Components", "Routing"] } ``` **2. helper.js文件内容(可执行代码)**: ```javascript // 定义一个工具函数(逻辑) export function formatFeatures(features) { return features.map(feature => feature.toUpperCase()).join(', '); } ``` **3. DataDisplay.vue组件代码(Vue单文件组件)**: ```vue <template> <div> <h1>{{ appName }}</h1> <p>Features: {{ formattedFeatures }}</p> <button @click="increment">Increment Count</button> <p>Count: {{ count }}</p> </div> </template> <script> // 导入JSON数据(解析为JS对象) import config from '../data/config.json'; // 导入JS函数(可执行代码) import { formatFeatures } from '../utils/helper.js'; export default { data() { return { appName: config.appName, // 使用JSON数据 count: 0, }; }, computed: { formattedFeatures() { // 调用JS函数处理数据 return formatFeatures(config.features); } }, methods: { increment() { this.count++; // 动态逻辑,只能存在于JS中 } } }; </script> ``` **解释代码**: - 在`DataDisplay.vue`中: - `import config from '../data/config.json'`:JSON文件被导入为JavaScript对象(在构建时如Webpack会处理)。这里`config.appName`是静态数据,不能修改或运行函数。 - `import { formatFeatures } from '../utils/helper.js'`:JS文件导出一个函数,在Vue组件的computed属性中被调用,添加动态格式化逻辑。 - 点击按钮的`increment`方法展示了JS文件的优势:它支持交互式逻辑。 - JSON文件适用于只读数据,如配置;JS文件适用于需要运行时行为的场景。 这个示例突出了区别:JSON是数据载体,JS是代码载体。Vue项目中,合理使用它们能提升效率和代码清晰度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值