ThinkPHP踩坑记录之数据库篇

虽然这么多年来ThinkPHP框架已经更新到大版本8了,越来越接近Laravel框架了,但是ThinkPHP 8框架还是有很多坑,我在工作中遇到不少,在此记录一下,以警醒后来人。

第1个坑,使用Db门面的inserA()批量插入数据到Oracle报错

因为ThinkPHP生成的批量插入SQL语句不符合Oracle语法。

避开这个坑的一个方法是,使用循环语句一条条地插入数据到Oracle,不要使用inserA()批量插入数据。

第2个坑,使用Think ORM操作Oracle 11g报错:SQLSTATE[HY000]: General error: 972 OCIStmtExecute: ORA-00972: identifier is too long

Oracle 11g的标识符的名字的长度不能超过30字节,标识符包括表名、视图名、序列名或触发器名。Oracle后续版本把标识符的名字的长度上限提高到了128字节。

ThinkPHP ORM 在处理 Oracle 时,有一个内部规范化逻辑(在 think-orm/src/db/connector/Oracle.phpBuilder 类中),会把表名/字段名转为小写+ 下划线风格(snake_case),以兼容 Oracle 的大小写不敏感特性。但当表名本身就包含大写或下划线时,这种转换会产生超长的蛇形名称,例如,把VIEW_JW_SPECIALTYDIRECTION转换为v_i_e_w__j_w__s_p_e_c_i_a_l_t_y_d_i_r_e_c_t_i_o_n,从而触发 Oracle 的长度限制。

A Quick Way to Test Laravel Database Connections

You can use Tinker to verify if your database connection is working:

php artisan tinker

Then inside Tinker, run:

DB::connection()->getPdo();

If the connection succeeds, you’ll get back PDO instance details. If it fails, you’ll see the actual error message (usually something helpful like credentials issues or host unreachable).

A Discussion on Logical Deletion (Soft Deletion): Whether It’s Necessary and How to Implement It

In the real world, some documents become obsolete and are immediately shredded, while others need to be preserved in archives for future reference.

Consider an order, which references many other pieces of information, such as seller details, buyer details, and product details. When a product is removed from the catalog, we can’t directly delete the product information; doing so would render the associated order information incomplete.

For tables that require logical deletion (referred to as “collections” in MongoDB), there are two methods:

  1. Method 1: Add fields like is_deleted or is_active to indicate whether a row has been logically deleted.
  2. Method 2: Create a corresponding archive table (recycle bin table) for each table that needs logical deletion. First, insert the rows to be deleted into the archive table (including additional fields like deletion time, ID of the person who deleted it, etc.), and then delete the rows from the source table.

Many experts have already pointed out the drawbacks of Method 1.

Method 2 is easier to implement, non-intrusive to the source table, but it comes at the cost of increased disk space usage.

When designing the database, we should analyze the specific application scenario:

1. Based on the Business Requirements

If the business requirement is to back up data, the solution should be database backups, not logical deletions.

If the business requirement is to archive data, the solution should be archiving data, i.e., moving data into an archive table.

If the goal is simply to “freeze” data, an inactive flag should be used. This provides perfect semantic meaning and ensures consistency. It’s important to note that “freezing” is not the same as “deleting.” “Freezing” means that if you need to use the data again, you can simply “unfreeze” it. “Deleting” means the data is gone, and if you need it again, you must recreate it.

2. Based on the Database System

Some database systems already implement archival features for you. For example, SQL Server has a history table feature that automatically logs deleted records into a history table, and updates are stored with their previous values. In such cases, there’s no need to create an archive table or implement archival logic at the code level.

3. Based on the Data Type in the Table

For tables such as menu tables (dictionary tables) or log tables, logical deletion is unnecessary and physical deletion is sufficient.

Only tables that store critical data, such as account tables or balance tables, should implement logical deletion. In such cases, using an archive table may be the better approach.

For further reading:

(Note: Currently, Zhihu requires login to view the original content. Without logging in, it will show random text as part of their anti-scraping measures against AI models.)